tpie
tpie

Reputation: 6221

Two-way binding within nested directives and ui-select

Problem I have been working on:

The original problem (which only addressed one-way binding) can be found here: Unable to pass/update ngModel from controller to directive

I have managed to get the one-way binding from inside the directive out to the view working. But if I want push in a selection when the page loads, for example, I cannot get the two-way binding to function. I can see that the ng-model inside the first directive is getting the data, but I tried various scope settings with the child directive and either it breaks it or it does the same thing as before - nothing.

I have a basic $watch function set up, so that when I push a simple object into the binding that is attached to ng-model in the view, the watcher assigns the $viewValue to the directive's scope object. It does this, and the directive responds only by having any existing selection wiped out, even though I can clearly see the objects inside ng-model binding assigned to ui-select.

Here is the watch function:

scope.$watch(function() {
    return ngModel.$viewValue;
}, function(newVal) {
    console.log(newVal, scope.options);
    scope.options.selected = newVal;
});

I use this function to update the view whenever we interact with the ui-select (which works fine):

scope.changer = function() {
   ngModel.$setViewValue(scope.options.selected);
   console.log(scope.options.selected);
};

A Plunker for tinkering

So the expected behavior is:

Upvotes: 2

Views: 1228

Answers (1)

tpie
tpie

Reputation: 6221

The situation was that I had a directive with ui-select inside it. The way I was able to get data from the main controller scope through the directive scope and down to ui-select's scope was by putting a watch function on ngModel.$viewValue in the link function of the directive.

I then assigned that new value, whenever there was a change, to an object on that directive's scope, to hold it for me. Then I set a watch function in the link function of ui-select to watch scope.$parent.myVal so that if anything was ever pushed to that variable from the main controller, ui-select would see it. When that happened, I would assign that new value to $select.selected which is the container for selected items in the ui-select directive.

It should be noted that ui-select uses scope: true in it's directive, and thus becomes a child of whatever scope it is instantiated in, which allows you to access the scope of it's parent with $parent.

Watch function for the directive:

scope.$watch(function() {
  return scope.$parent.myVar;
}, function(newVal) {
  $select.selected = newVal;
}) 

Watch function to be added to ui-select:

scope.$watch(function() {
  return ngModel.$viewValue;
}, function(newVal) {
  scope.myVar = newVal;
})

Plunker Demo

Upvotes: 2

Related Questions