在AngularJS控制器之间共享数据

我正在尝试跨控制器共享数据。用例是一种多步骤形式,在一个输入中输入的数据稍后将用于原始控制器之外的多个显示位置。下面和jsfiddle这里中的代码。

超文本标记语言

<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;
});

任何帮助都非常感激。

278935 次浏览

一个简单的解决方案是让你的工厂返回一个对象,让你的控制器使用同一个对象的引用:

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>

演示: http://jsfiddle.net/27mk1n1o/

我倾向于不使用$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);
}
});

我已经创建了一个工厂来控制路由路径模式之间的共享作用域,因此您可以在用户在相同的路由父路径中导航时维护共享数据。

.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

只需简单地执行(在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>

不知道我在哪里得到了这个模式,但对于跨控制器共享数据和减少$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方法,它会把那个广播给那个数据的所有订阅者。这减少了控制器之间的耦合。

还有另一种不用$watch的方法,使用angular.copy:

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;
});

有许多方法可以在控制器之间共享数据

  1. 使用服务
  2. 使用美元的状态。去服务
  3. 使用stateparams
  4. 使用rootscope

各方法说明:

  1. 我不打算解释,因为已经有人解释了

  2. 使用$state.go < p >

      $state.go('book.name', {Name: 'XYZ'});
    
    
    // then get parameter out of URL
    $state.params.Name;
    
  3. $stateparam works in a similar way to $state.go, you pass it as object from sender controller and collect in receiver controller using stateparam

  4. using $rootscope

    (a) sending data from child to parent controller

      $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);
    });
    

有多种方法可以做到这一点。

  1. 事件——已经解释得很好了。

  2. UI路由器-上面解释了。

  3. Service -使用上面显示的更新方法
  4. -观察变化。
  5. 另一种父-子方法,而不是发出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();
}
}
});

有多种方法可以在控制器之间共享数据

  • 角服务
  • $broadcast, $emit方法
  • 父到子控制器通信
  • rootscope美元

正如我们所知,$rootscope不是数据传输或通信的首选方式,因为它是一个全局作用域,可用于整个应用程序

对于Angular Js控制器之间的数据共享,Angular服务是最佳实践。.factory, .service < br > 对于参考 < / p > 如果数据从父控制器传输到子控制器,你可以通过$scope
直接访问子控制器中的父数据 如果你正在使用ui-router,那么你可以使用$stateParmas来传递url参数,如idnamekey

$broadcast也是在控制器之间从父控制器传输数据到子控制器的好方法,而$emit则是将数据从子控制器传输到父控制器的好方法

超文本标记语言

<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的信息

最简单的解决方案:

我使用了AngularJS服务

我已经创建了一个名为SharedDataService的AngularJS服务。

myApp.service('SharedDataService', function () {
var Person = {
name: ''


};
return Person;
});

步骤2:创建两个控制器并使用上面创建的服务。

//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;
}]);

简单地使用视图中创建的控制器。

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

要查看此问题的工作解决方案,请按下面的链接

< a href = " https://codepen。io/wins/pen/bmoYLr" rel="nofollow noreferrer">https://codepen.io/wins/pen/bmoYLr .io/wins/pen/bmoYLr " rel="nofollow noreferrer">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>

正如@MaNn在接受的答案的一个评论中指出的那样,如果页面被刷新,解决方案将无法工作。

解决方案是使用localStorage或sessionStorage来临时持久化希望跨控制器共享的数据。

  1. 您可以创建一个sessionService,它的GET和SET方法加密和解密数据,并从localStorage或sessionStorage读取数据。所以现在你可以直接使用这个服务,通过你想要的任何控制器或服务来读写存储中的数据。这是一种开放而简单的方法
  2. 否则,你创建一个数据共享服务,并在其中使用localStorage——这样,如果页面被刷新,服务将尝试检查存储,并通过你在该服务文件中设置为公共或私有的getter和setter进行回复。