1
\$\begingroup\$

I have a lot of <input> elements in my single page app that share a similar style for validation. To decrease the amount of code repeated (following DRY principals) I've created a Partial using ejs-local and ejs in an AngularJS application.

<%
// input.ejs - Partial
/* This file can take the following
 id: string - An id on the input for tests to grab the element
 parentForm: string - The form that hosts the element
 label: string - What is displayed labeling the input field;
 ngModel: string - the ng-model item to bind to the input;
 ngDisabled: boolean - the ng-disabled to bind to the input;
 type: string - The type of the input;
 placeholder: string - Text to show in the placeholder;
 layout: string - Horiz2, Horiz3, Vert, Vert6, Horiz2_2;
 tooltip: string (optional) - Displayed with '?'
 required: bool (optional) - If input value is required
 */
if (typeof tooltip === 'undefined') {
    tooltip = '';
}

if (typeof required === 'undefined') {
    required = false;
}

var _layoutLabelCss = {
    Horiz2: 'col-md-2',
    Horiz3: 'col-md-3',
    Vert: '',
    Vert6: '',
    Horiz2_2: 'col-md-2'
};
var _layoutInputCss = {
    Horiz2: 'col-md-10',
    Horiz3: 'col-md-9',
    Vert: '',
    Vert6: '',
    Horiz2_2: 'col-md-2'
};
var _layoutGroupCss = {
    Horiz2: 'clearfix',
    Horiz3: 'clearfix',
    Vert: 'col-xs-12',
    Vert6: 'col-sm-6',
    Horiz2_2: 'clearfix'
};
%>
<div class="form-group <%= _layoutGroupCss[layout] %>"
     ng-class="{ 'has-error': (<%=parentForm%>.$submitted || <%= parentForm %>.<%= id %>.$touched) && <%= parentForm %>.<%= id %>.$invalid }">
    <label class="control-label <%= _layoutLabelCss[layout] %>"
           for="<%= id %>">
        <%= label %>:
        <% if (!!tooltip) { %>
        <i class="fa fa-question-circle"
           title="<%= tooltip %>"></i>
        <% } %>
    </label>

    <div class="<%= _layoutInputCss[layout] %>">
        <div>
            <input id="<%= id %>"
                   name="<%= id %>"
                   class="form-control"
                   data-toggle="tooltip"
                   type="<%= type %>"
                   placeholder="<%= placeholder %>"
                   ng-model="<%= ngModel %>"
                   ng-disabled="<%= ngDisabled %>"
                   ng-required="<%= required %>"
                    />
        </div>
        <% if (required) { %>
        <div class="text-danger"
             ng-show="(<%=parentForm%>.$submitted || <%= parentForm %>.<%= id %>.$touched) && <%= parentForm %>.<%= id %>.$error.required">
            <i class="fa fa-asterisk"></i> This field is required.
        </div>
        <% } %>
    </div>
</div>

Example Usage

<%- partial('partials/input', {
      id: 'email',
      parentForm: 'loginForm',
      label: 'Email',
      type: 'text',
      placeholder: 'email@domain.com',
      ngModel: 'email',
      ngDisabled: 'isBusy',
      required: true,
      layout: 'Vert'
  }) %>

Gist available here

I have a couple of opinions on the code that hopefully someone can suggest an alternative:

  1. Generic Validation - This was easier in knockout validation in that I could have a generic error message for a single 'model' using validationElement and validationMessage rather than having to go through $error to show\hide various elements.

  2. Not very testable - I can hit it with protractor & check the console output for errors, but that's about the extent of the testing that can be done on this code.

  3. Client\Server side - Feels kind of dirty to be passing in the string for ng-model. Would a custom Angular directive be a better choice? If so, how would items like <%= parentForm %>.<%= id %>.$touched be created?

  4. Overcomplicated - Would I be better off just biting the bullet and cut\pasting the same code everywhere? Since there are a lot of customizations (i.e. layout, validation), then maybe it makes sense to have similar (but not identical) code everywhere...

Any thoughts\comments\questions are welcome.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.