jcm
jcm

Reputation: 5659

How can I get a reference to the enclosing form element from within an angularjs directive?

I have the following HTML:

<form name="my-form">
  <div class="col-sm-4">
    <input type="phone" name="mobileNumber" ng-model="form.mobileNumber" value="0439888999" required>
  </div>
</form>

And the following code in a directive:

angular.module('myApp.directives')
    .directive('required', function ($compile) {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {
                var formName = element.parents('form').attr('name');
                var fieldName = element.attr('name');
            }
     };
});

but when I run my unit test, I get the error: TypeError: Object [object Object] has no method 'parents'.

I know this is because jqLite that is packaged with my version of AngularJS (v1.2.13) doesn't support the parents method.

My question is, how can I implement this same functionality inside my directive? Do I need to use jQuery and if so, how do I inject it as a dependency into my directive and unit test?

Upvotes: 1

Views: 1280

Answers (2)

zszep
zszep

Reputation: 4458

If you just want to test the validity of the form (phone is required), you don't need a custom directive. Just use this code:

  <body ng-controller="MainCtrl">
    <form name="xform">
      <div class="col-sm-4">
        <input test type="phone" name="phone" ng-model="data.phone" required>
      </div>
      <p ng-if="xform.$valid">Valid</p>
      <p ng-if="!xform.$valid">Not valid</p>
    </form>
  </body>

If you still need to access the model and the form in a custom directive, you should use require in the directive to get access to the model and form controller. This should give you a direction how to solve your problem:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.data.phone = '031 584 658';
});

app.directive("test", function(){
  return {
    controller: function($scope) {
      $scope.$watch('xform.$valid', function(newVal, oldVal) {
        console.log('form validity has changed', newVal, oldVal);
      })
    },
    link: function(scope,element,attrs,controllers) {
      var model = controllers[0];
      var form = controllers[1];
      //console.log(model);
      //console.log(form);
      //console.log(form.$valid);
    },
    require: ['ngModel', '^form'],
  }
})

Here is a working plunker.

Upvotes: 0

Paul Rad
Paul Rad

Reputation: 4882

Replace parents by parent should work ;)

var formName = element.parent('form').attr('name');

List of availables methods with jQlite:

http://docs.angularjs.org/api/ng/function/angular.element

Upvotes: 1

Related Questions