AngularJS - Run function of child controller from parent controller

荒凉一梦 提交于 2019-12-20 07:38:00

问题


I have read many questions on this but still can't find solution that will be clean and reusable enough.

What I tried and don't want to use:

  • Events - $emit and $broadcast,
  • DOM manipulation - for example angular.element('nameOfElement').scope() to access scope of child,
  • $onChange in child component

Simple example

I've build simplified scenario of to present the problem.

On page there is TimerComponent that shows minutes and seconds. It have controller TimerController to change its state: start() and stop(). In example there are two of them, both presenting different values.

Timer template does not contain buttons to manipulate it - that is intentional. I want to start and stop the timer from other controller.

Child-To-Parent communication. I can pass value and function callback onTick() that will be run every second.

Parent-To-Child communication: How could I run start() or stop() functions from parent component?

timer.component.js

(function() {
    'use strict';

    TimerController.$inject = ['$interval']
    function TimerController($interval) {
        var ctrl = this;

        var interval = undefined;

        ctrl.start = start;
        ctrl.stop = stop;
        ctrl.minutes = minutes;
        ctrl.seconds = seconds;           

        function minutes() {
            return Math.floor(ctrl.value / 60);
        }

        function seconds() {
            return (ctrl.value % 60);
        }

        function start() {
            interval = $interval(function() {
                ctrl.value--;
                ctrl.onTick({ 'value': ctrl.value });
            }, 1000);
        }

        function stop() {
            $interval.cancel(interval);
        }
    }

    angular.module('app').component('timer', {
        bindings: {
            value: '<',
            onTick: '&'
        },

        templateUrl: 'timer.html',
        controller: TimerController
    });
})();

timer.html

<span ng-bind="$ctrl.minutes() + ':' + $ctrl.seconds()"></span>

app.html

<body ng-app="app" ng-controller="MainController as vm">
    <p>First timer: </p>
    <timer value="360" on-tick="vm.firstTimerTick(value)"></timer>

    <p>Second timer: </p>
    <timer value="120" on-tick="vm.secondTimerTick(value)"></timer>

    <p>
        <span ng-click="vm.startFirstTimer()">Start first timer</span>
    </p>
</body>

main.controller.js

(function() {
    'use strict';

    angular.module('app').controller('MainController', MainController);

    function MainController() {
        var ctrl = this;
        ctrl.firstTimerTick = firstTimerTick;
        ctrl.secondTimerTick = secondTimerTick;
        ctrl.startFirstTimer = startFirstTimer;

        function firstTimerTick(value) {
            console.log('FirstTimer: ' + value);
        }

        function secondTimerTick(value) {
            console.log('SecondTimer: ' + value);
        }

        function startFirstTimer() {
            /* How to run start() function of TimerController here? */
        }

        function stopFirstTimer() {
            /* How to run start() function of TimerController here? */
        }
    }
})();

回答1:


One approach is to use the new ngRef directive:

<timer ng-ref="vm.timerOne" value="360" on-tick="vm.firstTimerTick(value)">
</timer>

Then use it in the controller:

function startFirstTimer() {
    /* How to run start() function of TimerController here? */
    ctrl.timerOne.start();
}

The ngRef directive was introduced as a new feature with AngularJS V1.7.1.

For more information, see AngularJS ng-ref Directive API Reference.



来源:https://stackoverflow.com/questions/53033367/angularjs-run-function-of-child-controller-from-parent-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!