
Тема сегодняшнего урока - что такое scope - true и зачем он нужен.
Для начала, в файл index.html, создадим контроллер и директиву в нем:
<!DOCTYPE html>
<html lang="en" ng-app='app'>
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script src="main.js"></script>
</head>
<body>
<div ng-controller="booksCtrl">
<book></book>
</div>
</body>
</html>
Опишем наш контроллер и директиву в файле main.js:
var app= angular.module('app', []);
app.controller('booksCtrl', function($scope) {
console.log('scope from controller', $scope);
});
app.directive('book', function () {
return {
link: function (scope, element, attrs) {
console.log('scope from directive', scope);
}
};
});
Мы создали link функцию, для проверки работоспособности директивы, и передали в качестве параметров - scope, element, attrs.
В консоли браузера мы видим, что отображаются оба scope и, как мы помним из предыдущего урока, они идентичны на данный момент, так как ссылаются на один и тот же объект. Что произойдет, если мы в директиве укажем scope: true? Давайте проверим! А для большей наглядности, создадим в контроллере переменную name:
var app= angular.module('app', []);
app.controller('booksCtrl', function($scope) {
$scope.name = 'Harry';
console.log('scope from controller', $scope);
});
app.directive('book', function () {
return {
scope: true,
link: function (scope, element, attrs) {
console.log('scope from directive', scope);
}
};
});
Обновим страницу в браузере. Внутри $scope контроллера мы видим name: "Harry", а в scope директивы такое поле отсутствует. Но, если мы внимательно изучим поле proto - прототипное наследование, то внутри мы увидим наше name: "Harry". Почему? При использовании в директиве scope: true - создается new scope от $scope контроллера. То есть на данный момент, scope директивы является дочерним $scope контроллера и передается с помощью прототипного наследования. А это значит, что через свойство proto, мы можем получить доступ к ролительскому $scope.
Убедимся - так ли это? В index.html выводим переменную:
<div ng-controller="booksCtrl">
This is ctrl name: {{name}}
<book></book>
</div>
В директиве:
app.directive('book', function () {
return {
scope: true,
link: function (scope, element, attrs) {
console.log('scope from directive', scope);
console.log(scope.name);
}
};
});
Заглянем в браузер. Видим строку "This is ctrl name: Harry", которую мы создали в контроллере. При этом, в консоли браузера, также отображается Harry, но уже благодаря прототипному наследованию.
Добавим template в директиву:
app.directive('book', function () {
return {
scope: true,
template: "My name is {{name}}",
link: function (scope, element, attrs) {
console.log('scope from directive', scope);
console.log(scope.name);
}
};
});
В браузере появилась строка - "My name is Harry". Что произойдет, если мы в директиве захотим изменить нашу переменную? Давайте изменим наш template для большей наглядности:
app.directive('book', function () {
return {
scope: true,
template: "<div>My name is {{name}} <input type='text' ng-model='name'></div>",
link: function (scope, element, attrs) {
console.log('scope from directive', scope);
console.log(scope.name);
}
};
});
Теперь, в браузере, мы видим содержимое директивы, включая тектовое поле <input\>, в которой шаблоном мы создали текст с переменной {{name}} из контроллера. Harry в текстовом поле <input> - привязан к нашей модели и, если в <input> мы меняем Harry на что-то другое, то переменная в директиве также меняется, при этом переменная в контроллере не изменилась. Почему это происходит? Мы находимся совершеннов другом scope, когда используем поле <input\>, но так как это дочерний scope, то мы имеем доступ к переменным, находящимся внутри контроллера, через прототипному наследованию. Поэтому, при изменении в поле <input\> переменной - они изменяется только в дочернем scope директивы.
Данный метод очень удобен, так как позволяет получать доступ к переменным контроллера, но при этом использование директивы становится намного безопаснее, поскольку мы не можем менять переменные контроллера на прямую.