Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update controller scope from directive

I am creating reusable UI components with AngularJS directives. I would like to have a controller that contains my business logic with the nested components (directives). I want the directives to be able to manipulate a single property on the controller scope. The directives need to have an isolate scope because I might use the same directive more than once, and each instance needs to be bound to a particular controller scope property.

So far, the only way I can apply changes back to the controller's scope is to call scope.$apply() from the directive. But this breaks when I'm inside of an ng-click callback because of rootScope:inprog (scope operation in progress) errors.

So my question: What is the best way to make my controller aware when a child directive has updated a value on the controller's scope?

I've considered having a function on the controller that the directive could call to make an update, but that seems heavy to me.

Here is my code that breaks on an ng-click callback. Keep in mind that I don't just want to solve the ng-click issue. I want the best overall solution to apply reusable directives to modify a parent scope/model.

html

<div ng-controller="myCtrl">
    <my-directive value="val1"></my-directive>
</div>

controller

...
.controller('myCtrl', ['$scope', function ($scope) {
    $scope.val1 = 'something';
}});

directive

...
.directive('myDirective', [function () {

return {
    link: function(scope) {
        scope.buttonClick = function () {
            var val = 'new value';
            scope.value = val;
            scope.$apply(); 
        };
    },
    scope: {
        value: '='
    },
    template: '<button ng-click="buttonClick()"></button>'
};
}]);
like image 485
Brett Avatar asked Feb 27 '15 16:02

Brett


1 Answers

The purpose of two-way data binding in directives is exactly what you're asking about -- to "[allow] directives to modify a parent scope/model."

First, double-check that you have set up two-way data binding correctly on the directive attribute which exposes the variable you want to share between scopes. In the controller, you can use $watch to detect updates if you need to do something when the value changes. In addition, you have the option of adding an event-handler attribute to the directive. This allows the directive to call a function when something happens. Here's an example:

<div ng-controller="myCtrl">
    <my-directive value="val1" on-val-change="myFunc"> <!-- Added on-change binding -->
        <button ng-click="buttonClick()"></button>
    </my-directive>
</div>
like image 90
AlexMA Avatar answered Oct 27 '22 21:10

AlexMA