Search code examples
angularjsangular-ngmodelangularjs-ng-model

Reducing ng-model boilerplate code (DRY)


Using ng-model, the sign in form in our app has ended up looking something like this:

<form name="signIn" ng-submit="ctrl.signIn()" novalidate>
    <label class="item item-input" ng-class="{'invalid': signIn.email.$invalid && (signIn.$submitted || signIn.email.$touched)}">
        <input name="email" type="email" placeholder="Email Address" ng-model="ctrl.email" required>
    </label>
    <div class="form-errors" ng-messages="signIn.email.$error" ng-if="signIn.$submitted || signIn.email.$touched">
        <div ng-messages-include="app/common/form-messages.html"></div>
    </div>

    <label class="item item-input" ng-class="{'invalid': signIn.password.$invalid && (signIn.$submitted || signIn.password.$touched)}">
        <input name="password" type="password" placeholder="Password" ng-model="ctrl.password" required>
    </label>
    <div class="form-errors" ng-messages="signIn.password.$error" ng-if="signIn.$submitted || signIn.password.$touched">
        <div ng-messages-include="app/common/form-messages.html"></div>
    </div>

    <div class="list">
        <button class="button button-block button-positive">
            <b>Sign In</b>
        </button>
    </div>
</form>

This feels very repetitive to me. In a form with more than two inputs, this code would become quite overwhelming.

I'm an experienced developer, but new to Angular. What's the "Angular way" for reducing this boilerplate?

Specifically:

  • Every <label/> element will have essentially the same ng-class attribute of the form {'invalid': signIn.<field_name>.$invalid && (signIn.$submitted || signIn.<field_name>.$touched)}.

  • Every <label/> element will be followed by essentially the same <div class="form-errors"...> element. Similar to above, the only difference will be the field referenced.

As I try to "think in Angular" (especially with an eye toward Components), it seems that the best approach would be to make each <label></label><div class="form-errors"></div> pair a directive. I would simply need to pass into the directive the various attributes to use for each <input/> element (e.g. name, type, placeholder, ng-model, and ng-model validators (e.g. required)).

Is this the recommended "Angular way" to solve this problem?


Solution

  • I agree with you, the angular aproach would be to create a directive for that or if you use Angular 1.5+ a component.