Открыть меню    

angular 2, angular 4

angular.io docs ts latest guide/

@angular/core

Возможности import рассмотрим на примере:

import {
    Component,
    Pipe,
    Directive,
    NgModule,
    Input,
    Output,
    ViewEncapsulation,
    EventEmitter,
    PipeTransform,
    OnInit,
    HostListener
} from '@angular/core';

Модули

Angular 2 состоит из модулей. Приложение на angular 2 также является модулем.

Компоненты

Компоненты отвечают за внешний вид и за взаимодействие с пользователем.

Компоненты представляют основные строительные блоки приложения Angular 2. Каждое приложение Angular имеет как минимум один компонент.

Компоненты представляют из себя часть пользовательского интерфейса.

Идея компонентов состоит в том, чтобы разделить пользовательские интерфейсы на составные части.

При создании компонентов имена тегов в свойстве selector должны подчиняться следующим правилам:
1. слова разделяться дефисом
2. желательно не использовать заглавные буквы
3. обязателен закрывающий тег
<custom-comp></custom-comp>

Директивы

Директивы - можно представить как пользовательские атрибуты в HTML, которые позволяют добавлять элементам новый функционал. Директивы те же компоненты, но без представлений. Если же у директивы есть шаблон, то она становится компонентом.

Структурная директива (на это указывает *), которая меняет DOM - (например, ngFor - добавляет элементы)

<todo-item *ngFor="let todo of todos" 

Атрибутные директивы (на это указывает []) предназначены для изменения внешнего вида или поведения элементов (они не создают и не удаляют элементы, например, [ngClass])

<div class="todo-item"  [ngClass]=" { 'completed' : todo.completed } ">
  • *ngIf - удаляет или создает часть дерева DOM на основании выражения.
  • *ngFor
  • [ngStyle]
  • [ngClass]
  • [ngSwitch]
  • ngSwitchWhen]
  • [ngSwitchDefault]

Свойство selector позволяет определить к какому DOM-элементу или компоненту применить директиву. Свойство selector:

// Custom Directives
@Directive({
    // нам нужно придать поведение, например, компоненту с атрибутом [task]
    selector: '[task]'
})
class TaskMyDirective {
    private defaultMyText: string;
    //...

Пользовательские директивы

Импортируем класс Directive

import {
    Directive,

} from '@angular/core';

@HostListener - с помощью данного декоратора можно подключить обработчики событий, возникающие во вмещающем компоненте.

@HostListener('mouseover')
onMouseOver() {
    //toDO
}

Фильтры (pipes)

Фильтры - так называемые 'помощники', которые форматируют вывод данных в шаблонах в зависимости от наших потребностей.

<h1> {{ minutes }}:{{ seconds | number: '2.0' }} </h1>
  • uppercase
  • lowercase
  • number
  • percent
  • currency
  • slice
  • date
  • json
  • replace
  • i18nPlural - число по объекту в строку
  • i18nSelect - анализирует строку
  • async - наблюдает за асинхронными данными

Пользовательские фильтры

Импортируем декоратор pipe и интерфейс PipeTransform

import {
    Pipe,
    PipeTransform
} from '@angular/core';

Реализуем класс:

@Pipe({
    name: 'nameFilter',
    pure: false // если false, то фильтр будет следить за изменением состояния
})

Обязательный метод класса transform имеет два параметра:

  • 1 - входные данные
  • 2 - параметры для настройки фильтра

И возвращает преобразованные данные

@Pipe({
    name: 'componentFormattedTime'
})
class FormattedTimePipe implements PipeTransform {
    transform(totalMinutes: number): string {
        let minutes: number = totalMinutes % 60;
        let hours: number = Math.floor(totalMinutes / 60);
        return `${hours}h:${minutes}m`;
    }
}

В шаблоне:

<p>{{ 90 | componentFormattedTime }}</p>
@NgModule({
    imports: [BrowserModule],
    declarations: [
        //...
        FormattedTimePipe,
        //...
    ],
    bootstrap: [MyComponent],
})

Атрибуты

[] - сообщают феймворку, что атрибут является входным свойством.

Если требуется связать свойство с переменной компонента, то: [my_prop]="{{valueProp}}".

<countdown
    [seconds]="25">
</countdown>
class CountdownComponent {
    @Input() seconds: number;
    //...

() - сообщают феймворку, что атрибут является выходным свойством, запускающее подключенный к нему обработчик событий.

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

<!-- свойство todo отправляется в компонент todo-item -->
   <todo-item *ngFor="let todo of todos" [todo]="todo"     ....

Привязка данных: Шаблонные теги

Шаблонные теги (интерполяция) - один из видов привязки данных

Пример:

<!-- Шаблонные теги (интерполяция) - один из видов привязки данных -->
<i>
    {{ todo.completed ? 'check_box' : 'check_box_outline_blank' }}
</i>

Привязка данных: через свойство DOM-элемента

Пример:

<i class="material-icons" [innerText] = "todo.completed ? 'check_box' : 'check_box_outline_blank'" >
</i>

Привязка события (event binding)

<button class="checkbox icon" (click)="toggle()">
    Hello
</button>

TypeScript

Интерфейс - описание формы объекта

interface ITodo {
    title: string;
    completed: boolean;
}

todo: ITodo
//Привести пустой объект к типу интерфейса Task
this.Task = <Task>{ };

Классы отличаются от интерфейсов тем, что на основе классов мы можем создать объект.

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

Имена классов определяются в стиле UpperCamelCase с добавлением суффикса, указывающего на его тип (компонент, директива, фильтр и т.д.)

Отметим некоторые неочевидные моменты в TS:

Необязательные параметры в функциях

Добавим символ ? в конце параметра, сделаем такой параметр необязательным.

function greetMe(name: string, greeting?: string): string {
    return greeting ? greeting : 'Hello' + ', ' + name;
}

Формы

Для работы с формами используется модуль:

import { FormsModule } from '@angular/forms'; // импортируем модуль для работы с формами

Благодаря модулю FormsModule мы можем использовать ngModel для привязки к свойству, ngSubmit:

<!-- #todoForm="ngForm" : этим angular поместит в переменную todoForm объект формы  -->
<form class="todo-form" (ngSubmit)="create(); todoForm.reset()" #todoForm="ngForm">
    <input   name="title"
                [(ngModel)]="newTodoTitle"
                type="text"
                placeholder="Что нужно сделать?"
                required >
    <button type="submit" [disabled]="todoForm.form.invalid">
        Добавить
    </button>
</form>
export class AppComponent {
    newTodoTitle: string = '';
    // с использования модуля от angular FormsModule
    // (привязка по ngModel), а также использование (ngSubmit)
    create() {
        let todo: Todo = new Todo(this.newTodoTitle);
        this.todos.push(todo);
        this.newTodoTitle = '';
    }
}

Директива NgForm

Директива NgForm - отслеживает состояние всех элементов формы.

Директива NgModel

Директива NgModel создает экземпляр FormControl из модели и связывает его с элементом формы.

В формах оставлена двусторонняя привяка при помощи Директивы NgModel.

[(ngModel)] - указывает на строковое свойство компонента, обеспечит обновление модели в обоих направлениях (иначе говоря, двусторонняя привязка данных).

    {{title}}
    <input name="title"
           [(ngModel)]="title"
           type="text"
           required />

Валидация и NgModel

NgModel

<input [(ngModel)]="name" #ctrl="ngModel" required>

<p>Value: {{ name }}</p>
<p>Valid: {{ ctrl.valid }}</p>

<p *ngIf = "ctrl.valid" > Valid ok  </p>

Валидация при помощи valueChanges и statusChanges

Более реактивную валидацию можно реализовать при помощи valueChanges и statusChanges.

Они оба возвращают Observable:

//loginForm: ControlGroup
const email = this.loginForm.controls['email'];
email.valueChanges.subscribe(value => {
    this.emailValid = (email.dirty && value.indexOf('@') < 0);
});

valueChanges

Объект FormControl

FormControl

FormControl один из трех фундоментальных строительных блоков форма Angular, помимо FormGroup и FormArray.

Чтобы сообщить Angular о том, что input связан с name FormControl в классе (reactive-forms#create-the-template), вам потребуется в шаблоне воспользоваться директивой formControl, в angular 2 - ngControl.

export class HeroDetailComponent1 {
    name = new FormControl();
}
<input class="form-control" [formControl]="name">
  • Первый аргумент - значение
  • Второй аргумент - функция-валидатор
const ctrl = new FormControl('', Validators.required);
console.log(ctrl.value);     // ''
console.log(ctrl.status);   // 'INVALID'

FormGroup

FormGroup

FormBuilder

Класс FormBuilder обеспечиват большую гибкость при создании сложных форм внутри контроллера компонента.

FormBuilder

<form [formGroup]="heroForm" novalidate>

Как видите ниже FormGroupDirectiver связывает существующую FormGroup с DOM элементом (в Angular 2 использовалась ngForModel).

import { Component }  from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { states } from './data-model';

export class HeroDetailComponent4 {
  heroForm: FormGroup;
  states = states;

  constructor(private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.heroForm = this.fb.group({
      name: ['', Validators.required ],
      street: '',
      city: '',
      state: '',
      zip: '',
      power: '',
      sidekick: ''
    });
  }
}

Пользовательская валидация

Формы в angular 2 можно создать, используя несколько подходов, например, императивный или декларативный.

Двунаправленное связывание (Two-way binding ( [(...)] ))

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

Элемент принимает комбинацию из настройки специфического свойства и прослушивает события элемента.

Для этих целей у ангуляра есть специальное двунаправленное связывание: [(x)].

У свойства [(x)] будет соответствующее событие xChange.

Двунаправленное связывание (Two-way binding ( [(...)] ))

//todo-list.components.ts (родитель)

sizeInToDo: number;

ngOnInit() {
    this.sizeInToDo = 0;
}
<todo-item[(size)]="sizeInToDo"></todo-item>
//todo-item.components.ts (потомок)
@Input() size: number | string;
@Output() sizeChange = new EventEmitter();

dec() {
    this.resize(-1);
}
inc() {
    this.resize(+1);
}

resize(delta: number) {
    this.size = +this.size + delta;
    this.sizeChange.emit(this.size);
}
<button (click) = "dec()">dec(-)</button>
<button (click) = "inc()">inc(+)</button>

Декомпозиция

Процесс разделения проекта на части или компоненты называется декомпозицией.

Взаимодействие компонентов

<todo-item *ngFor="let todo of todos" [todo]="todo"></todo-item>

Свойство todo будет доступно в компоненте todo-item

Декоратор

Декоратор - особенность, появившаяся в ES7, и затем добавленная в TypeScript, позволяющая добавлять метаданные в классы.

Все декораторы узнаются по префиксу @

Декортатор Input

Декортатор Input указывают, какие свойства вы можете установить на компоненте.

В самом todo-item импортируем декортатор Input (им помечаются входные данные) -

<todo-item *ngFor="let todo of todos" [todo]="todo" 
 { Component, Input } from '@angular/core';

Используем в компоненте:

export class TodoItemComponent {
    //Декоратором @Input помечаются входные данные
    @Input() todo: Todo;

}

При удалении нужно передать данные от родителя потомку ((delete)="delete($event)") - один из способов это события (можно подписаться на события пользовательских компонентов).

<div class="todo-list" *ngIf="todos.length > 0">
    <todo-item *ngFor="let todo of todos" [todo]="todo" (delete)="delete"></todo-item>
    <!-- (delete) привязываемся к событию
        ="delete" - метод у родительскокого компонента, который необходимо вызвать при событии delete
    -->
</div>

декоратор Output (EventEmitter)

В дочернем импортируем декоратор Output (им помечаются выходные данные)

Или Output идентифицируют события, которые компонент может инициировать для отправки информации по иерархии родительскому элементу.

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


import { Component, Input, Output, EventEmitter } from '@angular/core';

Класс EventEmitter предназначен для объектов способных генерировать события. Также эти объекты предоставляют интерфейс для подписки на эти события.

Пример 2

От ребенка (todo-item.component) родителю (todo-list.component.html)

<!-- todo-item.component.html -->
<div class="todo-item"  [ngClass]=" { 'completed' : todo.completed } ">
    <button class="checkbox icon" (click)="onToggle()">
export class TodoItemComponent {
    @Output() toggle = new EventEmitter();

    onToggle() {
        this.toggle.emit(this.todo);
    }
<!-- todo-list.component.html -->
<div class="todo-list" *ngIf="todos.length --> 0"-->
    <todo-item *ngFor="let todo of todos" [todo]="todo" (toggle)="toggle($event)"--></todo-item-->
export class TodoListComponent implements OnInit {

    toggle(todo: Todo) {
        this.todoService.toggleTodo(todo);
    }

Класс EventEmitter

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

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

//authentication.service.ts
    userIslogin: EventEmitter<boolean>;
    constructor() {
        this.userIslogin = new EventEmitter();
    }

    login({ username, password }): Promise<boolean> {
        return new Promise(resolve => {
            let validCredentials: boolean = true;

            // toDo check User credentials

            // испускаем событие
            this.userIsloggedIn.emit(validCredentials);
            resolve(validCredentials);
        });
    }

Далее (не забудьте внедрить сервис аутенфикации в нужный компонент) мы уже в компоненте подписываемся (subscribe) на уведомления о входе и выходе пользователя из системы.

userIslogin: boolean;

    constructor(private authenticationService: AuthenticationService) {

        authenticationService.userIslogin.subscribe(userIslogin => {
            this.userIslogin = userIslogin;
        });
    }

Сервисы

Сервисы отвечают за получение, предоставление и работу с данными.

Для того чтобы в нашем сервисе иметь возможность использовать другие сервисы (например, Http) необходимо добавить аннотацию с помощью декоратора injectable.

Проблема: логика по работе с задачами разбросана по компонентам (за добавление отвечает компонент app, удаление - todo-list, выполнение - todo-item).

Одним из вариантов разделения ответственности между различными частями приложения являются сервисы.

Традиционно в сервисы помещается логика, то есть непосредственно работа с данными приложения.

В нашем случае сервис (todo.service.js) будет отвечать за предоставление задач, их добавление и удаление.

Сервисы в angular 2 это простые классы.

Важно: клиенты, которые используют сервис, не знают и не должны знать как сервис получает данные.

Внедрение зависимостей (dependencies injection)

Сервис необходимо внедрить как зависимость, чтобы разные компоненты могли работать с одним и тем же сервисом одновременно.

В angular 2 имеется встроенный механизм внедрения зависимостей.

Внедрить сервис в компонент:

1. Компоненту добавить constructor и указать параметр с типом сервиса

2. Зарегистрировать сервис в приложении (файл app.module.ts):

//app.module.ts
import { TodoService } from './shared/todo.service.ts';

@NgModule({
    // ...
    // в свойстве providers мы регистрируем сервисы
    providers: [TodoService],

    // ...

})

Жизненный цикл компонента

Для решения задач связанных с жизненным циклом компонента angular предоставляет несколько методов: life cycle hooks (крюки жизненного цикла).

Например, ngOnInit (потребуется для сервиса) , интерфейс который называется OnInit и находится в @angular/core

Пример сервиса

todo.service.ts

import { todos } from './data';
import { Todo } from './todo';

export class TodoService {
    todos: Todo[] = todos;

    // возвращает задачи
    getTodos(): Todo[] {
        return this.todos;
    }

    createTodo(title: string) {
        let todo = new Todo(title);
        this.todos.push(todo);
    }

    deleteTodo(todo: Todo) {
        let index = this.todos.indexOf(todo);

        if (index > -1 ) {
            this.todos.splice(index, 1);
        }
    }

    toggleTodo(todo: Todo) {
        todo.completed = !todo.completed;
    }

}

todo-list.component.html

<div class="todo-list" *ngIf="todos.length > 0">
    <todo-item
    *ngFor="let todo of todos"
    [todo]="todo"
    (delete)="delete($event)"
    (toggle)="toggle($event)"></todo-item>
</div>

todo-list.components.ts

// с использованием сервиса
import { Component, Input, OnInit } from '@angular/core';
import { Todo } from '../shared/todo';
//импортируем сервис
import { TodoService } from '../shared/todo.service';

@Component({
    moduleId: module.id,
    selector: 'todo-list',
    templateUrl: 'todo-list.component.html',
    styleUrls: ['todo-list.component.css']
})

export class TodoListComponent implements OnInit {
    todos: Todo[];
    todoService: TodoService;

    // конструктор предназначен для инициализации свойств (если конструктор сработал это еще не значит, что компонент создан и готов к работе)
    constructor(todoService: TodoService) {
        this.todoService = todoService;
        this.todos = [];
    }

    // вызовется в момент инициализации компонента
    ngOnInit() {
        this.todos = this.todoService.getTodos();
    }

    delete(todo: Todo) {
        // от компонента todo-item мы получим задачу, которую дальше отправим в сервис
        this.todoService.deleteTodo(todo);
    }

    // выполнение задачи и далее в сервис
    toggle(todo: Todo) {
        this.todoService.toggleTodo(todo);
    }
}

Локальные ссылки в шаблонах

Идентификаторы с предшествующим символом решетки (#) - это такие локальные имена, которые используются для ссылок на компоненты в представлениях, чтобы в дальнейшем получить к ним доступ.

  <count
    [seconds]="125"
    #counter>
  </count>

{{ counter.seconds }}

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

<p #tooltip >Hello?</p>

Стили компонента

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

1. Свойство styles

Свойство styles декоратора @Component

@Component({
  styles: [`
    h1 {
        color: #900
    }
    p {
        color: #000
    }
  `],

2. Свойство styleUrls

@Component({
        styleUrls: ['path-to-style.css']

3. Внутрення таблица стилей

@Component({
  template: '
    <style>    h1 {
        color: #900
    }</style>
    <h1>Hello, world!</h1>',

http

Общение с сервером происходит в сервисе посредством HTTP.
HTTP это отдельный модуль, который не является частью angular.

Как использовать

1. Необходимо зарегестрировать http-модуль в основном модуле приложения.

//app.module.ts
import { HttpModule } from '@angular/http';

//...

@NgModule({
    imports: [BrowserModule, FormsModule, HttpModule], // что модуль импортирует
//...

2. Далее в сервисе мы можем импортировать объект Http

//todo.service.ts
    import { Http } from '@angular/http';

3. Экземпляр сервиса мы получим через конструктор.


// инициализируем экземпляр Http
constructor(private http: Http) {}
// таким образом экземпляр сервиса Http будет помещен в свойство класса под названием http

Для того чтобы в нашем сервисе (todo.service.ts) иметь возможность использовать другие сервисы необходимо добавить аннтотация с помощью декоратора injectable

// todo.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';

@Injectable()
export class TodoService {
    //..

Благодаря модулю angular-in-memory-web-api можно создать фейковый сервер.

npm i angular-in-memory-web-api --save

Для загрузки модулей мы используем system.js, поэтому в нем (systemjs.config.js) необходимо указать откуда брать модуль angular-in-memory-web-api.

Далее нужно создать класс, который будет являться БД для фейкового сервера.

/shared/data.service.ts

Через сервис http мы будем на сервер отправлять запросы (мы будем работать с restfull api):

  • post - для создания задач
  • delete - для удаления
  • put - для сохранения измененных задач

Для отправки данных на сервер нам нужно будет указать заголовок content-type, для того чтобы сервер знал, что мы ему отправляем JSON.

Для удобства создания заголовком мы импортируем два класса Headers и RequestOptions из Http

//todo.service.ts
import { Http, Headers, RequestOptions } from '@angular/http';

Переходим к запросам

import {RequestOptions, Request, RequestMethod} from '@angular/http';
var options = new RequestOptions({
  method: RequestMethod.Post,
  url: 'https://google.com'
});
var req = new Request(options);
var myHttpRequest = Observable<Response> = http.request(req);

// сокращенная запись:
var myHttpRequest = Observable<Response> = http.post('https://google.com');

//методы класса Http возвращают наблюдаемый поток экземпляров класса Response

myHttpRequest.map(response: Response => response.json())
    .subscribe(data => console.log(data))

Response

Http возвращают наблюдаемый поток экземпляров класса Response.

response.json():

Парсим JSON: Данные в JSON формате. Приложение должно распарсить эти данные в JavaScript объект, вызвав response.json().

https://angular.io/docs/ts/latest/guide/server-communication.html#!#parse-to-json

Ошибки

Для обработок ошибок в angular есть специальный оператор - catch.

myHttpRequest.map(response: Response => response.json())
    .subscribe(data => console.log(data))
    .catch(error: Response => console.error(error));

Внедрение зависимостей

Внедрение зависимостей полагается на список поставщиков (providers) и внедрение через конструктор. Каждый раз когда поставщик находит зависимость, он создает и возвращает одиночный экземпляр этого типа. Основа - фабрика.

Зависимость ищется снизу вверр (от дочернего к родит-му компоненту).

Зависимость можно зарегестрировать на уровне компонета или всего модуля:

@NgModule({
    imports: [BrowserModule],
    providers: [TaskService],

Далее добавляем сервис через конструктор:

export class TodoFormComponent {

//добавим конструктор для того чтобы получить service
constructor(private taskService: TaskService) {

}

Внедрение зависимостей внутрь отдельного компонента

Посредством providers:

@Component({
    providers: [Http],
    selector: '[data-hello]'
})
class MyClass {
data: string;
    consructor(http: Http){
        http.het('googgle.com')
        .map((res: Response) => res.text())
        .subscribe((data: string) => this.data = data)
    }
}

Декортатор @Injectable

import { Injectable } from '@angular/core';

@Injectable()
export default class MyService {
    constructor(myService: MyService) {

    }
    //...

Декортатор @Injectable делает служебные классы видимыми для механизма внедрения зависимостей.

Соглашение об именовании в angular 2

Имя модуля требуется указывать в верблюжьей нотации, а также суффикс типа (например, Pipe): NumberOnlyPipe

Маршрутизация

Routing

<base href='/'> - сообщает браузеру путь, по которому он должен идти, чтобы загрузить внешние стили, катринки и т.д.

Подключаем поставщики, которые понадобятся в дальнейшем для создания экземпляров необходимых для реализации маршрутизации.

import { ROUTER_PROVIDERS, RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated';

@Component({
  selector: 'my-app',
  directives: [ROUTER_DIRECTIVES],
  providers: [ROUTER_PROVIDERS],

Документация с актуальными мудулями: https://angular.io/docs/ts/latest/guide/router.html

Опции маршрута в устаревшей версии прописываются в декораторе:

@RouteConfig([
    {   path: '',
        name: 'Home',
        redirectTo: ['TasksComponent']
    },
    //....

Актуально:

import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard',  component: DashboardComponent },
  { path: 'detail/:id', component: HeroDetailComponent },
  { path: 'heroes',     component: HeroesComponent }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

Директивы RouterOutlet, RouterLink

RouterOutlet - директива (<router-outlet>) станет заполнителем, где роутер отобразит view (при этом все предыдущие компоненты будут удалены).

Активная ссылка с директивой [routerLink] получает класс router-link-active.

Принудительная навигация в компоненте

Как видите, методу navigate передается строка, содержащая полный путь.

gotoDetail(): void {
    this.router.navigate(['/detail', this.selectedHero.id]);
}

Динамические параметры

<button (click)="gotoDetail(i)">View Details</button>
gotoDetail(index: number): void {
//Переходим к компоненту Timer с параметром id
    this.router.navigate(['Timer', { id: index }]);
}

Или

<a *ngFor="let product of products"
  [routerLink]="['/product-details', product.id]">
  {{ product.name }}
</a>

Разбор параметров

Сейчас актуально (https://angular-2-training-book.rangle.io/handout/routing/routeparams.html) посредством сервиса: ActivatedRoute. Deprecated: RouteParams.

... (многоточие)

... (многоточие) в конце маршрута, указывает маршрутизатору Router, что он должен смотреть определение маршрута во вложенном компоненте.

Получаем параметры в компоненте:

// программный переход в
this.router.navigate(['TimerComponent', 'TaskTimer', { id: index }]);
import { RouteParams, CanReuse, OnReuse } from '@angular/router-deprecated';

constructor(
    private routeParams: RouteParams) {
}

ngOnInit(): void {
    let taskIndex = parseInt(this.routeParams.get('id'));

интерфейс CanActivate

интерфейс CanActivate расширяет класс для решения задачи по активации маршрута.

метод canActivate - возвращает логическое значение, указывающее на необходимость активации компонента. Удобно для проверки паролем и т.д.

интерфейс onActivate

Использованы материалы в том числе:
codedojo.ru

Шаблон Observable

Если уже совсем простым языком:

Экземпляр наблюдаемого объекта (observable) имеет подписку (subscribe) с определенным функционалом; наблюдатель (observer) при помощи, например, метода next говорит об изменении состояния наблюдаемого объекта, благодаря чему вызывается функционал из подписки (subscribe) наблюдаемого объекта. Метод next наблюдателя (observer) может передавать параметры, которые затем принимает подписка (subscribe) наблюдаемого объекта (observable).

Observable (наблюдаемый объект) - источник асинхронного события; Observable сообщает об изменении своего состояния объекту - Observer (наблюдатель или подписчик).

В независимости от того переданы данные или нет объект Observable может быть оставлен в любое время(в отличие от тех же Promise).

RxJS - библиотека, необходима для создания Observable-объектов.

В отличие от Promise (где сработает только 1 раз) нижеприведенный код будет работать как задумано (https://jsfiddle.net/3cz80mjn/):


//  в этом примере мы создали наблюдаемый объект и подписались на его события
var observable = Rx.Observable.create(observer => {
    setInterval(() => {
        observer.next('Асинхронная операция');
    }, 1000);
});

observable.subscribe(response => {
    console.log('response: ', response);
})

Observable производят непрерывный поток событий (тоже самое что и коллекция объектов), на которые можно подписать абонентов. Подписчики получают уведомления об этих событиях и реагирует на них. Прежде чем поток достигнет подписанных на него наблюдателей его можно предварительно обработать: при помощи методов, например, map(), filter().

Реактивное программирование - подписка на асинхронные события и преобразование потоков наблюдаемых событий.

Observable с использованием map, filter b subscribe https://jsfiddle.net/dnzl/g2juyk7d/5/

Метод map

Метод map в реактивном программировании аналогичен функциональному методу map:

В методу map результат выполнения callback-функции добавляется в новый массив, который возвращается после последней итерации. Другими словами, результатом метода map всегда является новый массив с результатами выполнения функции callback на исходном массиве.

var nums = [11, 21, 31, 41];
var results = nums.map(function(num, index, arr) {
    return num * 2;
});

// Исходный массив nums не изменяется
console.log(nums); // [11, 21, 31, 41]
// результат выполнения map, записанный в переменную
console.log(results); // [ 22, 42, 62, 82 ]
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);

// теперь roots равен [1, 2, 3], а numbers всё ещё равен [1, 4, 9]
console.log('roots: ', roots); // [ 1, 2, 3 ]
https://jsfiddle.net/y08234mv/1/
var objs = [
    {which: 1},
    {which: 0},
    {data: 0}
];
var objsWithWhich = objs.map(val => val.which);

console.log('objsWithWhich: ', objsWithWhich); // [ 1, 0, undefined ]

В отличие от forEach при использовании map вам становится доступен chaining.

http://jsraccoon.ru/fn-array-methods

Метод filter

Метод filter служит для фильтрации массива по условию, заданным в callback функции. В результате создаётся новый массив, куда добавляются все элементы прошедшие провеку колбэком.

function isBigEnough(value) {
  return value >= 10;
}
var filtered = [1, 5, 8, 13, 454].filter(isBigEnough);

console.log('filtered: ', filtered); // [ 13, 454 ]

Комментарии к статье

Добавить комментарий