it-swarm.com.ru

Запутался в том, что Angularjs включил и изолировал области видимости и привязки

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

Я понял, что ограничение области действия директивы означает, что controller. $ Scope и directive.scope больше не одно и то же. Однако меня смущает то, как размещение моделей в шаблоне директивы или в html влияет на привязку данных. Я чувствую, что упускаю что-то очень фундаментальное, и чтобы двигаться дальше, мне нужно это понять.

Возьмите следующий код (скрипите здесь: http://jsfiddle.net/2ams6/ )

JavaScript

var app = angular.module('app',[]);
app.controller('Ctrl',function($scope){
});
app.directive('testel', function(){
    return {
        restrict: 'E',
        scope: {
            title: '@'
        },
        transclude: true,
        template:   '<div ng-transclude>'+
                    '<h3>Template title: {{title}}</h3>' +
                    '<h3>Template data.title:{{data.title}}</h3>' +
                    '</div>'
    }    
}); 

HTML

<div ng-app='app'>
    <div ng-controller="Ctrl">
        <input ng-model="data.title">
        <testel title="{{data.title}}">
            <h3>Transclude title:{{title}}</span></h3>
            <h3>Transclude data.title:{{data.title}}</h3>
        </testel>
    </div>
</div>

Модель обновляет только {{title}} в шаблоне и {{data.title}} в включении. Почему бы ни {{title}} в трансклюзии, ни {{data.title}} в шаблоне?

Перемещение ввода в трансклюзию, например, так (скрипка здесь: http://jsfiddle.net/eV8q8/1/ ):

<div ng-controller="Ctrl">
    <testel title="{{data.title}}">
        <input ng-model="data.title">
         <h3>Transclude title: <span style="color:red">{{title}}</span></h3>

         <h3>Transclude data.title: <span style="color:red">{{data.title}}</span></h3>

    </testel>
</div>

теперь означает, что только transclude {{data:title}} обновляется. Почему бы не использовать шаблон {{title}} или {{data.title}} и не включить {{title}}?

И, наконец, перемещение ввода в шаблон, например, так (здесь: fiddle: http://jsfiddle.net/4ngmf/2/ ):

template: '<div ng-transclude>' +
            '<input ng-model="data.title" />' +
            '<h3>Template title: {{title}}</h3>' +
            '<h3>Template data.title: {{data.title}}</h3>' +
            '</div>'

Теперь означает, что обновляется только шаблон {{data.title}}. Опять же, почему не остальные 3 привязки?

Надеюсь, что-то очевидное смотрит мне в лицо, и я скучаю по этому. Если вы дадите мне это, я куплю вам пиво, или дам вам очки, или еще что-нибудь подобное. Большое спасибо.

55
dewd

Ваши скрипки создают три области:

  1. область, связанная с контроллером Ctrl, из-за ng-controller
  2. директива перешла в область видимости из-за transclude: true
  3. директива изолирует область действия из-за scope: { ... }

В fiddle1, прежде чем мы введем что-либо в текстовое поле, мы имеем следующее:

enter image description here

Область действия 003 - это область действия, связанная с контроллером. Поскольку мы еще не печатали в текстовое поле, свойства data не существует. В изолированной области видимости 004 мы видим, что свойство title было создано, но оно пустое. Он пуст, поскольку родительская область еще не имеет свойства data.title.

После ввода my title в текстовое поле мы теперь имеем:

enter image description here

Область действия контроллера 003 теперь имеет новое свойство объекта data (поэтому оно окрашено в желтый цвет), для свойства title которого теперь установлено значение my title. Поскольку свойство изолирующей области title является односторонней привязкой данных к интерполированному значению data.title, оно также получает значение my title (значение окрашено в желтый цвет, поскольку оно изменилось).

Трансклюзивная область прототипно наследуется от области контроллера, поэтому внутри включенного HTML angular может следовать цепочке прототипов и находить $scope.data.title в родительской области (но $scope.title там не существует).

Область изолята имеет доступ только к своим собственным свойствам, следовательно, только к свойству title.

В fiddle2 перед тем, как печатать, мы имеем ту же картинку, что и в fiddle1.

После ввода my title:

enter image description here

Обратите внимание, где появилось новое свойство data.title - в области включения. Изолированная область все еще ищет data.title в области контроллера, но на этот раз ее там нет, поэтому значение свойства title остается пустым.

В fiddle3 перед тем, как печатать, мы имеем ту же картинку, что и в fiddle1.

После ввода my title:

enter image description here

Обратите внимание, где появилось новое свойство data.title - в изолированной области видимости. Ни одна из других областей не имеет доступа к изолированной области, поэтому строка my title больше нигде не появится.


Обновление для Angular v1.2:

С изменением eed299a Angular теперь очищается точка включения перед включением, поэтому части Template title: ... и Template data.title: ... не будут отображаться, если вы не измените шаблон так, чтобы ng-transclude сам по себе, например :

'<h3>Template title: <span style="color:red">{{title}}</span></h3>' +
'<h3>Template data.title: <span style="color:red">{{data.title}}</span></h3>' +
'<div ng-transclude></div>'

В приведенном ниже обновлении для Angular v1.3 это изменение шаблона было сделано.


Обновление для Angular v1.3 +:

Начиная с Angular v1.3, включенная область видимости теперь является дочерним элементом изолированной области директивы, а не дочерней областью контроллера. Итак, в fiddle1, прежде чем мы что-то наберем

enter image description here

Изображения в этом обновлении рисуются с помощью инструмента Peri $ scope , поэтому изображения немного другие. @ указывает на то, что у нас есть свойство изолированного контекста, в котором используется синтаксис @, а розовый фон означает, что инструмент не смог найти ссылку на предка для сопоставления (что верно, поскольку мы еще ничего не вводили в текстовое поле ).

После ввода my title в текстовое поле мы теперь имеем:

enter image description here

Свойства изоляции, использующие привязку @, всегда будут отображать результат интерполированной строки в изолированной области после символа @. Peri $ scope также смог найти это точное строковое значение в области предков, поэтому он также показывает ссылку на это свойство.

В скрипте 2 перед тем, как печатать, мы имеем ту же картинку, что и в скрипте 1.

После ввода my title:

enter image description here

Обратите внимание, где появилось новое свойство data.title - в области включения. Изолированная область все еще ищет data.title в области контроллера, но на этот раз ее там нет, поэтому значение свойства title остается пустым.

В fiddle3 перед тем, как печатать, мы имеем ту же картинку, что и в fiddle1.

После ввода my title:

enter image description here

Обратите внимание, где появилось новое свойство data.title - в изолированной области видимости. Даже несмотря на то, что включенная область имеет доступ к изолированной области через отношение $parent, она не будет искать там title или data.title - она ​​будет искать только в области контроллера (т. Е. Она будет следовать наследованию прототипа), и контроллер область не имеет эти свойства определены.

113
Mark Rajcok

После прочтения всех представленных ответов, включая фантастические схемы Марка, это мое понимание объема и наследования для моего вопроса. Буду признателен за комментарии о том, где эта диаграмма падает, для того, чтобы я мог соответствующим образом обновить. Я надеюсь, что это просто дает другое представление о том, что представил Марк

Scope inheritance

22
dewd

Хорошо спросил, кстати! Надеюсь, мой ответ столь же красноречив.

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

Подводя итог, у вас есть две области:

  1. Область контроллера, которая имеет $scope.data.title. (Неявно добавлено вашим элементом input)
  2. Область действия директивы, которая имеет $scope.title.

Когда вы изменяете $scope.data.title контроллера, директива $scope.title также изменяется.

У вас также есть два раздела HTML, включенный и шаблон. Происходит то, что включенный HTML находится в области видимости контроллера , а HTML-шаблон находится в директиве сфера. Таким образом, включенный HTML ничего не знает о title, а область действия шаблона ничего не знает о data.title

На самом деле это именно то, для чего предназначалась Transclusion - , чтобы позволить дочерним элементам директивы сохранять родительскую область видимости , в данном случае область контроллера. По замыслу, включенные элементы не знают, что они в директиве, и поэтому не имеют доступа к области действия директивы.

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

Я немного изменил ваш код, чтобы сделать имена немного более понятными (хотя и с той же функциональностью)

http://jsfiddle.net/yWWVs/2/

8
Roy Truelove