How to get all input fields within a form (AngularJS directive)

20,253

Solution 1

Warning: This is just an idea that works in a trivial example. I'm not saying it's wrong (this is open to discussion, though) but I have NOT used it in a more complicated context.

So... you can actually create a second input directive and have it applied only when another directive (let's say myDirective) has been applied to the enclosing form.

Suppose you have 2 forms:

<body>
    <form name="myForm1" ng-controller="MainCtrl">
      Name: <input id="name1" type="text" ng-model="data.name" /><br/>
      Surname: <input id="surname1" type="text" ng-model="data.surname" />
      <pre>{{data}}</pre>
    </form>
    <br/>
    <form name="myForm2" ng-controller="MainCtrl" my-directive>
      Name: <input id="name2" type="text" ng-model="data.name" /><br/>
      Surname: <input id="surname2" type="text" ng-model="data.surname" />
      <pre>{{data}}</pre>
    </form>
</body>

Only the second form is tagged with my-directive. Now, your directives could look like:

app.directive("myDirective", function(){
    return {
        restrict: 'A',
        require: ['form'],
        controller: function() {
          // nothing here
        },
        link: function(scope, ele, attrs, controllers){
          var formCtrl = controllers[0];
          console.log("myDirective applied to form:", formCtrl.$name);
        }
    };
});

app.directive("input", function(){
    return {
        restrict: 'E',
        priority: -1000,
        require: '^?myDirective',
        link: function(scope, ele, attrs, ctrl){
          if (ctrl) {
            console.log("applying custom behaviour to input: ", ele.attr('id'));
            // ... awesomeness here
          }
        }
    };
});

See it live and check out the logs. The original input directive lives side-by-side with your own. The proof for that is that the form still works (as you type, the model is updated: that's input's and then, ngModel's job).

Your input directive could also use ngModel to manipulate the input value:

app.directive("input", function(){
    return {
        restrict: 'E',
        priority: -1000,
        require: ['?ngModel', '^?myDirective'],
        link: function(scope, ele, attrs, ctrls){
          var ngModel = ctrls[0];
          var myDirective = ctrls[1];
          if (myDirective) {
            console.log("applying custom behaviour to input: ", ele.attr('id'));
            // ... awesomeness here
          }
        }
    };
});

Solution 2

why not use Angular's jqLite (or jQuery if you choose to load it)

angular.forEach(element.find('input'), function(node){ 
 awesomize(node)
});
Share:
20,253
user2422960
Author by

user2422960

Updated on July 09, 2022

Comments

  • user2422960
    user2422960 almost 2 years

    I would like to create a directive which does something awesome with all the input fields within a form.

    However, i'd be happy if i could apply that directive only once (to the <form> itself) instead of having it to bind to all the <input>'s

    How should i determine all of a forms input elements?

    I see some possible solutions:

    element[0].childNodes  // filter all inputs
    element[0].children
    element[0].elements   // seems to contain nothing but the stuff i want
    

    Maybe i am even to close-minded and don't see the correct solution here.

    Any help and opion is appreciated

  • user2422960
    user2422960 over 10 years
    I still shudder when thinking about using jQuery stuff for an Angular application. Nevertheless, i'd give it a try, thank you for pointing out the obvious
  • Vlad Gurovich
    Vlad Gurovich over 10 years
    you have to iterate the dom tree under <form> regardless, might as well do it in a semantically pleasant way(that is provided by angular)
  • The DIMM Reaper
    The DIMM Reaper over 7 years
    I like this approach. It does still have to bind to all the input elements, but conveniently, that happens without any additional tags. This wouldn't apply, for example, to a textarea element. Just something to keep in mind.