@daffodil/contact/state provides a fully featured state library to streamline the management of contact form submissions and driver interaction.
This package provides a DaffContactFacade that abstracts the complexities of the library into one place. This facade handles sending your contact form to your application's backend and can also be utilized to build your UI with behaviors common to a contact form.
DaffContactStateModule in the root component.StoreModule.forRoot({}). This will be relevant when using the redux and state management features of @daffodil/contact.import { DaffContactStateModule } from '@daffodil/contact/state';
@NgModule({
imports:[
StoreModule.forRoot({}),
DaffContactStateModule
]
})
export class AppModule {}
To inject the facade inside a component, include an instance of DaffContactFacade in the component's constructor.
import { DaffContactFacade } from '@daffodil/contact/state';
@Component({})
export class ContactComponent {
constructor(public contactFacade: DaffContactFacade) {}
}
Once the DaffContactFacade has been set up in the component, it can be used to manage contact form submissions.
The DaffContactFacade provides the following observable streams to enhance your application's UI:
| Observable | Type | Description |
|---|---|---|
success$ |
Observable<boolean> |
Whether the contact form submission succeeded |
error$ |
Observable<DaffStateError[]> |
An array of submission errors |
loading$ |
Observable<boolean> |
Whether a submission is currently in progress |
Sample usage:
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { DaffContactFacade } from '@daffodil/contact/state';
import { DaffStateError } from '@daffodil/core/state';
export class ContactComponent implements OnInit {
success$: Observable<boolean>;
error$: Observable<DaffStateError[]>;
loading$: Observable<boolean>;
constructor(public contactFacade: DaffContactFacade) {}
ngOnInit() {
this.success$ = this.contactFacade.success$;
this.error$ = this.contactFacade.error$;
this.loading$ = this.contactFacade.loading$;
}
}
Actions are dispatched to the store to trigger state changes. Once the DaffContactFacade has been set up in your component, use the dispatch() method to dispatch actions.
Submits a contact form to the backend. The DaffContactFacade is built generically, so you can create your own submission object that represents your app's contact form.
import { DaffContactSubmit } from '@daffodil/contact/state';
interface ContactFormData {
email: string;
name?: string;
message?: string;
}
const payload: ContactFormData = {
email: 'customer@example.com',
name: 'John Doe',
message: 'I have a question about your products.'
};
this.contactFacade.dispatch(new DaffContactSubmit(payload));
Dispatched automatically when a submission succeeds. Generally, you don't need to dispatch this manually.
import { DaffContactSubmitSuccess } from '@daffodil/contact/state';
this.contactFacade.dispatch(new DaffContactSubmitSuccess());
Dispatched automatically when a submission fails. Generally, you don't need to dispatch this manually.
import { DaffContactSubmitFailure } from '@daffodil/contact/state';
const errors = [{ code: 'NETWORK_ERROR', message: 'Failed to connect' }];
this.contactFacade.dispatch(new DaffContactSubmitFailure(errors));
Retries a failed submission with the same payload.
import { DaffContactRetry } from '@daffodil/contact/state';
const payload = {
email: 'customer@example.com'
};
this.contactFacade.dispatch(new DaffContactRetry(payload));
Cancels an ongoing submission.
import { DaffContactCancel } from '@daffodil/contact/state';
this.contactFacade.dispatch(new DaffContactCancel());
Resets the contact state to its initial state (clears success, errors, and loading states).
import { DaffContactReset } from '@daffodil/contact/state';
this.contactFacade.dispatch(new DaffContactReset());
Selectors can be used to directly access specific slices of state. The facade's observable streams use these selectors under the hood.
Selects whether the last submission succeeded.
import { selectDaffContactSuccess } from '@daffodil/contact/state';
store.select(selectDaffContactSuccess);
Selects the array of submission errors.
import { selectDaffContactError } from '@daffodil/contact/state';
store.select(selectDaffContactError);
Selects whether a submission is currently in progress.
import { selectDaffContactLoading } from '@daffodil/contact/state';
store.select(selectDaffContactLoading);
The following example illustrates a complete contact form component using the facade, including:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { DaffContactFacade, DaffContactSubmit, DaffContactReset } from '@daffodil/contact/state';
import { DaffStateError } from '@daffodil/core/state';
@Component({
selector: 'app-contact-form',
templateUrl: './contact-form.component.html'
})
export class ContactFormComponent implements OnInit {
contactForm: FormGroup;
loading$: Observable<boolean>;
success$: Observable<boolean>;
error$: Observable<DaffStateError[]>;
constructor(
private fb: FormBuilder,
private contactFacade: DaffContactFacade
) {}
ngOnInit() {
this.contactForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
phone: [''],
message: ['', Validators.required]
});
this.loading$ = this.contactFacade.loading$;
this.success$ = this.contactFacade.success$;
this.error$ = this.contactFacade.error$;
}
onSubmit() {
if (this.contactForm.valid) {
this.contactFacade.dispatch(new DaffContactSubmit(this.contactForm.value));
}
}
reset() {
this.contactForm.reset();
this.contactFacade.dispatch(new DaffContactReset());
}
}
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()">
<div>
<label>Name:</label>
<input type="text" formControlName="name" />
</div>
<div>
<label>Email:</label>
<input type="email" formControlName="email" />
</div>
<div>
<label>Phone:</label>
<input type="tel" formControlName="phone" />
</div>
<div>
<label>Message:</label>
<textarea formControlName="message"></textarea>
</div>
<button type="submit" [disabled]="(loading$ | async) || !contactForm.valid">
{{ (loading$ | async) ? 'Submitting...' : 'Submit' }}
</button>
<button type="button" (click)="reset()">Reset</button>
<div *ngIf="success$ | async" class="success-message">
Thank you! Your message has been sent successfully.
</div>
<div *ngIf="error$ | async as errors" class="error-message">
<p *ngFor="let error of errors">{{ error.message }}</p>
</div>
</form>