Передача данных между контроллерами в 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>

Итак, мое сомнение вот в чем, как передать эти щелкнутые продукты с первого контроллера на второй? я предположил, что cart тоже должен быть контроллером.

Я обрабатывать событие click директива using. Также я чувствую, что должен использовать сервис для достижения вышеуказанной функциональности, просто не могу понять, как? потому что корзина будет предопределенное количество добавленных продуктов может быть 5/10 в зависимости от того, какой пользователь страницы. Поэтому я хотел бы сохранить это общее.

обновление:

Я создал службу для трансляции, и во втором контроллере я ее получаю. Теперь вопрос в том, как обновить dom? Поскольку мой список для удаления продукта довольно жестко закодирован.

18 ответов


из описания кажется, что вы должны использовать службу. Проверьтеhttp://egghead.io/lessons/angularjs-sharing-data-between-controllers и Служба AngularJS Передает Данные Между Контроллерами чтобы увидеть некоторые примеры.

вы можете определить ваш продукт как таковой:

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 в службы, нет ничего похожего на одноэлементную $scope.

но мы можем впрыснуть $rootScope. Поэтому, если вы сохраняете значение в Службе, вы можете запустить $rootScope.$broadcast('SOME_TAG', 'your value'); в Сервисный орган. (См. Описание @Charx об услугах)

app.service('productService',  function($rootScope) {/*....*/}

пожалуйста, проверьте хорошую статью о $ broadcast, $emit


решение без создания сервиса, используя $rootScope:

для обмена свойствами между контроллерами приложений вы можете использовать Angular $rootScope. Это еще один вариант обмена данными, поставив его так, чтобы люди знали об этом.

предпочтительным способом обмена некоторыми функциями между контроллерами являются службы, для чтения или изменения глобального свойства вы можете использовать $rootscope.

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>

вы можете сделать это двумя способами.

  1. С помощью $rootscope, но я не рекомендую это. The $rootScope самый верхний объем. Приложение может иметь только один $rootScope что будет общий доступ ко всем компонентам приложения. Следовательно, он действует как глобальная переменная.

  2. использование услуг. Вы можете сделать это путем обмена между двумя контроллерами. Код для обслуживания может выглядеть так:

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

Я создал фабрику, которая управляет общей областью между шаблоном пути маршрута, поэтому вы можете поддерживать общие данные только тогда, когда пользователи переходят по тому же родительскому пути маршрута.

.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


сделайте фабрику в вашем модуле и добавьте ссылку фабрики в контроллере и используйте ее переменные в контроллере, а теперь получите значение данных в другом контроллере, добавив ссылку, где бы вы ни хотели


Я не знаю, поможет ли это кому-нибудь, но на основе 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
    };
});

один из способов использования углового сервиса:

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>

https://jsfiddle.net/1w64222q/


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

при нажатии вы можете вызвать метод, который вызывает broadcast:

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

к вашему сведению Объект $ scope имеет $emit, $broadcast, $on И Объект $rootScope имеет идентичные $emit, $broadcast, $on

подробнее о шаблоне публикации / подписки в angular здесь


существует три способа сделать это,

a) использование сервиса

b) использование зависимого родительского/дочернего отношения между областями контроллера.

c) в Angular 2.0 ключевое слово "As" будет передавать данные от одного контроллера к другому.

для получения дополнительной информации с примером, пожалуйста, проверьте ссылку ниже:

http://www.learnit.net.in/2016/03/angular-js.html


чтобы улучшить решение, предложенное @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
})

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

ваш cardController будет

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