Грязная проверка с общим сервисом между контроллерами. Один способ работает, другой нет?

Пытаясь ответить на вопрос об обмене данными между двумя отдельными контроллерами, я столкнулся с вопросом.

Я обычно использую сервисы для этой задачи и начал создавать jsfiddle, но не смог заставить его работать.

После небольшой отладки, если я динамически создавал свойства в setActivePersonWorks(person), грязная проверка работала, и второй контроллер показывал правильное значение.

Если бы я присвоил значение в setActivePersonDoesNotWork(), это не так.

Если бы я использовал $timeout(), я смог убедиться, что DataService.badPerson действительно содержит правильные данные.

Я делаю что-то неправильно? Я думаю, если вы сделаете что-то с $apply(), это будет работать правильно, но почему динамическое создание значений приводит к тому, что все просто работает?

Рабочий пример:

var myTest = angular.module("MyTest", []);
myTest.factory("DataService", function () {
    var People = {
        goodPerson: {},
        badPerson: {},
        setActivePersonWorks: function (person) {
            People.goodPerson.name = person.name;
            People.goodPerson.id = person.id;
        },
        setActivePersonDoesNotWork: function (person) {
            People.badPerson = person;
        }
    };
    return People;
});

function ViewController($scope, DataService, $timeout) {
    $timeout(function () {
        DataService.setActivePersonWorks({
            id: 1,
            name: "Good Mark"
        });
        DataService.setActivePersonDoesNotWork({
            id: 2,
            name: "Bad Mark"
        });
    }, 1000);
}

function DetailController($scope, DataService, $timeout) {
    $scope.goodPerson = DataService.goodPerson;
    $scope.badPerson = DataService.badPerson;

    $timeout(function(){
        $scope.message = "DataService has the value: " + DataService.badPerson.name + " but $scope.badPerson is " + $scope.badPerson.name;
    }, 2000);
}

<html/>

<div ng-app="MyTest">
    <div ng-controller="ViewController"></div>
    <div ng-controller="DetailController">
         <h1>Works: {{goodPerson.name}}</h1>

         <h1>Does Not Work: {{badPerson.name}}</h1>
        {{message}}
    </div>
</div>

На jsfiddle


person Mark Coleman    schedule 09.05.2013    source источник


Ответы (1)


Когда Angular видит

<h1>Does Not Work: {{badPerson.name}}</h1>

он устанавливает $watch на объект badPerson. Глядя на ваш контроллер, $scope.badPerson является ссылкой на объект DataService.badPerson. Пока все в порядке... проблема возникает здесь:

setActivePersonDoesNotWork: function (person) {
    People.badPerson = person;
}

Когда эта функция выполняется, badPerson назначается новая/другая ссылка на объект, но контроллер по-прежнему $наблюдает за старой/исходной ссылкой на объект.

Исправление заключается в использовании angular.copy() для обновления существующего объекта badPerson вместо назначения новой ссылки:

setActivePersonDoesNotWork: function (person) {
    angular.copy(person, People.badPerson);
}

Это также объясняет, почему setActivePersonWorks() работает — он не присваивает новую ссылку на объект.

person Mark Rajcok    schedule 09.05.2013
comment
Превосходно! Спасибо за исправление, а также объяснение. - person Mark Coleman; 09.05.2013