Обмен данными между контроллерами AngularJS
Я пытаюсь обмениваться данными между контроллерами. Use-case-это многоступенчатая форма, данные, введенные на одном входе, позже используются в нескольких местах отображения вне исходного контроллера. Код ниже, и в jsfiddle здесь.
HTML
<div ng-controller="FirstCtrl">
<input type="text" ng-model="FirstName"><!-- Input entered here -->
<br>Input is : <strong>{{FirstName}}</strong><!-- Successfully updates here -->
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{FirstName}}<!-- How do I automatically updated it here? -->
</div>
JS
// declare the app with no dependencies
var myApp = angular.module('myApp', []);
// make a factory to share data between controllers
myApp.factory('Data', function(){
// I know this doesn't work, but what will?
var FirstName = '';
return FirstName;
});
// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){
});
// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.FirstName = Data.FirstName;
});
любая помощь очень ценится.
9 ответов:
простое решение состоит в том, чтобы ваша фабрика возвращала объект и позволяла вашим контроллерам работать со ссылкой на тот же объект:
JS:
// declare the app with no dependencies var myApp = angular.module('myApp', []); // Create the factory that share the Fact myApp.factory('Fact', function(){ return { Field: '' }; }); // Two controllers sharing an object that has a string in it myApp.controller('FirstCtrl', function( $scope, Fact ){ $scope.Alpha = Fact; }); myApp.controller('SecondCtrl', function( $scope, Fact ){ $scope.Beta = Fact; });HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="Alpha.Field"> First {{Alpha.Field}} </div> <div ng-controller="SecondCtrl"> <input type="text" ng-model="Beta.Field"> Second {{Beta.Field}} </div>демо:http://jsfiddle.net/HEdJF/
когда приложения становятся больше, сложнее и сложнее тестировать, вы можете не захотеть выставлять весь объект с завода таким образом, но вместо этого предоставить ограниченный доступ, например, через геттеры и сеттеры:
myApp.factory('Data', function () { var data = { FirstName: '' }; return { getFirstName: function () { return data.FirstName; }, setFirstName: function (firstName) { data.FirstName = firstName; } }; });при таком подходе это до потребляющих контроллеров, чтобы обновить фабрику с новыми значениями, и следить за изменениями, чтобы получить их:
myApp.controller('FirstCtrl', function ($scope, Data) { $scope.firstName = ''; $scope.$watch('firstName', function (newValue, oldValue) { if (newValue !== oldValue) Data.setFirstName(newValue); }); }); myApp.controller('SecondCtrl', function ($scope, Data) { $scope.$watch(function () { return Data.getFirstName(); }, function (newValue, oldValue) { if (newValue !== oldValue) $scope.firstName = newValue; }); });HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="firstName"> <br>Input is : <strong>{{firstName}}</strong> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{firstName}} </div>
Я предпочитаю не использовать
$watchдля этого. Вместо назначения всей службы области контроллера можно назначить только данные.JS:
var myApp = angular.module('myApp', []); myApp.factory('MyService', function(){ return { data: { firstName: '', lastName: '' } // Other methods or objects can go here }; }); myApp.controller('FirstCtrl', function($scope, MyService){ $scope.data = MyService.data; }); myApp.controller('SecondCtrl', function($scope, MyService){ $scope.data = MyService.data; });HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="data.firstName"> <br>Input is : <strong>{{data.firstName}}</strong> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{data.firstName}} </div>кроме того, вы можете обновить данные службы с помощью прямого метода.
JS:
// A new factory with an update method myApp.factory('MyService', function(){ return { data: { firstName: '', lastName: '' }, update: function(first, last) { // Improve this method as needed this.data.firstName = first; this.data.lastName = last; } }; }); // Your controller can use the service's update method myApp.controller('SecondCtrl', function($scope, MyService){ $scope.data = MyService.data; $scope.updateData = function(first, last) { MyService.update(first, last); } });
существует множество способов обмена данными между контроллерами
- С помощью услуги
- С помощью $state.перейти услуги
- используя stateparams
- С помощью rootscope
объяснение каждого метода:
Я не собираюсь объяснять, как его уже объяснял кто-то
используя
$state.go$state.go('book.name', {Name: 'XYZ'}); // then get parameter out of URL $state.params.Name;
$stateparamработает в подобный способ$state.go, вы передаете его как объект от контроллера отправителя и собирать в контроллере приемника с помощью stateparamиспользуя
$rootscope(a) отправка данных от дочернего к родительскому контроллеру
$scope.Save(Obj,function(data) { $scope.$emit('savedata',data); //pass the data as the second parameter }); $scope.$on('savedata',function(event,data) { //receive the data as second parameter });(b) отправка данных от родителя к дочернему контроллеру
$scope.SaveDB(Obj,function(data){ $scope.$broadcast('savedata',data); }); $scope.SaveDB(Obj,function(data){`enter code here` $rootScope.$broadcast('saveCallback',data); });
Я создал фабрику, которая управляет общей областью между шаблоном пути маршрута, поэтому вы можете поддерживать общие данные только тогда, когда пользователи перемещаются по одному и тому же родительскому пути маршрута.
.controller('CadastroController', ['$scope', 'RouteSharedScope', function($scope, routeSharedScope) { var customerScope = routeSharedScope.scopeFor('/Customer'); //var indexScope = routeSharedScope.scopeFor('/'); } ])таким образом, если пользователь переходит на другой путь маршрута, например '/Support', общие данные для пути '/Customer' будут автоматически уничтожены. Но, если вместо этого пользователь переходит к "дочерним" путям, например "/Customer/1 " или "/ Customer/list", область действия не будет разрушенный.
вы можете увидеть пример здесь:http://plnkr.co/edit/OL8of9
Существует несколько способов обмена данными между контроллерами
- Угловое услуг
- $ broadcast, $emit method
- связь между родительским и дочерним контроллерами
- $rootscope
как известно
$rootscopeне является предпочтительным способом для передачи данных или связи, потому что это глобальная сфера, которая доступна для всего приложениядля обмена данными между угловыми контроллерами Js Угловые услуги-это лучшие практики, например.
.factory,.service
Ибо ссылкав случае передачи данных от родительского к дочернему контроллеру вы можете напрямую получить доступ к родительским данным в дочернем контроллере через
$scope
Если вы используетеui-routerзатем вы можете использовать$stateParmasдля передачи параметров url, таких какid,name,key, etc
$broadcastтоже хороший способ передачи данных между контроллерами от родителя к ребенку и$emitto передача данных от дочерних контроллеров к родительскимHTML
<div ng-controller="FirstCtrl"> <input type="text" ng-model="FirstName"> <br>Input is : <strong>{{FirstName}}</strong> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{FirstName}} </div>JS
myApp.controller('FirstCtrl', function( $rootScope, Data ){ $rootScope.$broadcast('myData', {'FirstName': 'Peter'}) }); myApp.controller('SecondCtrl', function( $rootScope, Data ){ $rootScope.$on('myData', function(event, data) { $scope.FirstName = data; console.log(data); // Check in console how data is coming }); });см. Учитывая ссылке чтобы узнать больше о
$broadcast
есть еще один способ без использования $watch, используя angular.копия:
var myApp = angular.module('myApp', []); myApp.factory('Data', function(){ var service = { FirstName: '', setFirstName: function(name) { // this is the trick to sync the data // so no need for a $watch function // call this from anywhere when you need to update FirstName angular.copy(name, service.FirstName); } }; return service; }); // Step 1 Controller myApp.controller('FirstCtrl', function( $scope, Data ){ }); // Step 2 Controller myApp.controller('SecondCtrl', function( $scope, Data ){ $scope.FirstName = Data.FirstName; });
есть несколько способов сделать это.
события-уже хорошо объяснены.
ui router-объяснено выше.
- сервис - с методом обновления отображается выше
- плохо - наблюдая за изменениями.
- другой Родительский дочерний подход, а не выделяет и brodcast -
*
<superhero flight speed strength> Superman is here! </superhero> <superhero speed> Flash is here! </superhero>*
app.directive('superhero', function(){ return { restrict: 'E', scope:{}, // IMPORTANT - to make the scope isolated else we will pollute it in case of a multiple components. controller: function($scope){ $scope.abilities = []; this.addStrength = function(){ $scope.abilities.push("strength"); } this.addSpeed = function(){ $scope.abilities.push("speed"); } this.addFlight = function(){ $scope.abilities.push("flight"); } }, link: function(scope, element, attrs){ element.addClass('button'); element.on('mouseenter', function(){ console.log(scope.abilities); }) } } }); app.directive('strength', function(){ return{ require:'superhero', link: function(scope, element, attrs, superHeroCtrl){ superHeroCtrl.addStrength(); } } }); app.directive('speed', function(){ return{ require:'superhero', link: function(scope, element, attrs, superHeroCtrl){ superHeroCtrl.addSpeed(); } } }); app.directive('flight', function(){ return{ require:'superhero', link: function(scope, element, attrs, superHeroCtrl){ superHeroCtrl.addFlight(); } } });
не уверен, где я взял этот шаблон, но для обмена данными между контроллерами и уменьшения $rootScope и $scope это отлично работает. Это напоминает репликацию данных, где у вас есть издатели и подписчики. Надеюсь, это поможет.
Сервис:
(function(app) { "use strict"; app.factory("sharedDataEventHub", sharedDataEventHub); sharedDataEventHub.$inject = ["$rootScope"]; function sharedDataEventHub($rootScope) { var DATA_CHANGE = "DATA_CHANGE_EVENT"; var service = { changeData: changeData, onChangeData: onChangeData }; return service; function changeData(obj) { $rootScope.$broadcast(DATA_CHANGE, obj); } function onChangeData($scope, handler) { $scope.$on(DATA_CHANGE, function(event, obj) { handler(obj); }); } } }(app));контроллер, который получает новые данные, который является издателем будет делать что-то вроде этого..
var someData = yourDataService.getSomeData(); sharedDataEventHub.changeData(someData);контроллер, который также использует эти новые данные, который называется Абонент будет делать что-то вроде этого...
sharedDataEventHub.onChangeData($scope, function(data) { vm.localData.Property1 = data.Property1; vm.localData.Property2 = data.Property2; });Это будет работать для любого сценария. Поэтому, когда первичный контроллер инициализируется и получает данные, он вызывает метод changeData, который затем транслирует это всем подписчикам этих данных. Это уменьшает соединение наших регуляторов к Одину другого.
просто сделайте это просто (проверено с v1.3. 15):
<article ng-controller="ctrl1 as c1"> <label>Change name here:</label> <input ng-model="c1.sData.name" /> <h1>Control 1: {{c1.sData.name}}, {{c1.sData.age}}</h1> </article> <article ng-controller="ctrl2 as c2"> <label>Change age here:</label> <input ng-model="c2.sData.age" /> <h1>Control 2: {{c2.sData.name}}, {{c2.sData.age}}</h1> </article> <script> var app = angular.module("MyApp", []); var dummy = {name: "Joe", age: 25}; app.controller("ctrl1", function () { this.sData = dummy; }); app.controller("ctrl2", function () { this.sData = dummy; }); </script>
Comments