2

I have the following (https://jsfiddle.net/f30bj43t/5/) HTML:

<div ng-controller="DataController as vm">
  <div ng-repeat="name in vm.users track by $index">{{name}}</div>
  <form name="form" validation="vm.errors">
    <input validator ng-model="vm.name" name="vm.name" placeholder="name" type="text" />
    <a href="#" ng-click="vm.add(vm.name)">Add</a>
  </form>
</div>

This form adds names to a list and the controller is:

app.controller("DataController", DataController);

function DataController() {
  var vm = this;
  vm.name = "Mary";
  vm.users = ["Alice", "Peter"];
  vm.errors = [];
  vm.add = function(name) {  
    if (name == "Mary") {
      var error = { property: "name", message: "name cannot be Mary"};
      if (vm.errors.length == 0) 
        vm.errors.push(error);        
      } else {
        vm.users.push(name);      
        vm.errors = [];
      }      
    }
}

On the form I added validation="vm.errors" that defines which variable holds the errors to be used in each validator directive ...

Then in each validator directive I will use that variable to pick the correct error and display it ...

app.directive("validation", validation);

function validation() {

  var validation = {
    controller: ["$scope", controller],
    replace: false,
    restrict: "A",
    scope: {
      validation: "="
    }
  };

  return validation;

  function controller($scope) { 
    this.getErrors = function () {
      return $scope.validation;
    }    
  } 

}  

app.directive("validator", validator);

function validator() {

  var validator = {
    link: link,
    replace: false,
    require: "^validation",
    restrict: "A"
  };

  return validator;

  function link(scope, element, attributes, controller) {    
    var errors = controller.getErrors();
    console.log(errors);    
    // do something with errors
  } 

}

PROBLEM

In link function of validator directive I need to track changes of the variable passed by validation="vm.errors" so I can in each validator check if a error occurs and take action.

But console.log(errors) seems to have no effect ...

How can I solve this?

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • Have you tested your JSFiddle? It's not working correctly – Gabriel Câmara Apr 22 '16 at 11:27
  • Just updated it: https://jsfiddle.net/f30bj43t/5/. BTW the problem with the previous fiddler was that moving validator from form to the outer div where I have the controller gives me that error ... It is something I also wanted to solve. – Miguel Moura Apr 22 '16 at 11:29

2 Answers2

1

You can do it with either $watch or $broadcast and $on.
I preffer to use the $on, because watching a variable consumes more than listening to an event and I'd say that to your case it's better to use $broadcast and $on, because you're not watching a scope variable, but a variable from a controller.

If you want to learn more about $on and $watch, here's a suggestion: Angular JS $watch vs $on

And here's your JSFiddle with the modifications.

Community
  • 1
  • 1
Gabriel Câmara
  • 1,249
  • 15
  • 22
  • Gabriel, unfortunately I cannot use your example as I need all work to be done on the directives side ... So it must be a directive to watch what happens in the variable defined in validation="vm.errors". So I think the way to do this is using watch. My idea was something like: https://jsfiddle.net/q0dy20nv/1/ ... Can you help me out in making this work ... This has been my biggest problem. – Miguel Moura Apr 22 '16 at 13:31
  • I'm sorry that I took so long to answer, I've been busy. Now I've just updated the JSFiddle, please check and tell if it fills your needs. =) – Gabriel Câmara Apr 23 '16 at 16:52
  • I followed your example but something strange happens. If the variable is not an array and I watch it instead of watching its length the watch fires only once ... Do you have any idea why? I forked your example with just that change: https://jsfiddle.net/qb8o006h/2/ – Miguel Moura Apr 24 '16 at 20:06
  • Here's an adjustment https://jsfiddle.net/qb8o006h/4/ . I'm guessing the problem is because the changes in the variable won't reflect in controller since its a number, not a javascript object, and everytime you update it, the reference is lost. I made the controller watch the variable and that did the trick. If there's another reason, I really don't know. – Gabriel Câmara Apr 24 '16 at 20:39
1

Here you have a working jsfiddle: https://jsfiddle.net/f30bj43t/8/

I am logging the vm.errors variable into the console each time it changes:

function link(scope, element, attributes, controller) {   
    scope.$watch('vm.errors.length', function () {
        if(scope.vm.errors){
            console.log(scope.vm.errors);
        }   
  });
} 

This is possible due to the scope inheritance. On your case, vm is a variable added to the controller's scope, and all directives inside this scope will inherit it by default (there are ways to avoid that).

Anyhow it seems you are creating too much directives. On your case, for me would be enough having everything in the controller.

Cheers

Javier

JavierFromMadrid
  • 621
  • 9
  • 21
  • Sorry, but that won't work for me ... I have already done that. The problem is in one page I might have multiple controllers with vm1, vm2, and so on ... That is why I am using validation="vm.errors". To indicate where are the errors. That is my main problem ... I need to be able to indicate in validation="vm1.errors" what is the variable to watch. See why your example won't work: https://jsfiddle.net/cLqa1gqd/1/. – Miguel Moura Apr 23 '16 at 11:28