{{tag>java-script angular angularjs lessons}}

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

MVC - Java-Script это 

====== APP / Modules ======

  * [[java-script:angularjs:lessons#module|Module]] - Базовый контейнер для app включает в себя controllers, services, filters, directives сконфигурированные Injector
  * [[java-script:angularjs:lessons#service_сервисы|Service]] - Бизнес логика для отображения в views
    * [[java-script:angularjs:lessons#factory|Factory]] - 
    * [[java-script:angularjs:lessons#provider|Provider]] - 
  * Dependency-Injection - Создает ленивые связи с объектами
  * Injector - dependency injection container
  * [[java-script:angularjs:lessons#view_представление|View]] - HTM представление (может содержать ng дериктивы)
    * Template - HTML шаблон
      * [[java-script:angularjs:lessons#директивы|Directives]] - extend HTML with custom attributes and elements
      * Markup - Обработка шаблона {{ }}
      * [[java-script:angularjs:lessons#filters|Filter]] - Обработка данных перед выводом
      * [[java-script:angularjs:lessons#form|Form]] controls - Angular автоматически обрабатывает формы
  * Compiler - 	parses the template and instantiates directives and expressions
  * [[java-script:angularjs:lessons#controller|Controller]] - the business logic behind views
    * [[java-script:angularjs:lessons#behavior|Behavior]] - Функции внутри контролера
    * Model - Данные содержащиеся в контролере
    * [[java-script:angularjs:lessons&#scope|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

===== Module =====


<code html>
<div ng-app="myApp">
</div>
</code>

<code javascript>
var app = angular.module('myApp', []);
</code>

===== Директивы =====

<note tip>Директивы при создании всегда именуются с использованием lowerCamelCase. При использовании директиву необходимо именовать в нижнем регистре с использованием в качестве разделителя одного из спец символов: :, -, или _. По желанию для получения валидного кода можно использовать префиксы x- или data-. Примеры: tb:tooltip, tb-tooltip, tb_tooltip, x-tb-tooltip и data-tb-tooltip.</note>

==== 4 способа задания директив ====

<note tip><code html><my-element></my-element>

<div my-element></div>

<div class="my-element"></div>

<!-- directive: my-element --></code></note>

==== Ограничение / restrict ====

При указании restrict: "A", данная директива будет доступна только для аттрибутов, те <div my-directive></div>

  * E - для элементов
  * A - для атрибутов
  * C - для классов
  * М - для комментариев

==== Фазы работы директивы ====

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

[[http://jsfiddle.net/vojtajina/8yzbZ/|Последовательность выполнения фаз]]

==== Встроенные директивы ====

  * 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

<code html>
<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>
</code>


==== API Директив ====

  * [[java-script:angularjs:diretive:api]]

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

  * [[http://habrahabr.ru/post/260559/|Директива AngularJS для запоминания e-mail]]

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

  * https://github.com/simpulton/angular-dynamic-templates
==== Расширения ====

  * https://github.com/angular-ui
  * https://github.com/andreev-artem/angular_experiments ([[http://andreev-artem.github.com/angular_experiments/index.html|Демонстрация]])
  * http://ngmodules.org/tags/directives

==== Статьи ====

  * [[http://habrahabr.ru/post/179755/|Директивы в Angularjs для начинающих. Часть 1]]
  * [[http://habrahabr.ru/post/180365/|Директивы в Angularjs для начинающих. Часть 2]]
  * [[http://habrahabr.ru/post/164493/|Директивы в AngularJS]]

===== Service / Сервисы =====

{{:java-script:angularjs:concepts-module-service.png|}}

<code javascript>
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
  };
});
</code>

<code javascript>
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!");
  };
}]);
</code>

<code html>
<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>
</code>

==== Пример ====

<code javascript>
app.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, service!"
    };
});
</code>

===== Factory =====

<code javascript>
app.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, Factory!"
        }
    };
});
</code>

===== Provider =====

<code javascript>
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;
    };
});
</code>
===== Controller =====

{{:java-script:angularjs:concepts-databinding2.png|}}

<code html>
<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>
</code>

<note tip>Алиас **invoce** работает только для view</note>

<code javascript>
var app = angular.module('myApp', []);

app.conroller('invoceController', function(){
  this.item = {
    name: '',
    field1: '',
    field2: ''
  };
});
</code>

==== Behavior ====

<code html>
<!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>
</code>

<code javascript>
(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
        }]
      }
    ];
})();
</code>
==== Scope ====

{{:java-script:angularjs:atagg.png?|}}

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

=== Статьи ===

  * [[http://habrahabr.ru/post/182670/|Понимание областей видимости или Scope в AngularJS]]

=== Example 1 ===


<code html>
<div ng-controller="MyController">
  Your name:
    <input type="text" ng-model="username">
    <button ng-click='sayHello()'>greet</button>
  <hr>
  {{greeting}}
</div>
</code>

<code javascript>
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
  $scope.username = 'World';

  $scope.sayHello = function() {
    $scope.greeting = 'Hello ' + $scope.username + '!';
  };
}]);
</code>

=== Example 2 ===

<code html>
<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>
</code>

<code javascript>
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'];
}]);
</code>


==== Filters ====

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

<note tip>Аргументы в фильтр передаются через : двоеточия</note>

<note tip>Фильтр это обычный метод контролера и может создаваться без специализированного метода .filter()</note>

  * limitTo - Ограничивает количество выводимых данных
  * uppercase
  * date:"MM/dd/yyyy @ h:mma"
  * orderBy - Сортирует выводимые данные
  * [[java-script:angularjs:lessons&#custom-filters|custom filters]]

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

<code javascript>
var app = angular.module('myApp', []);

app.conroller('myAppConroller', function(){
  this.items = items;
});

var items = {
  name: '',
  price: '',
  description: '',
  canPurchase: false,
  soldOut: true,
}
</code>

=== limitTo ===

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

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

=== Custom filter ===

<code html>
<div ng-app="myApp">
  <div ng-controller="myAppConroller as controller">
    <div ng-repeat="league in game.leagues | orderByPopular:game.name">
    </div>
  </div>
</div>
</code>

<code javascript>
//Собственно сам фильтр для 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;
    };
});
</code>

===== APP =====

  * [[http://angularlight.org/|MVVM web interfaces/applications. Angular.js + Knockout.js way.]]


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

===== Bind =====

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

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

===== Form =====

  * [[java-script:angularjs:lessons:form]]
===== Шаблонизация и импорт HTML =====

  * Все загруженные шаблоны хранятся в $templateCache в течение всей жизни приложения.

===== template =====


<code javascript>
{
  template: [
    '<div>',
      '<ul>',
        '<li ng-repeat="item in vm.items">',
          '{{ item }}',
        '</li>',
      '</ul>',
    '</div>'
  ].join('')
}
</code>

===== templateUrl =====

<code javascript>
{
  templateUrl: './partials/items.html'
}
</code>

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

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