1

I'm trying do a small reusable component in AngularJS using directives. I have made good progress but I have a problem with the validations. For example the required validation not working. I think is "binding" issue.

My HTML code: also in http://jsfiddle.net/pQwht/17/

<html ng-app="myApp">
<body>
<form ng-controller="Ctrl"
  id="paymentCallForm"
  action="#"
  name="paymentCallForm">
  <table>
   <tr tdfield 
      labelname="Primary Account Number:" 
      fieldname="primaryAccountNumber"
      title="Primary title" 
      >
    </tr>  
  </table>

My directive script:

 angular.module('myApp').directive('tdfield', function() {
    return {
    restrict: 'A',
    replace:false,
    transclude: false,
    scope: { labelname: '@', fieldname: '@', title: '@'},
    templateUrl:'element.html'
  };
 });

My element.html code:

 <td id="lbl_paymentReference" class="formInputLabelWrapper">{{labelname}}</td>
 <td class="formInputTextWrapper">
   <input id="{{fieldname}}"
     name="{{fieldname}}"
     title="{{title}}" 
     class="large empty"  
     required>
<span data-ng-show="paymentCallForm.{{fieldname}}.$error.required"
    class="error">Error</span></td>
2
  • Your <table does not have a closing > Commented Apr 26, 2013 at 23:28
  • Thanks Ketan, was a typing error. In the jsfiddle is right. Commented Apr 27, 2013 at 1:37

2 Answers 2

2

Well, I solved this, but for what a price. There is a number of issues and angular related among them. I may not recall all, so here is the working example https://github.com/yaroslav-ulanovych/soq16245177.

When you define scope parameter like scope: { labelname: '@', fieldname: '@', title: '@'}, (with an object as a value), that creates an isolated scope, which means not inherited from parent one's. Therefore here ng-show="paymentCallForm.{{fieldname}}.$error.required" is no access to the form. As a workaround ng-show="$parent.paymentCallForm.{{fieldname}}.$error.required", but I didn't check whether your inputs are published in the form in case of the isolated scope. Or scope: true and inject attributes into the scope manually.

compile: function() {
    return {
        pre: function (scope, element, attr) {
            scope.fieldname = attr.fieldname;
        }
    }
}

Note on using prelink function, so that it's called before children are linked.

Next ng-show will actually use not interpolated expression and there is obviously no property named {{fieldname}} in the form. That is fixed in later versions of Angular, don't know when exactly, cause I'm using master.

But what is not fixed is ngModelController. It gets it's name very early so publishes itself on the form under wrong one. I had to fix that myself, good that there is only one line to do that, in file src/ng/directive/input.js.

// add
modelCtrl.$name = attr.name;
// before this
formCtrl.$addControl(modelCtrl);
Sign up to request clarification or add additional context in comments.

2 Comments

Yaroslav, for use angular 1.1.1 in the element.html I used <span data-ng-show="form['\{\{fieldname\}\}'].$error.required" class="error">Error</span>
That works, cause both input and span use the same field name which is {{fieldname}}, not primaryAccountNumber. If you add the second row in the table, you see that it's input is ignored and the first input controls both spans.
0

I believe you need a controller attached to your view. The form object will be attached to property with the id of the form on $scope object of this controller. Once you add that, I think it will start showing up.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.