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

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

  1. Используя $rootscope, но я не рекомендую это. $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");

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>

https://jsfiddle.net/1w64222q/

Чтобы улучшить решение, предложенное @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 ключевое слово "как" будет передавать данные с одного контроллера на другой.

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

http://www.tutespace.com/2016/03/angular-js.html

К сведению, объект $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')
}
Другие вопросы по тегам