Angular.JS - Краткая документация

MVC - Java-Script это

APP / Modules

  • Module - Базовый контейнер для app включает в себя controllers, services, filters, directives сконфигурированные Injector
  • Service - Бизнес логика для отображения в views
  • Dependency-Injection - Создает ленивые связи с объектами
  • Injector - dependency injection container
  • View - HTM представление (может содержать ng дериктивы)
    • Template - HTML шаблон
      • Directives - extend HTML with custom attributes and elements
      • Markup - Обработка шаблона
      • Filter - Обработка данных перед выводом
      • Form controls - Angular автоматически обрабатывает формы
  • Compiler - parses the template and instantiates directives and expressions
  • Controller - the business logic behind views
    • Behavior - Функции внутри контролера
    • Model - Данные содержащиеся в контролере
    • Scope - $scope - Область контроллера содержащая данные модели
    • Expressions - access variables and functions from the scope
  • Data Binding - sync data between the model and the view

https://docs.angularjs.org/guide/concepts

<div ng-app="myApp">
</div>
var app = angular.module('myApp', []);
Директивы при создании всегда именуются с использованием lowerCamelCase. При использовании директиву необходимо именовать в нижнем регистре с использованием в качестве разделителя одного из спец символов: :, -, или _. По желанию для получения валидного кода можно использовать префиксы x- или data-. Примеры: tb:tooltip, tb-tooltip, tb_tooltip, x-tb-tooltip и data-tb-tooltip.
<my-element></my-element>
 
<div my-element></div>
 
<div class="my-element"></div>
 
<!-- directive: my-element -->

При указании restrict: "A", данная директива будет доступна только для аттрибутов, те

  • E - для элементов
  • A - для атрибутов
  • C - для классов
  • М - для комментариев
  • compile: фаза, во время которой можно производить трансформацию шаблонной DOM-структуры элемента, к которому применяется директива. Под шаблонной структурой подразумевается либо внутренняя структура, описанная в самом коде HTML страницы, либо шаблон, заданный полями template или
  • templateUrl: конфигурационного объекта. Следующим примером будет как раз директива на базе compile функции;
  • preLink: фаза, выполняемая перед связыванием всех дочерних элементов. Здесь не рекомендуется проводить какие-либо трансформации DOM;
  • postLink: фаза, выполняемая после связывания всех дочерних элементов. Наиболее часто используемая фаза. Здесь рекомендуется выполнять все необходимые DOM трансформации, навешивать обработчики событий и т.п.

Последовательность выполнения фаз

  • ng-init - Инициализация APP
  • ng-repeat - Выводить массив данных
  • ng-show | ng-hide - Выводить или нет контейнер
    • Пример: ng-show="product.images.length", ng-hide="product.images[0].hidden">
  • ng-class - Сообщает имя класса
  • ng-click - Слушает событие клик на объекте
  • ng-model - Служит для привязки контролера к элементам формы

https://docs.angularjs.org/guide/directive

<div ng-app="myApp">
  <div ng-controller="myAppConroller as controller">
    <div ng-repeat="item in controller.items | limitTo:3 | orderBy:'-price'">
      <div ng-hide="controller.item.soldOut">
        <h1>{{item.name | name}}</h1>
        <h1>{{item.price | price}}</h1>
        <h1>{{item.description | limitTo:52}}</h1>
        <button ng-show="controller.product.canPurchase"> Add to Cart </button>
      </div>
    </div>
  </div>
 
  <div ng-controller="reviewsConroller as review">
  <div class="myForms">
    <form name="reviewForm">
      <blockquote>
        {{review.stars}}
        {{review.body}}
      </blockquote>
      <select ng-model="review.stars">
        <option value="1">1 Star</option>
      </select>
      <textarea ng-model="review.body"></textarea>
      <input type="submit" value="Submit">
    </form>
  </div>
  </div>
</div>

Пример кастомных директив

Пример реализции динамических шаблонов

angular.module('finance2', [])
.factory('currencyConverter', function() {
  var currencies = ['USD', 'EUR', 'CNY'];
  var usdToForeignRates = {
    USD: 1,
    EUR: 0.74,
    CNY: 6.09
  };
  var convert = function (amount, inCurr, outCurr) {
    return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
  };
 
  return {
    currencies: currencies,
    convert: convert
  };
});
angular.module('invoice2', ['finance2'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
  this.qty = 1;
  this.cost = 2;
  this.inCurr = 'EUR';
  this.currencies = currencyConverter.currencies;
 
  this.total = function total(outCurr) {
    return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
  };
  this.pay = function pay() {
    window.alert("Thanks!");
  };
}]);
<div ng-app="invoice2" ng-controller="InvoiceController as invoice">
  <b>Invoice:</b>
  <div>
    Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
  </div>
  <div>
    Costs: <input type="number" min="0" ng-model="invoice.cost" required >
    <select ng-model="invoice.inCurr">
      <option ng-repeat="c in invoice.currencies">{{c}}</option>
    </select>
  </div>
  <div>
    <b>Total:</b>
    <span ng-repeat="c in invoice.currencies">
      {{invoice.total(c) | currency:c}}
    </span>
    <button class="btn" ng-click="invoice.pay()">Pay</button>
  </div>
</div>
app.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, service!"
    };
});
app.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, Factory!"
        }
    };
});
app.provider('helloWorld', function() {
 
    this.name = 'Provider';
 
    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };
 
    this.setName = function(name) {
        this.name = name;
    };
});

<div ng-app="myApp">
  <div ng-controller="invoceController as invoce">
    <h1>{{invoce.item.name}}</h1>
    <h1>{{invoce.item.field1}}</h1>
    <h1>{{invoce.item.field2}}</h1>
  </div>
</div>
Алиас invoce работает только для view
var app = angular.module('myApp', []);
 
app.conroller('invoceController', function(){
  this.item = {
    name: '',
    field1: '',
    field2: ''
  };
});
<!DOCTYPE html>
<html ng-app="gemStore">
  <head>
    <link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
    <script type="text/javascript" src="angular.min.js"></script>
    <script type="text/javascript" src="app.js"></script>
  </head>
  <body class="list-group" ng-controller="StoreController as store">
    <header>
      <h1 class="text-center">Flatlander Crafted Gems</h1>
      <h2 class="text-center">– an Angular store –</h2>
    </header>
    <div class="list-group-item" ng-repeat="product in store.products">
      <h3>
        {{product.name}}
        <em class="pull-right">{{product.price | currency}}</em>
      </h3>
 
      <!-- Image Gallery  -->
      <div class='gallery' ng-show="product.images.length" ng-controller="GalleryController as gallery">
        <img ng-src="{{product.images[gallery.current]}}" />
        <ul class="list-inline thumbs">
          <li class="thumbnail" ng-repeat="image in product.images">
            <img ng-src="{{image}}" />
          </li>
        </ul>
      </div>
 
      <section class="tab" ng-controller="TabController as tab">
        <ul class="nav nav-pills">
          <li ng-class="{ active: tab.isSet(1) }">
            <a href ng-click="tab.setTab(1)">Description</a></li>
          <li ng-class="{ active: tab.isSet(2) }">
            <a href ng-click="tab.setTab(2)">Specs</a></li>
          <li ng-class="{ active: tab.isSet(3) }">
            <a href ng-click="tab.setTab(3)">Reviews</a></li>
        </ul>
        <div ng-show="tab.isSet(1)">
          <h4>Description</h4>
          <blockquote>{{product.description}}</blockquote>
        </div>
        <div ng-show="tab.isSet(2)">
          <h4>Specs</h4>
          <blockquote>Shine: {{product.shine}}</blockquote>
        </div>
        <div ng-show="tab.isSet(3)">
          <h4>Reviews</h4>
        </div>
      </section>
    </div>
  </body>
</html>
(function() {
  var app = angular.module('gemStore', []);
 
  app.controller('StoreController', function(){
    this.products = gems;
  });
 
  app.controller('TabController', function(){
    this.tab = 1;
 
    this.setTab = function(newValue){
      this.tab = newValue;
    };
 
    this.isSet = function(tabName){
      return this.tab === tabName;
    };
  });
 
  app.controller('GalleryController', function(){
    this.current = 0;
    this.setCurrent = function(newGallery){
      this.current = newGallery || 0;
    };
  });
 
  var gems = [
      {
        name: 'Azurite',
        description: "Some gems have hidden qualities beyond their luster, beyond their shine... Azurite is one of those gems.",
        shine: 8,
        price: 110.50,
        rarity: 7,
        color: '#CCC',
        faces: 14,
        images: [
          "images/gem-02.gif",
          "images/gem-05.gif",
          "images/gem-09.gif"
        ],
        reviews: [{
          stars: 5,
          body: "I love this gem!",
          author: "joe@example.org",
          createdOn: 1397490980837
        }, {
          stars: 1,
          body: "This gem sucks.",
          author: "tim@example.org",
          createdOn: 1397490980837
        }]
      },
      {
        name: 'Bloodstone',
        description: "Origin of the Bloodstone is unknown, hence its low value. It has a very high shine and 12 sides, however.",
        shine: 9,
        price: 22.90,
        rarity: 6,
        color: '#EEE',
        faces: 12,
        images: [
          "images/gem-01.gif",
          "images/gem-03.gif",
          "images/gem-04.gif",
        ],
        reviews: [{
          stars: 3,
          body: "I think this gem was just OK, could honestly use more shine, IMO.",
          author: "JimmyDean@example.org",
          createdOn: 1397490980837
        }, {
          stars: 4,
          body: "Any gem with 12 faces is for me!",
          author: "gemsRock@example.org",
          createdOn: 1397490980837
        }]
      },
      {
        name: 'Zircon',
        description: "Zircon is our most coveted and sought after gem. You will pay much to be the proud owner of this gorgeous and high shine gem.",
        shine: 70,
        price: 1100,
        rarity: 2,
        color: '#000',
        faces: 6,
        images: [
          "images/gem-06.gif",
          "images/gem-07.gif",
          "images/gem-09.gif"
        ],
        reviews: [{
          stars: 1,
          body: "This gem is WAY too expensive for its rarity value.",
          author: "turtleguyy@example.org",
          createdOn: 1397490980837
        }, {
          stars: 1,
          body: "BBW: High Shine != High Quality.",
          author: "LouisW407@example.org",
          createdOn: 1397490980837
        }, {
          stars: 1,
          body: "Don't waste your rubles!",
          author: "nat@example.org",
          createdOn: 1397490980837
        }]
      }
    ];
})();

Статьи

Example 1

<div ng-controller="MyController">
  Your name:
    <input type="text" ng-model="username">
    <button ng-click='sayHello()'>greet</button>
  <hr>
  {{greeting}}
</div>
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
  $scope.username = 'World';
 
  $scope.sayHello = function() {
    $scope.greeting = 'Hello ' + $scope.username + '!';
  };
}]);

Example 2

<div class="show-scope-demo">
  <div ng-controller="GreetController">
    Hello {{name}}!
  </div>
  <div ng-controller="ListController">
    <ol>
      <li ng-repeat="name in names">{{name}} from {{department}}</li>
    </ol>
  </div>
</div>
angular.module('scopeExample', [])
.controller('GreetController', ['$scope', '$rootScope', function($scope, $rootScope) {
  $scope.name = 'World';
  $rootScope.department = 'Angular';
}])
.controller('ListController', ['$scope', function($scope) {
  $scope.names = ['Igor', 'Misko', 'Vojta'];
}]);

Фильтры обрабатывают информацию и выдают определённые наборы данных, основываясь на какой-либо логике. Это может быть что угодно, от форматирования даты в читаемый формат, до списка имён, которые начинаются на заданную букву. Посмотрим на популярные встроенные фильтры.

Аргументы в фильтр передаются через : двоеточия
Фильтр это обычный метод контролера и может создаваться без специализированного метода .filter()
  • limitTo - Ограничивает количество выводимых данных
  • uppercase
  • date:"MM/dd/yyyy @ h:mma"
  • orderBy - Сортирует выводимые данные

https://docs.angularjs.org/guide/filter

var app = angular.module('myApp', []);
 
app.conroller('myAppConroller', function(){
  this.items = items;
});
 
var items = {
  name: '',
  price: '',
  description: '',
  canPurchase: false,
  soldOut: true,
}

limitTo

Обычно применяется совместно с директивой ng-repeat

<ul>
  <li ng-repeat="user in users | limitTo:10">
    {{ user.name }}
  </li>
</ul>

Custom filter

<div ng-app="myApp">
  <div ng-controller="myAppConroller as controller">
    <div ng-repeat="league in game.leagues | orderByPopular:game.name">
    </div>
  </div>
</div>
//Собственно сам фильтр для angular
board.filter('orderByPopular', function () {
    return function (items, sport) {
        var filtered = [];
        angular.forEach(items, function (item) {
            filtered.push(item);
        });
        switch (sport) {
            case('Basketball'):
                sortAll(filtered, sortBasketball);
                break;
            case('Ice Hockey'):
                sortAll(filtered, sortIceHockey);
                break;
            case('Soccer'):
                sortAll(filtered, sortSoccer);
                break;
            case('Tennis'):
                sortAll(filtered, sortTennis);
                break;
        }
 
        return filtered;
    };
});

Привязка данных

  • ng-bind: осуществляет привязку к свойству innerText html-элемента
  • ng-bind-html: осуществляет привязку к свойству innerHTML html-элемента
  • ng-bind-template: аналогична ng-bind за тем исключением, что позволяет установить привязку сразу к нскольким выражениям
  • ng-model: создает двустороннюю привязку
  • ng-non-bindable: определяет участок html-кода, в котором привязка не будет использоваться

View / Представление

  • Все загруженные шаблоны хранятся в $templateCache в течение всей жизни приложения.
{
  template: [
    '<div>',
      '<ul>',
        '<li ng-repeat="item in vm.items">',
          '{{ item }}',
        '</li>',
      '</ul>',
    '</div>'
  ].join('')
}
{
  templateUrl: './partials/items.html'
}

Angular сначала поищет в DOM элемент <script> с подходящим id, а если не найдёт, тогда запросит документ через HTTP GET.

<script type="text/ng-template" id="/hello.html">
  <div>
    <ul>
      <li ng-repeat="item in vm.items">
        {{ item }}
      </li>
    </ul>
  </div>
</script>