takeradi
takeradi

Reputation: 3861

Two way binding from the link function

Can someone tell me why I am not able to two way bind from the link function?

Please refer to this plunk: http://plnkr.co/edit/RI1ztP?p=preview

The below watch successfully adds the collection to attrs.ngModel but I dont see it reflecting in the parent controller

scope.$watchCollection("selectedItems",function(collection){
    attrs.ngModel = [];
    for(var i=0;i<collection.length;i++){
      attrs.ngModel.push(collection[i]);
    }
    console.log("ngModel",attrs.ngModel);
  });

Cant see the collection over here (selectedUsers):

<body ng-controller="mainCtrl">
 <div multi-select-search-box ng-model="selectedUsers" label="name" my-options="state in states"></div>
{{selectedUsers}}

If you look at the above html, I am binding the selectedUsers array to ng-model. In my link function, i add the selected users to attrs.ngModel array. When I look at the console, the selectedUsers are added to attrs.ngModel but the array isn't reflected back on the html {{selectedUsers}}

Upvotes: 0

Views: 562

Answers (2)

takeradi
takeradi

Reputation: 3861

The solution was to require the ng-model controller and sync changes using the viewValue array:

scope.$watchCollection("selectedItems",function(collection){
    ctrl.$viewValue.splice(0,ctrl.$viewValue.length);
    for(var i=0;i<collection.length;i++){
      ctrl.$viewValue.push(collection[i]);
    }
  });

and

require: 'ngModel'

Upvotes: 0

Sean Larkin
Sean Larkin

Reputation: 6430

The data bound to the ng-model of your multi-select-search-box is $scope.selectedUsers.

Therefore to register a change in the DOM you have to update that variable rather than ng-model.

scope.$watchCollection("selectedItems",function(collection){
  for(var i=0;i<collection.length;i++){
    scope.myNgModelVar.push(collection[i]);
  }
});

Since ng-model is a string that gets $parse()/$eval() called on it to evaluate it as an expression, updating that ng-model value won't do you any good.

EDIT:

After some clarification it appears that this is a custom directive designed to be reusable. So therefore we do not want to stick variables from your controller inside the directive. Instead, you should bind a directive attribute to your directives scope.

// Directive Def. Object:

return {
  restrict: "AE",
  scope: {
    myNgModelVar: "=",
    bindModel: "=ngModel" //This is the alternate method aliasing ngModel var with a scope var.
  },
  template: "<input ng-model='myNgModelVar' />"
};

Although you could use ngModel by using an alias scope: {bindModel:'=ngModel'}, this gives you an isolated scope variable that you bind to ngModel instead. Therefore keeping your directive reusable.

Upvotes: 1

Related Questions