Почему я не могу перезаписать значение такой переменной?

Я пытаюсь понять, почему у меня возникают проблемы с перезаписью значения, переданного в директиву angularJS через изолированную область (@). Я пытаюсь перезаписать значение vm.index следующим:

vm.index = parseInt(vm.index, 10)

Однако он не работает по какой-то причине.

Если я изменю его на:

vm.newIndex = parseInt(vm.index, 10)

Оно работает. Кроме того, присвоение значения $scope работает.

Почему не работает первый способ?

Я создал этот пример плунжера для справки.


person Raphael Rafatpanah    schedule 23.06.2015    source источник
comment
Что именно вы имеете в виду, когда говорите, что это не работает?   -  person Pointy    schedule 23.06.2015
comment
Извините, я не имел в виду, что vm.index не преобразуется из строки в число, что приводит к конкатенации строк при выполнении чего-то вроде {{ vm.index + 1 }}.   -  person Raphael Rafatpanah    schedule 23.06.2015
comment
@ brso05, я в курсе. Однако область действия здесь не является проблемой, поскольку вы можете убедиться в этом сами, изменив vm.index = ... на vm.newIndex = ... и обновив шаблон для использования vm.newIndex + 1.   -  person Raphael Rafatpanah    schedule 23.06.2015
comment
@RaphaelRafatpanah, не могли бы вы взглянуть на мой обновленный ответ ... который дал бы вам больше понимания, почему vm.index не будет работать, сделав прямой parseInt с контроллера   -  person Pankaj Parkar    schedule 24.06.2015
comment
@pankajparkar, в моем коде я просто заменил @ на =, но я отметил ваш ответ как правильный, потому что он очень хорошо отвечает на вопрос. Спасибо.   -  person Raphael Rafatpanah    schedule 24.06.2015
comment
@RaphaelRafatpanah спасибо..Рад вам помочь..Спасибо :)   -  person Pankaj Parkar    schedule 26.06.2015
comment
Ссылка на плунжер мертва.   -  person fracz    schedule 03.12.2015


Ответы (2)


Поскольку вы использовали здесь @, для которого требуется значение из атрибута с директивой интерполяции {{}}. И кажется, что сначала загружается директива, а затем оценивается значение vm.index. Таким образом, изменения не происходят в текущем цикле дайджеста. Если вы хотите, чтобы они отражались, вам нужно запустить цикл дайджеста более безопасным способом, используя $timeout.

$timeout(function(){
  vm.index = parseInt(vm.index, 10)
})

Вышеупомянутая вещь гарантирует, что значение преобразуется в десятичное значение. Добавление будет происходить по директиве html <h2>Item {{ vm.index + 1 }}</h2>

Рабочая демонстрация

Возможная причина

Согласно @dsfq и моему обсуждению, мы прошли угловой $compile API и обнаружили, что это один вызов метода initializeDirectiveBindings, который вызывается только тогда, когда мы используем controllerAs в директиве с изолированной областью. В этой функции есть случаи переключения для различных привязок @, = и & , поэтому, поскольку вы используете @, это означает, что вызывается односторонняя привязка, следующая за кодом случая переключения.

Код

case '@':
    if (!optional && !hasOwnProperty.call(attrs, attrName)) {
        destination[scopeName] = attrs[attrName] = void 0;
    }
    attrs.$observe(attrName, function(value) {
        if (isString(value)) {
            destination[scopeName] = value;
        }
    });
    attrs.$$observers[attrName].$$scope = scope;
    if (isString(attrs[attrName])) {
        // If the attribute has been provided then we trigger an interpolation to ensure
        // the value is there for use in the link fn
        destination[scopeName] = $interpolate(attrs[attrName])(scope);
    }
    break;

В приведенном выше коде вы можете ясно видеть, что там они разместили attrs.$observe, который является одним из видов наблюдателя, который обычно используется, когда значение интерполировано, как в нашем случае это то же самое {{index}}, это означает, что это $observe оценивается при запуске цикла дайджеста, это почему вам нужно поставить $timeout, сделав index значением decimal.

Причина, по которой ответ @dsfq работает, потому что он использует =, обеспечивает двустороннюю привязку, код которой не помещает наблюдатель напрямую извлекать значение из изолированной области, вот код. Таким образом, без цикла дайджеста это значение обновляется.

person Pankaj Parkar    schedule 23.06.2015
comment
Это правильный подход к проблеме. Что происходит, так это то, что контроллер инициализируется до конфигурации области действия директивы. Таким образом, контроллер запускается первым, затем scope => index создает контроллер this.index из значения атрибута, которое является строкой. Он перезаписывает все, что вы установили в контроллере. - person dfsq; 24.06.2015

По-видимому, это как-то связано с односторонней привязкой значения области видимости index. Таким образом, Angular не будет обновлять scope.index (или this.index в случае bindToController: true), потому что область действия настроена как

scope: {
    index: '@'
},

Если вы измените его на двустороннюю привязку, например:

scope: {
    index: '='
},

Это будет работать:

<some-directive index="$index"></some-directive>

Демо: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview

UPD. @pankajparkar хорошо заметил, что обновление значения в следующем дайджесте решило проблему. Тогда этот подход к проблеме ближе, чем то, что я сделал в этом ответе.

person dfsq    schedule 23.06.2015
comment
Извините, но я думаю, что вы неправильно прочитали вопрос. Почему область действия работает, а vm.index не работает, я имею в виду дополнение к директиве html. - person Pankaj Parkar; 23.06.2015
comment
Да, похоже, вы правы, однако непонятно, зачем в таком случае нужен следующий дайджест. - person dfsq; 24.06.2015
comment
это, вероятно, из-за @ или, скорее, я могу сказать, что директива интерполяции.. директива инициализируется первой, а значение заполняется после оценки парсера - person Pankaj Parkar; 24.06.2015
comment
Да, это определенно связано с @, но я не уверен насчет всего механизма в данном случае. Но вы хорошо заметили с тайм-аутом. - person dfsq; 24.06.2015
comment
Спасибо за вашу оценку ... ваше решение тоже круто ... но не объяснило ответ на вопрос ОП ... - person Pankaj Parkar; 24.06.2015
comment
Давайте продолжим обсуждение в чате. - person Pankaj Parkar; 24.06.2015
comment
в соответствии с нашим обсуждением я обновил ответ .. не могли бы вы взглянуть на него .. и не стесняйтесь редактировать его .. Спасибо :) - person Pankaj Parkar; 24.06.2015