0

I am working on a select directive that knows its repository and loads its data. this directive has a very simple template.

<select></select>

I have a compile function that adds a ng-options directive to our select. since the rendered element on the from is a select I expect that putting a ng-change directive on our element will call the related change function but it is called only once.Here's a code snippet that I made to share the code.

Here is also a plunker version of same code :https://plnkr.co/edit/D8lErJWKZyrAeI6BZ7iJ

// Code goes here

var app = angular.module("myShoppingList", []); 
app.controller("myCtrl",['$scope','productsRepository', function($scope,productsRepository) {
    $scope.products =productsRepository.getAll();
    $scope.selectdProduct={};
    $scope.onSelectedProductChanged=function(item){
      alert(item);
    }
}]);

app.service("productsRepository",[function(){
  return {
    getAll:function(){return [
      {
        id:1,title:'Milk'
      },
      {
        id:2,title:'Bread'
      },
      {
        id:3,title:'Cheese'
      }
      ]}
  }
}]);

app.directive("productsComboBox",['$compile','productsRepository',function($compile,productsRepository){
  return {
    restrict:'E',
    replace:true,
    template:'<select></select>',
    scope:{
      ngModel:'='
    },
    require:'ngModel',
    compile:function(elm,atts){
      elm.attr('ng-options','item.id as item.title for item in items' );
      var fn=$compile(elm);
      return function(scope,elm,atts){
        
          fn(scope);
          scope.items=productsRepository.getAll();
          console.log(scope.items);
      }
    }
  }
}])
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="4.0.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.10/angular.min.js"></script>
    <script data-require="angular.js@*" data-semver="4.0.0" src="script.ts"></script>
    <script data-require="angular.js@*" data-semver="4.0.0" src="system.config.js"></script>
    <script data-require="angular.js@*" data-semver="4.0.0" src="tsconfig.json"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app='myShoppingList' ng-controller='myCtrl'>
    <ul>
      <li ng-repeat='product in products'>{{product.title}}</li>
    </ul>
    <products-combo-box ng-model='selectdProduct' ng-change='onSelectedProductChanged(selectdProduct)'></products-combo-box>
  </body>

</html>

I have seen other question about the same problem but there's a difference between my problem and those questions. We don't have any root element in our template and thus ng=change is placed in our select and we can not define a ng-model for our select in our directive so that we can call the ng-change of the parent.

5
  • can't you do it through directive controller? You are losing the model with isolated scope, etc. It might be better to use bindToController and pass a reference to a function through an attribute Commented Nov 13, 2018 at 11:11
  • can you please explain it more in an answer. Commented Nov 13, 2018 at 11:27
  • The ng-change directive only works when there is an ng-model directive on the same element. Commented Nov 13, 2018 at 12:11
  • @georgeawg what do mean by same element ? cause we have a ng-model on our combo box element and when it is replaced it will be copied to our select tag. Commented Nov 13, 2018 at 12:34
  • Using replace: true is probably not a good idea. See Why is replace property deprecated in AngularJS directives?. Commented Nov 13, 2018 at 15:28

1 Answer 1

0

Try using $scope.$watch instead of ng-change, it will be easier to manage the value:

$scope.$watch('selectdProduct', function (item) {
    alert(item);
});
Sign up to request clarification or add additional context in comments.

2 Comments

the problem is I am writing the directive for a legacy system that uses ng-change and other directives such as ng-click .I can not tell our developers to change them . we want only to replace <select> tags with our custom directive and everything work as before
Using $scope.$watch might be easier but it will be far more heavy for the application.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.