CaptainMorgan
CaptainMorgan

Reputation: 1253

Using ng-messages with dynamic field names

I have a list of fields which are displayed using ng-repeat. The name of the input field is dynamic. How do you get ng-messages to work when using dynamic names? Below is what I've tried, but this doesn't work:

<form id="userForm" name="userForm" ng-submit="userForm.$valid && submit()" novalidate>
    <div ng-repeat="uniqueField in uniqueFields">
        <div>
            <label>{{uniqueField.form_field_label}}</label>
            <input required="{{uniqueField.isMandatory}}" name="text_{{uniqueField.form_field_id}}" ng-model="uniqueField.form_field_value" type="text">
            <div ng-messages="userForm.{{uniqueField.form_field_id}}.$error" ng-if="userForm.$submitted && uniqueField.isMandatory == true">
                <div ng-message="required">Please enter a {{uniqueField.form_field_label}}.</div>
            </div>

        </div>
    </div>
</form>

Upvotes: 1

Views: 948

Answers (3)

RahulD
RahulD

Reputation: 757

I have modified trollr's answer, and its working. I added the attr, ng-show="userForm[uniqueField.form_field_id].$error.required"

Here is the solution HTML:

<div ng-app="demoApp" ng-controller="MainCtrl as ctrl">
<code>{{userForm[uniqueField.form_field_id].$error}}</code>
  <form id="userForm" name="userForm" `enter code here`ng-submit="userForm.$valid && ctrl.submit()" novalidate>
    <div ng-repeat="uniqueField in ctrl.uniqueFields">
        <div>
            <label>{{uniqueField.form_field_label}}</label>
            <input required="{{uniqueField.isMandatory}}" name="{{uniqueField.form_field_id}}" ng-model="uniqueField.form_field_value" type="text">
            <div ng-messages="userForm[uniqueField.form_field_id].$error">
                <div class="error" ng-show="userForm[uniqueField.form_field_id].$error.required" ng-message="required">Please enter a {{uniqueField.form_field_label}}.</div>
            </div>
        </div>
    </div>
    <button type="submit">Submit
    </button>
</form>
</div>

And the Controller:

angular.module('demoApp', [])
    .controller('MainCtrl', MainCtrl);

function MainCtrl($log) {
    var ctrl = this;

    function activate() {
        ctrl.uniqueFields = [
      {
        form_field_label: 'Name',
        form_field_id: 'name',
        form_field_value: '',
        isMandatory: true
      }
    ]
    }

    activate();

  ctrl.submit = function() {
    $log.debug('form submitted');
  }
}

Or you can use ng-form instead of form tag.

Working fiddle: http://jsfiddle.net/Q386jmnw/

Upvotes: 0

Tjaart van der Walt
Tjaart van der Walt

Reputation: 5179

You can use the $eval method, you can read more about it here to parse the 'myDynamicForm.' + formField.formFieldId + '.$error' string to an expression.

$scope.$eval Executes the expression on the current scope and returns the result. Any exceptions in the expression are propagated (uncaught). This is useful when evaluating Angular expressions

Please see working jsfiddle here

Remember to register the ngMessages module in your application config.

HTML:

<div class="container">
  <div class="row">
    <div class="col-sm-4" data-ng-controller="DynamicFormController as vm">
      <form name="myDynamicForm" novalidate>
        <div class="form-group" data-ng-repeat="formField in formFields">
          <label for="{{formField.formFieldId}}">{{formField.label}}</label>
          <input class="form-control" name="{{formField.formFieldId}}" id="{{formField.formFieldId}}" ng-required="{{formField.isMandatory}}" type="text" ng-model="formField.value">
          <div ng-messages="vm.onValidateMessages(formField)">
            <label ng-message="required" class="label label-danger">{{formField.label}} required</label>
          </div>
        </div>
        <button type="button" class="btn btn-default" data-ng-click="vm.onSubmitForm()">Submit</button>
     </form>
   </div>
 </div>

JS:

var myApp = angular.module('myApp', ['ngMessages']);

myApp.controller('DynamicFormController', ['$scope', function($scope) {
  var self = this;

  $scope.formFields = [{
    isMandatory: true,
    formFieldId: 'UniqueField1',
    value: null,
    label: 'Email'
   }, {
    isMandatory: false,
    formFieldId: 'UniqueField2',
    value: null,
    label: 'First Name'
  }];

  self.onSubmitForm = function() {
    if (!$scope.myDynamicForm.$valid) {
      console.error('form is invalid');
      return;
    }
  };

  self.onValidateMessages = function(formField) {
    return $scope.$eval('myDynamicForm.' + formField.formFieldId + '.$error');
  };
}]);

Upvotes: 0

trollr
trollr

Reputation: 1115

You prefix the name of your input field with text_ but you lookup userForm.{{uniqueField.form_field_id}}.$error. Remove the prefix and it should work :)

Here is the solution HTML:

<div ng-app="demoApp" ng-controller="MainCtrl as ctrl">
  <form id="userForm" name="userForm" ng-submit="userForm.$valid && ctrl.submit()" novalidate>
    <div ng-repeat="uniqueField in ctrl.uniqueFields">
      <div>
        <label>{{uniqueField.form_field_label}}</label>
        <input required="{{uniqueField.isMandatory}}" name="{{uniqueField.form_field_id}}" ng-model="uniqueField.form_field_value" type="text">
        <div ng-messages="userForm[uniqueField.form_field_id].$error">
          <div ng-message="required">Please enter a {{uniqueField.form_field_label}}.</div>
        </div>
      </div>
    </div>
    <button type="submit">Submit</button>
  </form>
</div>

And the Controller:

angular.module('demoApp', [])
.controller('MainCtrl', MainCtrl);

function MainCtrl($log) {
  var ctrl = this;

  function activate() {
    ctrl.uniqueFields = [{
      form_field_label: 'Name',
      form_field_id: 'name',
      form_field_value: '',
      isMandatory: true
    }]
  }

  activate();

  ctrl.submit = function() {
    $log.debug('form submitted');
  }
}

Working fiddle: https://jsfiddle.net/trollr/133hhwzx/

Upvotes: 0

Related Questions