Общие переменные и несколько контроллеров AngularJS

У меня есть несколько контроллеров в небольшом приложении, которое я пишу, и я успешно поделился «выбранной» переменной между контроллерами.

app.service('selectedEmployee', function () {
    var selected = null;

    return 
    { 
        getSelected: function() {
            return selected;
        },
        postSelected: function(employee) {
            selected = employee;
        }
    };

});

У меня есть боковая панель навигации со списком сотрудников. Когда я нажимаю на сотрудника, я вызываю функцию postSelected, а затем getSelected для установки $scope.selected.

$scope.selectEmployee = function(employee) {

   //Calling Service function postSelected
    selectedEmployee.postSelected(employee);

    $scope.selected = selectedEmployee.getSelected();

    if ($mdSidenav('left').isOpen()) {
        $mdSidenav('left').close();
    }

}

У меня есть третий контроллер для области основного контента, и здесь я не понимаю, что делать. Я хочу, чтобы информация от выбранного сотрудника отображалась, но angular компилирует всю страницу до того, как первый сотрудник сможет быть установлен как выбранный, а последующие выборы сотрудника не перезагружают страницу основного контента (потому что я не т сказал им, я думаю). Вот мой основной контроллер контента:

app.controller('mainContentController', ['$scope','selectedEmployee',
    function ($scope, selectedEmployee) {
        $scope.selected = selectedEmployee.getSelected();
        console.log($scope.selected);
    }
]);

Мое основное представление контента сейчас очень простое

<h2>{{selected.firstName}}{{selected.lastName}}</h2>

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

репозиторий GitLab


person ajthyng    schedule 07.05.2016    source источник
comment
Ваш вопрос трудно понять. но не беспокойтесь, это может быть моя ошибка или это тип вопроса, который трудно понять. Было бы намного лучше, если бы вы могли отправить весь свой код на простой plunker.... plnkr.co/edit .. И поделитесь с нами своим планком!   -  person amanuel2    schedule 07.05.2016
comment
Я буду работать над этим прямо сейчас, хорошее предложение.   -  person ajthyng    schedule 07.05.2016
comment
Было не так просто, как я думал, преобразовать эту проблему в пригодный для использования плункер. Я добавил ссылку на gitlab для своего репозитория выше.   -  person ajthyng    schedule 07.05.2016
comment
Очень быстрое предложение: попробуйте бросить $scope.$applyAsync(...) вокруг тела вашей функции в mainContentController. Возможно, если ему нужен только один цикл дайджеста для достижения контроллера, это должно решить проблему.   -  person sg.cc    schedule 07.05.2016
comment
@UnicornMaster Если вы не знали, что есть онлайн-среда IDE (которую я считаю лучшей) под названием Cloud9IDE... В настоящее время я клонировал ее туда. мы могли бы обсудить это там и решить это также. Ссылка: ide.c9.io/amanuel2/gitclone. Оказавшись там, откройте вкладку Collab.   -  person amanuel2    schedule 07.05.2016


Ответы (3)


Не полагайтесь на беспорядочные трансляции, если ваша цель — просто отобразить и изменить данные в шаблоне контроллера.

Вашим контроллерам НЕ нужно «знать», когда сервис или фабрика обновились, чтобы использовать их в шаблоне, поскольку Angular сделает это за вас, поскольку вы получаете доступ к данным через точечную нотацию. Это важная концепция, о которой вы должны узнать больше.

Этот Fiddle показывает оба способа доступа к данным и то, как использование объекта-контейнера в шаблоне заставляет Angular повторно проверять один и тот же фактический объект при изменениях — вместо примитивного строкового значения, хранящегося в контроллере:

http://jsfiddle.net/a01f39Lw/2/

Шаблон:

<div ng-controller="Ctrl1 as c1">
    <input ng-model="c1.Bands.favorite" placeholder="Favorite band?">
</div>
<div ng-controller="Ctrl2 as c2">
    <input ng-model="c2.Bands.favorite" placeholder="Favorite band?">
</div>

JS:

var app = angular.module("app", []);      

app.factory('Bands', function($http) {
    return {
        favorite: ''
    };    
});

app.controller('Ctrl1', function Ctrl1(Bands){
    this.Bands = Bands;
});
app.controller('Ctrl2', function Ctrl2(Bands){
    this.Bands = Bands;
});
person William B    schedule 08.05.2016
comment
Есть ли в этой ситуации преимущество использования фабрики над сервисом? Насколько я понимаю, основное отличие состоит в том, что службы являются конструкторами, а фабрики возвращают литералы объектов. Я не знаю намного больше, чем это. - person ajthyng; 09.05.2016
comment
Этот пост может ответить на эту тему больше, чем я: stackoverflow.com/a/26924234/5046541 - person William B; 09.05.2016

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

Надлежащая практика

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

app.service('selectedEmployee', [selectedEmployeeService])

    function selectedEmployeeService(){
      this.selected = null;
      this.getSelected = function(){
        return this.selected;
      }
      this.postSelected = function(emp){
        this.selected = emp;
      }
    }

Вы видите, что я поместил функцию отдельно, а также сделал службу фактическим объектом. Я бы рекомендовал вам отформатировать аргумент функции контроллера следующим образом... Если вы хотите обсудить/увидеть передовой опыт, перейдите здесь. Навсегда достаточно о передовой практике, теперь к реальной проблеме.

Решение проблемы

Хорошо, Эндрю действительно понял это!! Проблема была в том, что ему нужно транслировать свое сообщение с помощью $rootScope:

$rootScope.$broadcast('selected:updated', $scope.selected);

И затем вы должны проверить, когда обновляется $scope.selected.. вроде как $scope.$watch...

$scope.$on('selected:updated', function(event, data) {
          $scope.selected = data;
})

После этого он автоматически обновляется и работает! Надеюсь, это помогло!

PS: Не знал, что он уже ответил...

person amanuel2    schedule 07.05.2016
comment
Я просто хотел указать здесь, что вы не используете правила области действия в том виде, в котором написана эта служба. Ключевое слово this изменит функцию, на которую оно ссылается. Когда вы говорите «вернуть this.selected;» вы возвращаете неопределенное значение, потому что this.selected в области члена getSelected еще не определен. Этот код не будет работать. - person ajthyng; 09.05.2016

Итак, после долгих исследований и большой помощи от Dsafds я смог использовать $rootScope.$broadcast для уведомления мой частичный взгляд на изменение переменной.

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

$scope.selectEmployee = function(employee) {
            selectedEmployee.postSelected(employee);
            $scope.selected = selectedEmployee.getSelected();
            $rootScope.$broadcast('selected:updated', $scope.selected);
            if ($mdSidenav('left').isOpen()) {
                $mdSidenav('left').close();
            }
        }

И в контроллере области основного контента

function ($scope) {
    $scope.$on('selected:updated', function(event, data) {
        $scope.selected = data;
    })
}

Я не думаю, что вам нужно передавать данные напрямую, вы также можете легко вызвать selectedEmployee.getSelected()

$rootScope также должен быть включен в родительский контроллер и широковещательный контроллер.

person ajthyng    schedule 07.05.2016
comment
Злоупотребление широковещательной рассылкой корневой области вызовет у вас проблемы в долгосрочной перспективе и будет непростым в отладке. Лучше иметь иерархические отношения между контроллерами, которым необходимо транслировать события друг другу, и использовать излучение/трансляцию из определенных областей, и даже проще использовать общую модель, когда это возможно - см. мой ответ для примера последнего. - person William B; 09.05.2016
comment
Спасибо за совет, мне нужно будет прочитать, как правильно настроить отношения контроллера. - person ajthyng; 09.05.2016