Lodin
Lodin

Reputation: 2068

Bind a property from one directive to another

I'm trying to use "Component approach" from Angular2 in Angular1, and my directives should send properties to each other. I've written code like this:

Parent directive

angular
    .module('myModule')
    .controller('parentController', ParentController)
    .directive('parentDirective', () => {
        return {
            restrict: 'E',
            scope: {},
            controller: 'parentController',
            controllerAs: 'ctrl',
            templateUrl: 'parent-template.html'
        }
    });

class ParentController {
    constructor() {
        this._increasableValue = 0;

        setInterval(() => {
            this._increasableValue += 1;
        })
    }

    get increasableValue() { return this._increasableValue; }
}

parent-template.html

<div class="container">
    <child-directive inc="{{ctrl.increasableValue}}"></child-directive>
</div>

Child directive

angular
    .module('myModule')
    .controller('childController', ChildController)
    .directive('childDirective', () => {
        return {
            restrict: 'E',
            scope: {
                increasableValue: '@inc'
            },
            bindToController: true,
            controller: 'childController',
            controllerAs: 'ctrl',
            templateUrl: 'child-template.html'
        }
    });

class ChildController {
    set increasableValue(value) { this._increasableValue = value; }
    get increasableValue() { return this._increasableValue; }
}

child-template.html

<div class="container">
    <div>{{ctrl.increasableValue}}</div>
</div>

But the increasableValue freezes on start value and do not changes at all. What should be done to get increasableValue from parent directive and bind it to child?

UPD: Here is jsfiddle to demonstrate problem (look at the console too).

Upvotes: 0

Views: 51

Answers (2)

Grundy
Grundy

Reputation: 13382

Yes you right! Problem is how you update your variable.

Angular not know, that value changed, and not call digest loop to update view.
Sample with $inteval service

angular.module('myModule', []);

var ParentController = (() => {
    function ParentController($interval) {
      this._increasableValue = 1;

      var interval = $interval(() => {
        this._increasableValue += 1;
        console.log(this._increasableValue);

        if (this._increasableValue > 20) {
          $interval.cancel(interval);
        }
      }, 1000);
    }

    Object.defineProperty(ParentController.prototype, "increasableValue", {
        get: function () { return this._increasableValue; },
        enumerable: true,
        configurable: true
    });
    
    return ParentController;
})()

var ChildController = (() => {
		function ChildController() {}

    Object.defineProperty(ChildController.prototype, "increasableValue", {
        get: function () { return this._increasableValue; },
        set: function (value) { this._increasableValue = value; },
        enumerable: true,
        configurable: true
    });
    
    return ChildController;
})();

angular
    .module('myModule')
    .controller('parentController', ParentController)
    .directive('parentDirective', () => {
        return {
            restrict: 'E',
            scope: {},
            controller: 'parentController',
            controllerAs: 'ctrl',
            template: `
<div class="container">
		<child-directive inc="ctrl.increasableValue"></child-directive>
</div>`
        }
    });

angular
    .module('myModule')
    .controller('childController', ChildController)
    .directive('childDirective', () => {
        return {
            restrict: 'E',
            scope: {
                increasableValue: '=inc'
            },
            bindToController: true,
            controller: 'childController',
            controllerAs: 'ctrl',
            template: `
<div class="container">
    <div>{{ctrl.increasableValue}}</div>
</div>`
        }
    });
    
angular.bootstrap(document.getElementById('wrapper'), ['myModule'])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<div id="wrapper">
  <parent-directive>Loading...</parent-directive>
</div>

UPDATE: Or you can simple call $digest function like this

angular.module('myModule', []);

var ParentController = (() => {
    function ParentController($scope) {
      this._increasableValue = 1;

      var interval = setInterval(() => {
        this._increasableValue += 1;
        console.log(this._increasableValue);
        $scope.$digest();
        if (this._increasableValue > 5) {
          clearInterval(interval);
        }
      }, 1000);
    }

    Object.defineProperty(ParentController.prototype, "increasableValue", {
        get: function () { return this._increasableValue; },
        enumerable: true,
        configurable: true
    });
    
    return ParentController;
})()

var ChildController = (() => {
		function ChildController() {}

    Object.defineProperty(ChildController.prototype, "increasableValue", {
        get: function () { return this._increasableValue; },
        set: function (value) { this._increasableValue = value; },
        enumerable: true,
        configurable: true
    });
    
    return ChildController;
})();

angular
    .module('myModule')
    .controller('parentController', ParentController)
    .directive('parentDirective', () => {
        return {
            restrict: 'E',
            scope: {},
            controller: 'parentController',
            controllerAs: 'ctrl',
            template: `
<div class="container">
		<child-directive inc="ctrl.increasableValue"></child-directive>
</div>`
        }
    });

angular
    .module('myModule')
    .controller('childController', ChildController)
    .directive('childDirective', () => {
        return {
            restrict: 'E',
            scope: {
                increasableValue: '=inc'
            },
            bindToController: true,
            controller: 'childController',
            controllerAs: 'ctrl',
            template: `
<div class="container">
    <div>{{ctrl.increasableValue}}</div>
</div>`
        }
    });
    
angular.bootstrap(document.getElementById('wrapper'), ['myModule'])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<div id="wrapper">
  <parent-directive>Loading...</parent-directive>
</div>

Upvotes: 1

Lodin
Lodin

Reputation: 2068

It seems that the dragons were in setInterval approach. Changing it to a button with ng-click attribute solved my problem. Here is updated jsfiddle.

I will be grateful if someone explain the root of the problem.

Upvotes: 1

Related Questions