Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   Вопрос от начинающего (Directive & isolated scope) (https://javascript.ru/forum/angular/59709-vopros-ot-nachinayushhego-directive-isolated-scope.html)

tfn2k 23.11.2015 15:51

Вопрос от начинающего (Directive & isolated scope)
 
Добрый день.
Попрошу учесть факт что я только начал изучать AngularJS, посему попрошу сильно не "гнобить" :)

Есть следующий пример HTML:
<input type="text" ng-model="myUrl" />
<div my-directive
some-attr="{{ myUrl }}"
my-link-text="Click me to go to Google">
</div>


И собственно сама директива:
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: 'A',
replace: true,
scope: {
myUrl: '@someAttr',
myLinkText: '@'
},
template: '<a href="{{myUrl}}">' +
'{{myLinkText}}</a>'
}
})


Вопрос:
В строчке HTML:
<input type="text" ng-model="myUrl" />

мы создаем свойство myUrl объекта scope данной области видимости (в моем понимании данного примера, это $rootScope)
Как видно с определения директивы, мы создаем изолированный scope.
Объясните, пожалуйста, как в этот isolated scope попадает свойство с $rootScope?
Или bind идет между isolated scope директивы ng-model и isolated scope моей директивы? Если так, объясните как это происходит.

З.Ы. Пытался найти ответ сам, не получилось :). Если есть ссылки на эту тему - буду благодарен.

Спасибо.

Shitbox2 25.11.2015 02:13

replace: true уже год помечено как depricated (не рекомендуется использовать).

В isolated scope создается копия свойства из $rootScope. При изменении данных в $rootScope копия обновляется. При изменении данных в isolated scope — перезаписывается, т. е. теряется связь с оригиналом.

tfn2k 25.11.2015 10:05

За Replace - спасибо, не знал.

"В isolated scope создается копия свойства из $rootScope".
Я думал что в isolated scope ничего не попадает, на то он и изолированный. И это вызывает еще один вопрос - что конкретно наследует isolated scope - $rootScope или ParentScope (+ вся цепочка)? Я думал что наследование directive's scope возможно только при scope: false или scope: true (но при таких значениях это уже не isolated scope)

Спасибо.

grego 25.11.2015 18:33

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

С технической точки зрения все скоупы (включая и rootScope) создаются одной функцией конструктором, поэтому безусловно они будут иметь общий набор свойств и методов, но это как правило внутренние свойства и методы Angular.
Вот здесь есть описание и куски кода, если интересна реализация? http://jonathancreamer.com/adding-cl...ce-in-angular/. Работу наследования можно проверить и самому - ходя по внутренним свойствам скоупа $scope.$parent, $scope.$parent.$parent и проверяя там наличие тех или иных данных, если сомневаетесь.

Так что все работает канонично - если хотите, чтобы isolated scope что-либо наследовал - придется передавать это как параметры скоупа в конфигурации директивы: scope: { prop1: '=', prop2: '=' }.

Теперь к твоему вопросу :)
Смотри, твой сниппет кода, который начинается с <input type="text" , в том виде в котором ты его скинул с точки зрения ангуляр приложения "висит в воздухе". Т. е. у тебя есть темплейт, тебе нужно "место для хранения данных".
У тебя есть 2 пути:
1. Создать контроллер, контроллер это "glue" между данными и темплейтом, https://docs.angularjs.org/guide/controller здесь больше информации. Соотв-но ты можешь разместить свойство myUrl в нем.
2. Второй подход - это создать директиву. Т. е. твой темплейт будет темплейтом директивы, свойство myUrl будет лежать либо в контроллере директивы (да, у директивы может быть контроллер) либо в специальной функции линковке link. В таком случае у тебя будет директива в директива, родительская будет связана свойством myUrl с дочерней.

Если что-то не понятно - пиши.

tfn2k 27.11.2015 11:23

Спасибо за инфо и за ссылки.
Но мне кажется что ты не совсем понял мой вопрос (либо я твой ответ :) ). Давайте еще раз и сначала :)

"Смотри, твой сниппет кода, который начинается с <input type="text" , в том виде в котором ты его скинул с точки зрения ангуляр приложения "висит в воздухе". Т. е. у тебя есть темплейт, тебе нужно "место для хранения данных"."

Это я понимаю и полностью согласен с описанными вариантами. Но я не согласен с:
"приложения "висит в воздухе". Т. е. у тебя есть темплейт, тебе нужно "место для хранения данных"."

Давайте разберем HTML код (код директивы без изменений):
<!DOCTYPE html>
<html ng-app='myApp'>
/* вот после этой директивы создается $rootScope.
    "When Angular starts to run and generate the view, it will create a binding from the root ng-app
    element to the $rootScope. This $rootScope is the eventual parent of all $scope objects."
    Взято с книги "ng-book The Complete Book on AngularJS" стр. 20
    "Placing ng-app on any DOM element marks that element as the beginning of the $rootScope"
    Взято с книги "ng-book The Complete Book on AngularJS" стр. 84    
*/
        <head>
		<title>AngularJS test</title>
	</head>

	<body>
		<input type="text" ng-model="myUrl" />
 /*Так как директив создающих новый scope не оглашалось, то директива ng-model  в поле видимости
    $rootScope, соответственно записывается в свойство $rootScope,
    "Ng-Model binds to the property given by evaluating the expression on the current scope. If the property
    doesn’t already exist on this scope, it will be created implicitly and added to the scope."
    Все так же книга стр. 93 
*/        
		<div my-directive
			some-attr="{{ myUrl }}"
			my-link-text="Click me to go to Google">
		</div>
/* Вот здесь самое интересное. Эта директива создает новый изолированный scope и компилируется она согласно своему скоупу, в котором (в моем понимании) не должно быть свойства myUrl, но Angular его как-то находит.
*/
		<script src="assets/js/modules/angular.js"></script>
		<script src="assets/js/main.js"></script>
	</body>
</html>


Собственно сам вопрос - как в изолированный scope директивы myDirective попадает свойство myUrl с $rootScope?
Я знаю что пример работает правильно, соответственно есть логическое объяснение принципа работы, вот его я пытаюсь понять :)

Спасибо.

grego 01.12.2015 00:14

Так, прошу прощения за поздний ответ.

1. Я вижу использование ng-app и в этом случае действительно директива связывает используемые данные с rootScope, т. е. ng-model="myUrl" смотрит на rootScope.myUrl. На практике такое встретишь редко, все же "загрязнять" рутовый скоуп считается bad practice, но в качестве тестового примера безусловно подойдет.

2. Теперь непосредственно к твоему вопросу (надеюсь сейчас я на него отвечу).
А. Итак, у тебя есть директива <div my-directive, с атрибутом some-attr="{{ myUrl }}". Т. е. мы в качестве значения атрибута some-attr поставляем извне myUrl (в данном случае это тот самый myUrl из рут скоупа). Фигурные скобки или обычные - это всего лишь способы биндинга данных, можешь почитать тут https://gist.github.com/CMCDragonkai/6282750 подробнее.
Б. Теперь идем в код непосредственно самой директивы и обращаем пристальное внимание на объект scope, видим следующее:
myUrl: '@someAttr',
myLinkText: '@'
Это говорит нам о следующем - для директивы будет создан изолированный объект-скоуп, в котором будут инициализированы 2 свойства - scope.myUrl и scope.myLinkText. Первое свойство будет связано со значением, которое подается в директиву в качестве атрибута some-attr (синтаксис таков, что в перечислении свойств используется camel case нотация атрибутов).
Вот и получается следующее - в изолированном скоупе появляется собственное свойство scope.myUrl - оно не унаследовано от родительского скоупа, но за счет создания связи - оно будет изменяться в обе стороны со свойством myUrl из рут скоупа, которое подано как значение someAttr.
В принципе чтобы не путаться, можно объявить изолированный скоуп как

scope: {
isolatedMyUrl: '@someAttr',
myLinkText: '@'
},
и поменять темплейт директивы
template: '<a href="{{isolatedMyUrl}}">' +
'{{myLinkText}}</a>'
Работать все будет так же.

tfn2k 01.12.2015 10:17

Вот теперь понятно :)
Меня интересовало как Angular интерполирует {{myUrl}} именно в атрибуте директивы. То как берется свойство $scope.myUrl в изолированном scope и как с ним дальше работать я понимал, но все равно спасибо!

Ответ 2.А - то что я искал + ссылка внесла ясность:
"//IMPORTANT: if scope.myUrl was not defined on the parent scope, then '@' interpolates it into". Иными словам - если в custom directive есть атрибут который надо интерполировать то Angular сделает это согласно ParentScope (и в зависимости от настроек isolated scope может быть одно/двонаправленная связь). Раньше я думал, что атрибуты кастомной директивы интерполируются согласно scope самой директивы, потому и не понимал как Angular понимает что подставить в some-attr="{{ myUrl }}"

Еще раз спасибо и "+" в карму тебе :)

AandreM92 15.12.2015 12:07

Вопрос от начинающего Directive isolated scope
 
Сейчас прочитал, что Экзаменатор должен иметь:
- диплом о высшем или среднем специальном техническом образовании. Это, что значит я пролетаю что ли?


Часовой пояс GMT +3, время: 23:07.