问题
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