javascript - funcion - pasar parametros entre controladores angular 2
Compartir datos entre los controladores AngularJS (10)
Estoy tratando de compartir datos entre los controladores. El caso de uso es un formulario de varios pasos, los datos ingresados en una entrada se usan más tarde en múltiples ubicaciones de visualización fuera del controlador original. Código abajo y en jsfiddle aquí .
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;
});
Cualquier ayuda es muy apreciada.
La solución más simple:
He utilizado un servicio AngularJS .
Paso 1: He creado un servicio AngularJS llamado SharedDataService.
myApp.service(''SharedDataService'', function () {
var Person = {
name: ''''
};
return Person;
});
Paso 2: crea dos controladores y utiliza el servicio creado anteriormente.
//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;
}]);
Paso 3: Simplemente use los controladores creados en la vista.
<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>
Para ver la solución de trabajo a este problema, presione el siguiente enlace
https://codepen.io/wins/pen/bmoYLr
archivo .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>
Existen múltiples formas de compartir datos entre los controladores.
- Servicios angulares
- $ broadcast, $ emitir método
- Comunicación padre a hijo controlador
- $ rootscope
Como sabemos, $rootscope
no es una forma preferible para la transferencia de datos o la comunicación, ya que es un ámbito global que está disponible para toda la aplicación.
Para compartir datos entre los controladores Angular Js, los servicios angulares son las mejores prácticas, por ejemplo .factory
, .service
Para reference
En caso de transferencia de datos del controlador principal al secundario, puede acceder directamente a los datos principales del controlador secundario a través de $scope
Si está utilizando ui-router
, puede usar $stateParmas
para pasar parámetros de URL como id
, name
, key
, etc.
$broadcast
también es una buena forma de transferir datos entre controladores de padres a hijos y $emit
para transferir datos de niños a controladores principales
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
});
});
Consulte el link dado para saber más sobre $broadcast
Hay muchas maneras de compartir los datos entre los controladores.
- usando servicios
- utilizando los servicios de $ state.go
- usando parques estatales
- usando rootscope
Explicación de cada método:
No voy a explicar como ya lo explicó alguien.
usando
$state.go
$state.go(''book.name'', {Name: ''XYZ''}); // then get parameter out of URL $state.params.Name;
$stateparam
funciona de manera similar a$state.go
, usted lo pasa como un objeto desde el controlador del remitente y lo recoge en el controlador del receptor utilizando stateparamusando
$rootscope
(a) envío de datos del niño al controlador principal
$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) envío de datos de padre a controlador hijo
$scope.SaveDB(Obj,function(data){ $scope.$broadcast(''savedata'',data); }); $scope.SaveDB(Obj,function(data){`enter code here` $rootScope.$broadcast(''saveCallback'',data); });
Hay otra forma sin usar $ watch, usando 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;
});
Hay varias formas de hacer esto.
Eventos - ya explicados bien.
enrutador ui - explicado anteriormente.
- Servicio - con el método de actualización mostrado arriba
- MALO - Observando cambios.
- Otro enfoque padre-hijo en lugar de emitir y 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();
}
}
});
He creado una fábrica que controla el alcance compartido entre el patrón de la ruta de acceso, por lo que puede mantener los datos compartidos justo cuando los usuarios navegan en la ruta principal de la misma ruta.
.controller(''CadastroController'', [''$scope'', ''RouteSharedScope'',
function($scope, routeSharedScope) {
var customerScope = routeSharedScope.scopeFor(''/Customer'');
//var indexScope = routeSharedScope.scopeFor(''/'');
}
])
Por lo tanto, si el usuario va a otra ruta, por ejemplo ''/ Soporte'', los datos compartidos para la ruta ''/ Cliente'' se destruirán automáticamente. Pero, si en lugar de esto, el usuario va a las rutas ''secundarias'', como ''/ Customer / 1'' o ''/ Customer / list'', el alcance no se destruirá.
Puede ver un ejemplo aquí: http://plnkr.co/edit/OL8of9
No estoy seguro de dónde recogí este patrón, pero para compartir datos entre los controladores y reducir $ rootScope y $ scope esto funciona muy bien. Es una reminiscencia de una replicación de datos donde tienes editores y suscriptores. Espero eso ayude.
El servicio:
(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));
El controlador que está obteniendo los nuevos datos, que es el editor, haría algo como esto ...
var someData = yourDataService.getSomeData();
sharedDataEventHub.changeData(someData);
El Controlador que también utiliza estos nuevos datos, que se llama el Suscriptor, haría algo como esto ...
sharedDataEventHub.onChangeData($scope, function(data) {
vm.localData.Property1 = data.Property1;
vm.localData.Property2 = data.Property2;
});
Esto funcionará para cualquier escenario. Entonces, cuando el controlador primario se inicializa y obtiene datos, llamará al método changeData que luego lo difundirá a todos los suscriptores de esos datos. Esto reduce el acoplamiento de nuestros controladores entre sí.
Prefiero no usar $watch
para esto. En lugar de asignar todo el servicio al alcance de un controlador, puede asignar solo los datos.
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>
Alternativamente, puede actualizar los datos del servicio con un método directo.
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);
}
});
Solo hazlo simple (probado con 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>
Una solución simple es que su fábrica devuelva un objeto y permita que sus controladores trabajen con una referencia al mismo objeto:
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>
Demostración: http://jsfiddle.net/HEdJF/
Cuando las aplicaciones se vuelven más grandes, más complejas y más difíciles de probar, es posible que no desee exponer todo el objeto de la fábrica de esta manera, sino que se le otorgue acceso limitado, por ejemplo, a través de captadores y configuradores:
myApp.factory(''Data'', function () {
var data = {
FirstName: ''''
};
return {
getFirstName: function () {
return data.FirstName;
},
setFirstName: function (firstName) {
data.FirstName = firstName;
}
};
});
Con este enfoque, depende de los controladores consumidores actualizar la fábrica con nuevos valores y observar los cambios para obtenerlos:
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>
Demostración: http://jsfiddle.net/27mk1n1o/