您的位置:首页 > Web前端 > AngularJS

Implementing Angular2 forms – Beyond basics (part 3)

2016-03-16 16:15 253 查看
In the first part of
this article, we deal with foundations of the form support. We then describe in a second
part
more advanced features to make form creation and processing more concise and robust. It’s now time to tackle the form submission.

Handling form submission

Angular 2 automatically applies the
NgForm
directive to the HTML form element. The main consequence is that we need to disable the default behavior of browsers and apply the one from Angular 2. That way a specific
event is fired and processing remains in the same page.

Submitting data

To submit data, we need to leverage the submit event of the form with the Angular 2 syntax. This event is triggered when clicking on an HTML submit button.
Simply register processing against this event using the bracket expression. In the following sample, we call the
onSubmit
method of the component when the
submit
event
occurs.
<form [ngFormModel]="companyForm" (submit)="onSubmit()">
(...)
<button type="submit">Save</button>
(...)
</form>

This
onSubmit
method will leverage the
CompanyService
service injected in the component to actually update the company data in the RESTful service. To give the user some
feedback, we can use a
submitPending
property to display a spinning icon during the execution of the HTTP request. When response is back, you can hide it and display a message using the Toastr library.
onSubmit() {
this.submitPending = true;
this.service.updateCompany(this.companyId, this.company).subscribe(
company => {
toastr.info('Company successfully updated');
this.submitPending = false;
}, error => {
(...)
}
);
return false;
}

We will see in the next section how to handle errors.
This
submitPending
property also allows us to disable the submit button to prevent users from clicking several times. For this we can simply use interpolation for the
disabled
attribute
of the button. This way the value of this attribute will be linked to the provided expression. This can be combined with the
pending
property of the form control to disable the button as well during asynchronous validation.
<button type="submit" [disabled]="submitPending || companyForm.pending">
Save
<span *ngIf="submitPending"
class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>
</button>

Here is the result.






Form submission error handling

In the previous section, we intentionally didn’t handle errors that could occur when executing the HTTP request to save the company. To make this processing more robust, we need to handle them. This must be done at two different levels.
First in the service. Since the map operator isn’t called in the case of failures, we need to extract the JSON error content from the payload using the catch operator, as described below:
updateCompany(companyId:string,company:Company) {
var headers = new Headers();
this.createAuthorizationHeader(headers);
headers.append('Content-Type', 'application/json');

return this.http.put(
`https://Angular 2.apispark.net/v1/companies/${companyId}`,
JSON.stringify(company), {
headers: headers
}).map(res => res.json()).catch(res => {
return Observable.throw(res.json());
});
}

Observables provide operators to configure asynchronous data streams. This aspect is part of Reactive Programming that will be discussed in a following article. We used the map operator in a previous Angular2 article in the section “Interacting
with the Web API”.
This way we will receive the error as JSON object when defining a second callback at the level of the subscribe method in the component. We can then directly handle it.
onSubmit() {
this.service.updateCompany(this.companyId, this.company).subscribe(
company => {
(...)
}, error => {
this.displayErrors(error);
}
);
return false;
}

Now we receive the error payload within the error callback registered in the subscribe method, we can distinguish two kinds of errors to handle within the displayErrors method:

Global errors that notify that the update fails

Server validation errors that are linked to the fields of the form

The method has the responsibility to handle both cases. In the first one, an error property is set with the message. A dedicated component will then use this property to display the message.
For field errors, the method will look for fields with errors and set them within their corresponding controls. All these hints are present in the error content as we can see within the DHC
HTTP client.



Here is its complete implementation.
displayErrors(error) {
if (error.messages) {
var messages = error.messages;
messages.forEach((message) => {
this.companyForm.controls[message.property].setErrors({ remote: message.message });
});
} else {
this.error = `${error.reasonPhrase} (${error.code})`;
}
}

Server validation errors for fields are displayed the same way as the local ones at the level of field inputs.



To display global errors as Bootstrap does, we need to go further by creating a simple component, as described below. It will leverage the alert* classes of the library.
@Component({
selector: 'error',
template: `
<div *ngIf="error" class="form-group form-group-sm">
<div class="alert alert-warning alert-dismissible col-md-10 col-sm-10" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{error}}
</div>
</div>
`
})
export class FormErrorComponent {
@Input()
error:string;
}

Simply add an tag in your form to specify where to display the error after having adding the FormErrorComponent component into the directives attribute of the component containing the form:
@Component({
directives: [ (...), FormErrorComponent ],
template: `
<form [ngFormModel]="companyForm" (submit)="onSubmit()">
(...)
<error [error]="error"></error>
</form>
`
})
export class DetailsComponent {
(...)
}

Here is how such messages will be displayed in the form.



Conclusion

In this article, we described how to implement forms with Angular 2. We went beyond the basics to show how to leverage the power of Angular 2. We saw how the standard form support of Angular 2 can fit into its component-based approach to implement
concise and powerful forms.
In this article, we made an effort to split form building and processing into several small components that interact together to provide the company editing feature. All this work contributes to improve code maintainability and reusability, since
it’s possible to reuse most of these components into other forms of the application.
As stated form controls can also leverage observables and reactive programming to make other parts of the application react following user inputs. We will focus on the support of such approaches within Angular 2 in a following article, so stay tuned!
The source code is available in the following Github repository: https://github.com/restlet/restlet-sample-angular2-forms.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: