Передача данных между контроллерами в Angular JS?
У меня есть основной контроллер, который отображает мои продукты,
App.controller('ProductCtrl',function($scope,$productFactory){
$productFactory.get().success(function(data){
$scope.products = data;
});
});
На мой взгляд, я показываю эти продукты в списке
<ul>
<li ng-repeat="product as products">
{{product.name}}
</li>
</ul
То, что я пытаюсь сделать, это когда кто-то нажимает на название продукта, у меня есть другое представление с именем корзина, в которую добавляется этот продукт.
<ul class="cart">
<li>
//click one added here
</li>
<li>
//click two added here
</li>
</ul>
Поэтому я сомневаюсь в том, как передать продукты, на которые нажали, с первого контроллера на второй? я предположил, что корзина должна быть контроллером тоже.
Я обрабатываю событие click, используя директиву. Также я чувствую, что должен использовать сервис для достижения вышеуказанной функциональности, просто не могу понять, как? потому что в корзине будет предопределенное количество добавленных товаров, может быть 5/10 в зависимости от того, на какой странице находится пользователь. Так что я хотел бы сохранить это общее.
Обновить:
Я создал сервис для трансляции и во втором контроллере я его получаю. Теперь вопрос, как я могу обновить дом? Поскольку мой список для отбрасывания продукта довольно жестко закодирован.
18 ответов
Из описания кажется, что вы должны использовать сервис. Посмотрите http://egghead.io/lessons/angularjs-sharing-data-between-controllers и AngularJS Service, передающий данные между контроллерами, чтобы увидеть некоторые примеры.
Вы можете определить свой продукт службы как таковой:
app.service('productService', function() {
var productList = [];
var addProduct = function(newObj) {
productList.push(newObj);
};
var getProducts = function(){
return productList;
};
return {
addProduct: addProduct,
getProducts: getProducts
};
});
Зависимость внедряет сервис в оба контроллера.
В вашем ProductController
Определите действие, которое добавляет выбранный объект в массив:
app.controller('ProductController', function($scope, productService) {
$scope.callToAddToProductList = function(currObj){
productService.addProduct(currObj);
};
});
В вашем CartController
, получить продукцию из сервиса:
app.controller('CartController', function($scope, productService) {
$scope.products = productService.getProducts();
});
как передать этот клик продукт с первого контроллера на второй?
При нажатии вы можете вызвать метод, который вызывает трансляцию:
$rootScope.$broadcast('SOME_TAG', 'your value');
и второй контроллер будет слушать этот тег как:
$scope.$on('SOME_TAG', function(response) {
// ....
})
Так как мы не можем внедрить $scope в сервисы, нет ничего лучше, чем singleton $scope.
Но мы можем ввести $rootScope
, Поэтому, если вы сохраняете ценность в Сервисе, вы можете запустить $rootScope.$broadcast('SOME_TAG', 'your value');
в сервисном органе. (См. @Charx описание услуг)
app.service('productService', function($rootScope) {/*....*/}
Пожалуйста, проверьте хорошую статью о трансляции $, $ emit
Решение без создания Сервиса с использованием $rootScope:
Для совместного использования свойств через контроллеры приложения вы можете использовать Angular $rootScope. Это еще один вариант обмена данными, чтобы люди знали об этом.
Предпочтительный способ обмена некоторыми функциями между контроллерами - это службы, для чтения или изменения глобального свойства вы можете использовать $ rootcope.
var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = true;
}]);
app.controller('Ctrl2', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = false;
}]);
Использование $ rootScope в шаблоне (доступ к свойствам с помощью $root):
<div ng-controller="Ctrl1">
<div class="banner" ng-show="$root.showBanner"> </div>
</div>
Вы можете сделать это двумя способами.
Используя
$rootscope
, но я не рекомендую это.$rootScope
это самая верхняя область. Приложение может иметь только один$rootScope
который будет использоваться всеми компонентами приложения. Следовательно, он действует как глобальная переменная.Использование услуг. Вы можете сделать это, разделив сервис между двумя контроллерами. Код для сервиса может выглядеть так:
app.service('shareDataService', function() { var myList = []; var addList = function(newObj) { myList.push(newObj); } var getList = function(){ return myList; } return { addList: addList, getList: getList }; });
Вы можете увидеть мою скрипку здесь.
Еще более простой способ обмена данными между контроллерами - использование вложенных структур данных. Вместо, например
$scope.customer = {};
мы можем использовать
$scope.data = { customer: {} };
data
свойство будет унаследовано от родительской области видимости, чтобы мы могли перезаписывать его поля, сохраняя доступ от других контроллеров.
angular.module('testAppControllers', [])
.controller('ctrlOne', function ($scope) {
$scope.$broadcast('test');
})
.controller('ctrlTwo', function ($scope) {
$scope.$on('test', function() {
});
});
Я видел ответы здесь, и он отвечает на вопрос об обмене данными между контроллерами, но что мне делать, если я хочу, чтобы один контроллер уведомил другой о том, что данные были изменены (без использования широковещательной передачи)? ЛЕГКО! Просто используя известный шаблон посетителей:
myApp.service('myService', function() {
var visitors = [];
var registerVisitor = function (visitor) {
visitors.push(visitor);
}
var notifyAll = function() {
for (var index = 0; index < visitors.length; ++index)
visitors[index].visit();
}
var myData = ["some", "list", "of", "data"];
var setData = function (newData) {
myData = newData;
notifyAll();
}
var getData = function () {
return myData;
}
return {
registerVisitor: registerVisitor,
setData: setData,
getData: getData
};
}
myApp.controller('firstController', ['$scope', 'myService',
function firstController($scope, myService) {
var setData = function (data) {
myService.setData(data);
}
}
]);
myApp.controller('secondController', ['$scope', 'myService',
function secondController($scope, myService) {
myService.registerVisitor(this);
this.visit = function () {
$scope.data = myService.getData();
}
$scope.data = myService.getData();
}
]);
Таким простым способом один контроллер может обновить другой контроллер, если некоторые данные были обновлены.
Мы можем хранить данные в сеансе и использовать их в любом месте нашей программы.
$window.sessionStorage.setItem("Mydata",data);
Другое место
$scope.data = $window.sessionStorage.getItem("Mydata");
1
using $localStorage
app.controller('ProductController', function($scope, $localStorage) {
$scope.setSelectedProduct = function(selectedObj){
$localStorage.selectedObj= selectedObj;
};
});
app.controller('CartController', function($scope,$localStorage) {
$scope.selectedProducts = $localStorage.selectedObj;
$localStorage.$reset();//to remove
});
2
При нажатии вы можете вызвать метод, который вызывает трансляцию:
$rootScope.$broadcast('SOME_TAG', 'your value');
and the second controller will listen on this tag like:
$scope.$on('SOME_TAG', function(response) {
// ....
})
3
using $rootScope:
4
window.sessionStorage.setItem("Mydata",data);
$scope.data = $window.sessionStorage.getItem("Mydata");
5
Один из способов использования углового сервиса:
var app = angular.module("home", []);
app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});
app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});
app.factory('ser1', function(){
return {o: ''};
});
Я не знаю, поможет ли это кому-нибудь, но, основываясь на ответе Charx (спасибо!), Я создал простой сервис кеширования. Не стесняйтесь использовать, делать ремиксы и делиться:
angular.service('cache', function() {
var _cache, _store, _get, _set, _clear;
_cache = {};
_store = function(data) {
angular.merge(_cache, data);
};
_set = function(data) {
_cache = angular.extend({}, data);
};
_get = function(key) {
if(key == null) {
return _cache;
} else {
return _cache[key];
}
};
_clear = function() {
_cache = {};
};
return {
get: _get,
set: _set,
store: _store,
clear: _clear
};
});
Я создал фабрику, которая контролирует общую область между шаблоном пути маршрута, поэтому вы можете поддерживать общие данные только тогда, когда пользователи перемещаются по одному и тому же родительскому пути маршрута.
.controller('CadastroController', ['$scope', 'RouteSharedScope',
function($scope, routeSharedScope) {
var customerScope = routeSharedScope.scopeFor('/Customer');
//var indexScope = routeSharedScope.scopeFor('/');
}
])
Таким образом, если пользователь идет по другому пути маршрута, например, "/ Поддержка", общие данные для пути "/ Клиент" будут автоматически уничтожены. Но если вместо этого пользователь перейдет к "дочерним" путям, таким как "/Customer/1" или "/Customer/list", область действия не будет уничтожена.
Вы можете увидеть образец здесь: http://plnkr.co/edit/OL8of9
Создайте фабрику в вашем модуле и добавьте ссылку на фабрику в контроллере и используйте ее переменные в контроллере, а теперь получите значение данных в другом контроллере, добавив ссылку туда, где вы хотите
Один из способов использования углового сервиса:
var app = angular.module("home", []);
app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});
app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});
app.factory('ser1', function(){
return {o: ''};
});
<div ng-app='home'>
<div ng-controller='one'>
Type in text:
<input type='text' ng-model="inputText.o"/>
</div>
<br />
<div ng-controller='two'>
Type in text:
<input type='text' ng-model="inputTextTwo.o"/>
</div>
</div>
Чтобы улучшить решение, предложенное @Maxim с использованием $broadcast, отправляйте данные без изменений
$rootScope.$broadcast('SOME_TAG', 'my variable');
но для прослушивания данных
$scope.$on('SOME_TAG', function(event, args) {
console.log("My variable is", args);// args is value of your variable
})
Есть три способа сделать это,
а) используя сервис
б) Использование зависимых родительских / дочерних отношений между областями контроллера.
в) В Angular 2.0 ключевое слово "как" будет передавать данные с одного контроллера на другой.
Для получения дополнительной информации с примером, пожалуйста, проверьте ссылку ниже:
К сведению, объект $scope имеет $emit, $broadcast, $on И объект $rootScope имеет идентичный $emit, $broadcast, $on
Подробнее о шаблоне публикации / подписки на английском языке здесь
var custApp = angular.module("custApp", [])
.controller('FirstController', FirstController)
.controller('SecondController',SecondController)
.service('sharedData', SharedData);
FirstController.$inject = ['sharedData'];
function FirstController(sharedData) {
this.data = sharedData.data;
}
SecondController.$inject['sharedData'];
function SecondController(sharedData) {
this.data = sharedData.data;
}
function SharedData() {
this.data = {
value: 'default Value'
}
}
Первый контроллер
<div ng-controller="FirstController as vm">
<input type=text ng-model="vm.data.value" />
</div>
Второй контроллер
<div ng-controller="SecondController as vm">
Second Controller<br>
{{vm.data.value}}
</div>
Я думаю
лучший способ
это использовать $localStorage. (Работает все время)app.controller('ProductController', function($scope, $localStorage) {
$scope.setSelectedProduct = function(selectedObj){
$localStorage.selectedObj= selectedObj;
};
});
Ваша карта будет
app.controller('CartController', function($scope,$localStorage) {
$scope.selectedProducts = $localStorage.selectedObj;
$localStorage.$reset();//to remove
});
Вы также можете добавить
if($localStorage.selectedObj){
$scope.selectedProducts = $localStorage.selectedObj;
}else{
//redirect to select product using $location.url('/select-product')
}