我正在尝试跨控制器共享数据。用例是一种多步形式,在一个输入中输入的数据稍后用于原始控制器外的多个显示位置。代码如下和jsfiddle here。
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;
});
非常感谢任何帮助。
答案 0 :(得分:468)
一个简单的解决方案是让您的工厂返回一个对象,让您的控制器使用对同一对象的引用:
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/
当应用程序变得更大,更复杂且更难测试时,您可能不希望以这种方式从工厂公开整个对象,而是通过getter和setter提供有限的访问权限:
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>
答案 1 :(得分:69)
我不想使用$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);
}
});
答案 2 :(得分:10)
您可以通过多种方式在控制器之间共享数据
我不会解释为已经由某人解释
使用$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);
});
答案 3 :(得分:6)
我创建了一个控制路径路径模式之间共享范围的工厂,因此您可以在用户在同一路径父路径中导航时维护共享数据。
.controller('CadastroController', ['$scope', 'RouteSharedScope',
function($scope, routeSharedScope) {
var customerScope = routeSharedScope.scopeFor('/Customer');
//var indexScope = routeSharedScope.scopeFor('/');
}
])
因此,如果用户转到另一个路径路径,例如&#39; /支持&#39;,路径&#39; /客户&#39;的共享数据将被自动销毁。但是,如果不是这样,用户就会去找孩子。路径,如&#39; /客户/ 1&#39;或者&#39; /客户/列表&#39;范围不会被摧毁。
您可以在此处查看示例:http://plnkr.co/edit/OL8of9
答案 4 :(得分:3)
有多种方法可以在控制器之间共享数据
我们知道$rootscope
不是数据传输或通信的首选方式,因为它是一个可用于整个应用程序的全局范围
Angular Js控制器之间的数据共享Angular服务是最佳实践,例如。 .factory
,.service
对于reference
如果数据从父控制器传输到子控制器,您可以通过$scope
来直接访问子控制器中的父数据
如果您使用的是ui-router
,那么您可以使用$stateParmas
来传递网址参数,例如id
,name
,key
等
$broadcast
也是在控制器之间传输数据的好方法,从父节点传输到子节点,$emit
传输数据从子控制器传输到父控制器
<强> 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
});
});
请参阅link以了解有关$broadcast
答案 5 :(得分:1)
使用angular.copy时还有另一种不使用$ watch的方法:
sender
答案 6 :(得分:1)
有多种方法可以做到这一点。
活动 - 已经解释清楚。
ui router - 上面解释过。
*
<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();
}
}
});
答案 7 :(得分:1)
我使用了 AngularJS服务。
第一步:我创建了一个名为SharedDataService的AngularJS服务。
myApp.service('SharedDataService', function () {
var Person = {
name: ''
};
return Person;
});
第二步:创建两个控制器并使用上面创建的服务。
//First Controller
myApp.controller("FirstCtrl", ['$scope', 'SharedDataService',
function ($scope, SharedDataService) {
$scope.Person = SharedDataService;
}]);
//Second Controller
myApp.controller("SecondCtrl", ['$scope', 'SharedDataService',
function ($scope, SharedDataService) {
$scope.Person = SharedDataService;
}]);
第3步::只需在视图中使用创建的控制器即可。
<body ng-app="myApp">
<div ng-controller="FirstCtrl">
<input type="text" ng-model="Person.name">
<br>Input is : <strong>{{Person.name}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{Person.name}}
</div>
</body>
要查看此问题的有效解决方案,请按下面的链接
https://codepen.io/wins/pen/bmoYLr
.html文件:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="FirstCtrl">
<input type="text" ng-model="Person.name">
<br>Input is : <strong>{{Person.name}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{Person.name}}
</div>
//Script starts from here
<script>
var myApp = angular.module("myApp",[]);
//create SharedDataService
myApp.service('SharedDataService', function () {
var Person = {
name: ''
};
return Person;
});
//First Controller
myApp.controller("FirstCtrl", ['$scope', 'SharedDataService',
function ($scope, SharedDataService) {
$scope.Person = SharedDataService;
}]);
//Second Controller
myApp.controller("SecondCtrl", ['$scope', 'SharedDataService',
function ($scope, SharedDataService) {
$scope.Person = SharedDataService;
}]);
</script>
</body>
</html>
答案 8 :(得分:0)
不确定我选择这种模式的位置,但是为了跨控制器共享数据并减少$ 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));
获取新数据的Controller,即发布者将执行此类操作。
var someData = yourDataService.getSomeData();
sharedDataEventHub.changeData(someData);
同样使用这个新数据的Controller(称为订阅者)会做这样的事情......
sharedDataEventHub.onChangeData($scope, function(data) {
vm.localData.Property1 = data.Property1;
vm.localData.Property2 = data.Property2;
});
这适用于任何场景。因此,当初始化主控制器并获取数据时,它将调用changeData方法,然后将该方法广播给该数据的所有订户。这减少了控制器之间的耦合。
答案 9 :(得分:0)
如@MaNn在接受的答案的评论之一中指出的那样,如果刷新页面,该解决方案将无法工作。
解决方案是使用localStorage或sessionStorage临时持久化要在控制器之间共享的数据。
答案 10 :(得分:-3)
做到这一点很简单(用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>