{% extends "subscribe-form.html" %} {% load static sekizai_tags djng_tags tutorial_tags %} {% block addtoblock %} {{ block.super }} {% addtoblock "ng-config" %}['$httpProvider', function($httpProvider) { $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; $httpProvider.defaults.headers.common['X-CSRFToken'] = '{{ csrf_token }}'; }]{% endaddtoblock %} {% endblock addtoblock %} {% block main-intro %}

Server-Side Form Validation

Django Form's two-way data-binding with an AngularJS controller

New in version 2.0 This example shows how to reflect Django's form data into an AngularJS controller.

{% endblock main-intro %} {% block form_tag %}name="{{ form.form_name }}" method="post" action="." djng-endpoint="." ng-model-options="{allowInvalid: true}" novalidate{% endblock %} {% block form_submission %}   {% endblock %} {% block form_foot %} {% verbatim %}
Scope:
subscribe_data = {{ subscribe_data | json }}
{% endverbatim %} {% endblock form_foot %} {% block main-tutorial %}

When working with Django Forms and AngularJS, it is a common use case to upload the form's model data to an endpoint on the server. If the directive ng-model is added to an input field, then, thanks to AngularJS's two-way databinding, the scope object contains a copy of the actual input field's content.

Auto-adding ng-model to forms

If a form inherits from the mixin class NgModelFormMixin, then django-angular renders each field with the directive ng-model="fieldname". To prevent polluting the scope's namespace, it is common practice to encapsulate all the form fields into a separate JavaScript object. The name of this encapsulating object can be set during the form definition, using the class member scope_prefix. Furthermore, set the class member form_name to a different name. If omitted, the mixin class will invent a unique form name for you. The form_name must be different from scope_prefix, because AngularJS's internal form controller adds its own object to the scope, and this objects is named after the form. To prevent confusion, name your forms ending in something such as …_form, whereas the form's models shall be kept inside an object ending in …_data.

In this example, an additional server-side validations has been added to the form: The method clean() rejects the combination of “John” and “Doe” for the first- and last name respectively. Errors for a failed form validation are send back to the client and displayed on top of the form.

Using directive djng-endpoint

We must inform the client where we want the form data to be sent. For this purpose, django-angular offers the attribute directive <form djng-endpoint="/path/to/endpoint">. This is the Ajax's counterpart of the action="…" form attribute.

Error responses

Form data submitted by Ajax, is validated by the server using the same functionality as if it would have been submitted using the classic application/x-www-form-urlencoded POST submission. Errors detected during such a validation, are sent back to the client using a JSON object. This object for example, is structured such as: {"formname": {"errors": {"fieldname1": ["This field is required."]}, "__all__": ["The combination of username and password is not correct."]}}}. Just as in Django, the __all__ is used for form errors not associated with a certain field. Such an error, typically is rendered on top of the form.

Populating the form

Sometimes it is desirable to use an Ajax request to prefill all or a subset of the form fields with values. Whenever the Django endpoint adds an object such as {"formname": {"models": {"fieldname1": "Some value", "fieldname2": "Other value"}}} to the response object, then the django-angular form-controller adds those values to the form's input fields.

Forms Submission

The submit button(s) must be placed anywhere inside the <form>…</form> element. To send the form's content to the server, add ng-click="do(update())" to the submission button. We have to start this expression with do(…), in order to emulate the first promise, see below.

By itself, do(update()) would just send the data to the server, but not invoke any further action on the client. We therefore must tell our directive, what we want to do next. For this purpose, django-angular's button directive offers a few prepared targets, which all can be chained in any order. If we change the above to ng-click="do(update()).then(reloadPage())", then after a successful submission the current page is reloaded. This is explained in detail in the next example.

{% endblock main-tutorial %} {% block main-sample-code %} {% autoescape off %}
{% pygments "forms/model_scope.py" %}
{% pygments "views/model_scope.py" %}
{% pygments "tutorial/model-scope.html" %}
{% endautoescape %} {% verbatim %}

Note: The AngularJS app is configured inside Django's HTML template code, since template tags, such as {​{ csrf_token }​} can't be expanded in pure JavaScript.

{% endverbatim %} {% endblock main-sample-code %}