#15 Scope true в директивах в AngularJS

poster
В этом уроке мы разберем чем отличается scope: true от scope: false в директиве и как изменения в скоупе директивы отражаются на контроллере.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Тема сегодняшнего урока - что такое 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 директивы.

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

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.