Инструменты пользователя

Инструменты сайта


angular:angularjs:custom_directive:component

Это старая версия документа!


от directive() к component()

В Angular 1.5 нам был представлен новый метод .component(), который намного проще чем .directive() и при этом он использует все лучшее по умолчанию. Метод .component() также позволит разработчикам писать в Angular2 стиле, то есть сделает переход на вторую версию максимально безболезненным.

В этом посте мы попробуем параллельно разобрать старый и новый подходы для создания компонентов.

На примере простой директивы counter мы посмотрим как можно создать компонент с аналогичной функциональностью:

<!DOCTYPE html>
<html ng-app="app">
<head>
    <title></title>
    <script src="http://crm.localhost/vendor/angular/angular.min.js"></script>
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <link href="../bootstrap.css" rel="stylesheet" />
    <script>
        angular.module("app", [])
        .controller("studyCtrl", function ($scope) {
            $scope.count = 5;
        })
 
        .directive('counter', function counter() {
            return {
                scope: {},
                bindToController: {
                    count: '='
                },
                controller: function () {
 
                    function increment() {
                        this.count++;
                    }
                    function decrement() {
                        this.count--;
                    }
                    this.increment = increment;
                    this.decrement = decrement;
                },
                controllerAs: 'counter',
                template: [
                    '<div class="form-group">',
                        '<label class="control-label col-md-1" for="">Директива</label>',
                        '<div class="input-group col-md-2">',
                            '<div class="input-group-addon" ng-click="counter.decrement();">-</div>',
                            '<input class="form-control" type="text" ng-model="counter.count">',
                            '<div class="input-group-addon" ng-click="counter.increment();">+</div>',
                        '</div>',
                    '</div>'
                ].join('')
            };
        });
 
    </script>
</head>
<body ng-controller="studyCtrl as vm">
    <div class="container">
        <br>
        <div class="row">
            <div class="col-md-1"><b>контроллер</b></div> <div class="col-md-2">{{count}}</div>
        </div>
        <br>
        <div class="row">
            <label><counter  count="count"></counter></label>
        </div>
    </div>
</body>
</html>

Объект вместо Функции

Начнем наш анализ со способа задания и обратим внимание на то, что параметры в компонент передаются как объект (а не функция, что было в директиве):

// до
.directive('counter', function counter() {
  return {    
  };
});
 
// после
.component('counter', {
 
});

Scope и BindToController становятся просто Bindings

В директиве мы можем задавать scope 3-мя способами: родительский(скоуп не создается), наследник от родительского, изолированный. Со временем мы приходим к выводу, что изолированный скоуп, где мы четко задаем входящие параметры, наилучший вариант. Так же каждый раз для изолированного скоупа нам приходиться прописывать bindToController, чтобы прокинуть данные со скоупа непосредственно на контроллер директивы.

Свойство компонента bindings позволяет использовать 2 в одном, так как компонент использует изолированный скоуп по умолчанию:

// before
.directive('counter', function counter() {
  return {
    scope: {},
    bindToController: {
      count: '='
    }
  };
});
 
// after
.component('counter', {
  bindings: {
    count: '='
  }
});

Controller и ControllerAs

Ничего не изменилось в способе задания контроллера, однако теперь controllerAs параметр по умолчанию, который задан как “$ctrl“: то есть если мы в контроллере напишем:

this.x = 5;

то в шаблоне компонента потом можно будет обратиться вот так:

<div>{{$ctrl.x}}</div>

Итак, что у нас получилось с контроллером для обоих случаев:

// до
.directive('counter', function counter() {
  return {
    scope: {},
    bindToController: {
      count: '='
    },
    controller: function () {
      function increment() {
        this.count++;
      }
      function decrement() {
        this.count--;
      }
      this.increment = increment;
      this.decrement = decrement;
    },
    controllerAs: 'counter'
  };
});
 
// после
.component('counter', {
  bindings: {
    count: '='
  },
  controller: function () {
    function increment() {
      this.count++;
    }
    function decrement() {
      this.count--;
    }
    this.increment = increment;
    this.decrement = decrement;
  }
});

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

Шаблоны

В определении шаблонов есть небольшое различие: шаблон компонента может задаваться как функция, в которую инжектятся элемент и атрибуты:

{
  ...
  template: function ($element, $attrs) {
    // access to $element and $attrs
    return '...';
  }
  ...
}

Улучшенное require

Да, это свершилось! Теперь мы можем задать имя для контроллера, подключаемого к нашему компоненту, и обратиться к нему из контроллера( до этого только из метода link, а в контроллер оно попадало только путем ужасных костылей):

{
  ...
  require: {
    parent: '^parentComponent'
  },
  controller: function () {
    // use this.parent to access required Objects
    this.parent.foo();
  }
  ...
}

В данном случае мы определили подключаемый контроллер на свойстве parent.

angular/angularjs/custom_directive/component.1626121297.txt.gz · Последние изменения: 2023/01/12 12:15 (внешнее изменение)