Я прочитал много вопросов по этому поводу, но все еще не могу найти решение, которое было бы достаточно чистым и пригодным для повторного использования.
Что пробовал и не хочу использовать:
Простой пример
Я построил упрощенный сценарий, чтобы представить проблему.
На странице есть TimerComponent, который показывает минуты и секунды. У него есть контроллер TimerController для изменения своего состояния: start() и stop(). В примере есть два из них, оба представляют разные значения.
В шаблоне таймера нет кнопок для управления им - это намеренно. Я хочу запускать и останавливать таймер с другого контроллера.
Общение между родителями и детьми. Я могу передать value и функцию обратного вызова onTick(), которая будет запускаться каждую секунду.
Общение между родителями и детьми: Как мне запустить функции start () или stop () из родительского компонента?
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.info('FirstTimer: ' + value);
}
function secondTimerTick(value) {
console.info('SecondTimer: ' + value);
}
function startFirstTimer() {
/* How to run start() function of TimerController here? */
}
function stopFirstTimer() {
/* How to run start() function of TimerController here? */
}
}
})();


Один из подходов - использовать новый директива ngRef:
<timer ng-ref = "vm.timerOne" value = "360" on-tick = "vm.firstTimerTick(value)">
</timer>
Затем используйте его в контроллере:
function startFirstTimer() {
/* How to run start() function of TimerController here? */
ctrl.timerOne.start();
}
директива ngRef был представлен как новая функция с AngularJS V1.7.1.
Для получения дополнительной информации см. Справочник по API директивы AngularJS ng-ref.