Last active
October 4, 2022 16:15
-
-
Save NetanelBasal/8c033644ea0c6c8105a27072ae1af461 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component({ | |
selector: 'add-story-form', | |
template: ` | |
<div class="container"> | |
<h1>New Story</h1> | |
<form [formGroup]="newStory" | |
(submit)="submit($event)" | |
(success)="onSuccess()" | |
(error)="onError($event)" | |
connectForm="newStory"> | |
<div class="form-group"> | |
<input type="text" formControlName="title" class="form-control" placeholder="Title"> | |
</div> | |
<div class="form-group"> | |
<textarea formControlName="description" | |
placeholder="Story.." | |
cols="10" rows="3" class="form-control"></textarea> | |
</div> | |
<div class="form-group"> | |
<input type="checkbox" formControlName="draft"> Draft | |
</div> | |
<select formControlName="category"> | |
<option *ngFor="let option of options" [ngValue]="option.id">{{option.label}}</option> | |
</select> | |
<button [disabled]="newStory.invalid" class="btn btn-primary" type="submit">Submit</button> | |
</form> | |
<div class="alert alert-success" *ngIf="success">Success!</div> | |
<div class="alert alert-danger" *ngIf="error">{{error}}</div> | |
</div> | |
` | |
}) | |
export class NewStoryComponent { | |
options = [{ id: 1, label: 'Category One' }, { id: 2, label: 'Category Two' }] | |
onError( error ) { | |
this.error = error; | |
} | |
onSuccess() { | |
this.success = true; | |
} | |
ngOnInit() { | |
this.newStory = new FormGroup({ | |
title: new FormControl(null, Validators.required), | |
description: new FormControl(null, Validators.required), | |
draft: new FormControl(false), | |
category: new FormControl(this.options[1].id, Validators.required) | |
}); | |
} | |
submit() { | |
this.success = false; | |
this.store.dispatch({ | |
type: 'ADD_STORY' | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Directive, EventEmitter, Input, Output } from '@angular/core'; | |
import { FormGroupDirective } from '@angular/forms'; | |
import { Store } from '@ngrx/store'; | |
import { Subscription } from 'rxjs/Subscription'; | |
import { Actions } from '@ngrx/effects'; | |
const FORM_SUBMIT_SUCCESS = 'FORM_SUBMIT_SUCCESS'; | |
const FORM_SUBMIT_ERROR = 'FORM_SUBMIT_ERROR'; | |
const UPDATE_FORM = 'UPDATE_FORM'; | |
export const formSuccessAction = path => ({ | |
type: FORM_SUBMIT_SUCCESS, | |
payload: { | |
path | |
} | |
}); | |
export const formErrorAction = ( path, error ) => ({ | |
type: FORM_SUBMIT_ERROR, | |
payload: { | |
path, | |
error | |
} | |
}); | |
@Directive({ | |
selector: '[connectForm]' | |
}) | |
export class ConnectFormDirective { | |
@Input('connectForm') path : string; | |
@Input() debounce : number = 300; | |
@Output() error = new EventEmitter(); | |
@Output() success = new EventEmitter(); | |
formChange : Subscription; | |
formSuccess : Subscription; | |
formError : Subscription; | |
constructor( private formGroupDirective : FormGroupDirective, | |
private actions$ : Actions, | |
private store : Store<any> ) { | |
} | |
ngOnInit() { | |
this.store.select(state => state.forms[this.path]).take(1).subscribe(val => { | |
this.formGroupDirective.form.patchValue(val); | |
}); | |
this.formChange = this.formGroupDirective.form.valueChanges | |
.debounceTime(this.debounce).subscribe(value => { | |
this.store.dispatch({ | |
type: UPDATE_FORM, | |
payload: { | |
value, | |
path: this.path, | |
} | |
}); | |
}); | |
this.formSuccess = this.actions$ | |
.ofType(FORM_SUBMIT_SUCCESS) | |
.filter(( { payload } ) => payload.path === this.path) | |
.subscribe(() => { | |
this.formGroupDirective.form.reset(); | |
this.success.emit(); | |
}); | |
this.formError = this.actions$ | |
.ofType(FORM_SUBMIT_ERROR) | |
.filter(( { payload } ) => payload.path === this.path) | |
.subscribe(( { payload } ) => this.error.emit(payload.error)) | |
} | |
ngOnDestroy() { | |
this.formChange.unsubscribe(); | |
this.formError.unsubscribe(); | |
this.formSuccess.unsubscribe(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { from } from 'rxjs/observable/from'; | |
import { formErrorAction, formSuccessAction } from '../connect-form.directive'; | |
@Injectable() | |
export class StoryEffects { | |
constructor( private storyService : StoryService, | |
private store : Store<any>, | |
private actions$ : Actions ) { | |
} | |
@Effect() addStory$ = this.actions$ | |
.ofType('ADD_STORY') | |
.switchMap(action => | |
this.storyService.add(action.payload) | |
.switchMap(story => (from([{ | |
type: 'ADD_STORY_SUCCESS' | |
}, formSuccessAction('newStory')]))) | |
.catch(err => (of(formErrorAction('newStory', err)))) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is not truely sync. store changes wont be reflected in form.