FLI

Инфо

Поток
Показаны сообщения с ярлыком знания. Показать все сообщения
Показаны сообщения с ярлыком знания. Показать все сообщения

Двустороннее связывание данных в Angular 2

Двустороннее связывание по-прежнему доступно в Angular 2 и ngModel делает его простым. Синтаксис является комбинацией из [input] и (output) синтаксиса для передачи данных в разных направлениях.

Итак, мы добавили код, для передачи сообщения через @Input, но теперь мы будем использовать ngModel нашего <input> элемента. Это выглядит как [(ngModel)] в квадратных скобках. Эта комбинация используется для двустороннего связывания, круглые скобки обозначают передачу значения наружу, квадратные скобки - передача внутрь через @Input.

simple-form.component.ts

@Component({
  selector: 'app-simple-form',
  template: `<div>
{{message}}
<input #myInput type="text" [(ngModel)]="message">
<button (click)="onClick($event, myInput.value)">Нажми меня!</button>
</div>`,
  styles:[]
})

Можно воспринимать [(...)] как явное указание на двустороннее связывание. При изменении сообщения снаружи, новое значение сразу отобразится в <input>. Также при изменении значения <input>, значение переменной message обновится.

Работу байндинга можно легко увидеть на странице с примером. Просто нужно ввести текст в поле ввода и значение {{message}} тут же обновится.

Чтобы проверить привязку с другой стороны, добавим в конструктор setInterval, и будем изменять значения this.message как Math.random().toString() каждую секунду.

simple-form.component.ts

export class SimpleFormComponent implements OnInit {
  @Input() message;
  onClick(event, value) {
    console.log(event);
    console.log(value);
  }
  constructor() {
    setInterval(()=> this.message = Math.random().toString(), 1000);
  }
  ngOnInit(){ }
}

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

Передача значений в компоненты через @Input

Вместо того, чтобы создавать список элементов, мы можем использовать наш app-simple-form элемент. Временно удалим {{message}}.

app.component.ts
@Component({
  selector: 'app-root',
  template: `<div>
<ul>
  <app-simple-form *ngFor="let message of mail.messages">
  </app-simple-form>
</ul>
</div>`
})
Сохраним файл. И теперь для каждого сообщения будет создана форма в браузере. Внутри нашей формы добавим входной параметр для сообщения, через декоратор @Input.

simple-form.component.ts
@Component({
  selector: 'app-simple-form',
  template: `<div>
{{message}}
<input #myInput type="text">
<button (click)="onClick($event, myInput.value)">Нажми меня!</button>
</div>`,
  styles: []
}) 
export class SimpleFormComponent implements OnInit {
  @Input() message;
  onClick(event, value){
    console.log(event);
    console.log(value);
  }
  constructor() { }
  ngOnInit() {
  }
}
Теперь мы можем вывести сообщение над полем ввода. Для этого будем использовать знакомый нам синтаксис с фигурными скобками. Также добавим атрибут [message]. Квадратные скобки необходимы для передачи значения в компонент в одном направлении. Компонент получит значение и отобразит его в шаблоне.

app.component.ts
@Component({
  selector: 'app-root',
  template: `<div>
<ul>
  <app-simple-form
    *ngFor="let message of mail.messages"
    [message]="message"
  >
  </app-simple-form>
</ul>
</div>`
})
Каждый раз, когда мы хотим передать значение в компонент, мы можем использовать синтаксис квадратных скобок для атрибута. Имя атрибута может быть любим, это же имя должно быть указано в конфигурации компонента с декоратором @Input().

Цикл ngFor в Angular 2

Этот пост охватывает циклы в шаблонах Angular 2 через *ngFor. Это почти тоже самое, как и ng-repeat в AngularJS, но с небольшими различиями в синтаксисе.

Что же, начнем с добавления сообщений в наш MailService. Создадим простой массив и добавим тестовые сообщения: 'Новое сообщение!',  'Сообщение было удалено' и 'Добавить отзыв'.

mail.service.ts

@Injectable()
export class MailService {
  messages = [
    `Новое сообщение!`,
    `Сообщение было удалено`,
    `Добавить отзыв`
  ]
  constructor() { }
}

Эти сообщения из нашего MailService мы можем вывести в app.component. Очистим шаблон для компонента и просто добавим mail сервис в конструктор.

app.component.ts

@Component({
  selector: 'app-root',
  template: ``
})
export class AppComponent {
  constructor(
    @Inject('mail') private mail
  ){}
}

Также, добавим ненумерованный список с элементами внутри. Мы хотим создать элемент списка для каждого сообщения, которые у нас есть. Для этого пропишем в шаблоне *ngFor. F должна быть заглавная. Затем, необходимо указать значение атрибута let message of mail.messages. mail - это mail сервис c нашими сообщениями, которые мы добавили.

app.component.ts

template: `<div>
<ul>
  <li *ngFor="let message of mail.messages">
    {{message}}
  </li>
</ul>
</div>`

Теперь переменная message может быть использована внутри цикла для каждого сообщения в списке. Просто выведем ее {{message}} в скобках и сохраним файл. Сообщения отобразятся списком на странице браузера.

Возможно, вам будет интересно зачем нужна звездочка *. Этот синтаксис просто указывает на то, что родительский элемент будет использоваться как шаблон в цикле. И данные просто подставятся в него. ngFor является структурной директивой, которая создает указанные элементы и помещает в них данные.

Настройка провайдеров в Angular 2

TypeScript повсеместно используется при создании Angular 2 приложений. Мы прописываем include для внедрения зависимостей. Если мы хотим использовать сервисы без include в компонентах, мы должны изучить декоратор @Inject. Данный декоратор позволяет внедрять любое значение или объект, без необходимости создания сервиса.

В нашем приложении мы добавили провайдер для MailService, и в компоненте AppComponent внедрили приватный параметр mail c типом MailService.

app.module.ts

@NgModule({
  declarations: [
    AppComponent,
    SimpleFormComponent
  ],
  imports: [
    BrowserModule,
    FomrsModule,
    HttpModule
  ],
  providers: [MailService],
  bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
export class AppComponent {
  title = `Hello world`;
  constructor(private mail:MailService){ }
}

Тоже самое можно сделать через конфигурационный объект. То есть передать в провайдер объект с ключом provide плюс значение. Добавим значение 'mail', и еще один ключ useClass:MailService.

app.module.ts

providers: [{provide:'mail', useClass:MailService}]

Теперь в AppComponent, вместо внедрения зависимости по типу, мы можем использовать декоратор inject. Необходимо убедиться, чтобы данный декоратор был подключен.

app.component.ts

export class AppComponent {
  title = `Hello world`;
  constructor(@Inject('mail') private mail){ }
}

Сервис mail подключается через значение 'mail', которое мы указали в провайдере. Класс MailService будет подставлен автоматически. И теперь нам не нужно явно прописывать include для него в компоненте. Angular знает, что необходимо взять класс из провайдеров, создать его сущность и подставить в наш код. После сохранения изменений, все будет работать по-прежнему.

Настройка провайдеров, также может пригодиться для предоставления значений. Например, путь для API запросов. Добавим провайдер provide: 'api' и передадим useValue: 'http//localhost:3000/', или что угодно.

app.module.ts

providers: [
  {provide:'mail', useClass:MailService},
  {provide: 'api', useValue: 'http://localhost:3000/'}
  ],

Теперь мы можем использовать значение API там, где нам нужно. Добавим api в конструктор и выведем значение в шаблоне через синтаксис {{api}}. Сохраним файл.

app.component.ts
@Component({
  selector: 'app-root',
  template: `<div>
<app-simple-form></app-simple-form>
{{mail.message}}
<hr>
{{api}}
</div>`
})
export class AppComponent {
  title = `Hello world`;
  constructor(
    @Inject('mail') private mail,
    @Inject('api') private api,
    ){ }
}

Таким образом, мы можем конфигурировать провайдеры через useClass, useValue, useFactory и тд. А также, использовать их во всем нашем приложении.

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

Из этого урока мы узнаем как создавать сервисы в Angular 2 для общего использования. А также, познакомимся с внедрением зависимостей - Dependency Injection.

Начнем. Используем Angular CLI для генерации нового сервиса. Сервис можно создать при помощи команды service или s. Также, необходимо указать имя сервиса через пробел. Назовем его mail. После выполнения команды, будет сгенерировано два файла. Наш mail.service и файл spec для тестов. В терминале будет предупреждение о том, что сервис сгенерирован, но не добавлен для использования в приложении.

Angular CLI

$ ng g s mail

Пойдем дальше и добавим его. Для этого необходимо в файле app.module.ts указать провайдер MailService и сделать импорт данного сервиса.

app.module.ts

import { MailService } from './mail.service'
@NgModule({
  declarations: [
    AppComponent,
    SimpleFormComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [MailService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Теперь MailService доступен для использования в приложении. Мы можем добавить его в конструктор  компонента AppComponent. Добавим параметр private mail:MailService и импорт самого сервиса. Необходимо проверить, чтобы импорт выполнялся из правильного файла.

app.component.ts

import { MailService } from './mail.service'
@Component({
  selector: 'app-root',
  template: `<div>
<app-simple-form></app-simple-form>
</div>`
})
export class AppComponent {
  title = `Hello World`;
  constructor(private mail:MailService){}
}

После этого, все данные из mail.service.ts доступны для приложения. Откроем наш сервис и добавим поле message с текстом 'Новое сообщение!'.

mail.service.ts

import { Injectable } from '@angular/core';
@Injectable()
export class MailService {
  message = `Новое сообщение!`;
  constructor() { }
}

Вернемся в компонент. Под нашей простой формой выведем сообщение из сервиса.

app.component.ts

@Component({
  selector: 'app-root',
  template: `<div>
<app-simple-form></app-simple-form>
{{mail.message}}
</div>`
})

Сохраним изменения. После обновления в браузере, мы увидим наше сообщение под формой. Таким образом мы можем обмениваться данными в нашем приложении.

Обработка Angular 2 событий через $event

Этот урок покажет нам преимущества использования Angular 2 синтаксиса для обработки событий. А так же получение доступа к объекту события, через знакомый нам из angularjs синтаксис $event.

Если нам нужно получить, например, событие MouseEvent, мы можем использовать $event синтаксис. Тот же, который мы использовали в Angular 1. Объект события просто передается через эту переменную.

simple.form.component.ts

@Component({
  selector: 'app-simple-form',
  template: `<div>
<input #myInput type="text">
<button (click)="onClick($event)">Нажми меня!</button>
</div>`,
  styles: []
})
export class SimpleFormComponent implements OnInit {
  onClick(value) {
    console.log(value);
  }
  constructor() { }
  ngOnInit() {
  }
}

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

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

simple.form.component.ts

@Component({
  selector: 'app-simple-form',
  template: `<div>
<input #myInput type="text">
<button (click)="onClick($event, myInput.value)">Нажми меня!</button>
</div>`,
  styles: []
})
export class SimpleFormComponent implements OnInit {
  onClick(event, value) {
    console.log(event);
    console.log(value);
  }
  constructor() { }
  ngOnInit() {
  }
}

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

Это работает со всеми DOM событиями. К примеру, если заменить click на mouseover для onClick обработчика. Сохранить файл. То каждый раз при наведении курсора на кнопку button, мы увидим, что обработчик срабатывает.

Работа с Angular 2 элементами через события и ссылки

В нашем шаблоне simple form заменим разметку на div, который содержит input и button теги внутри. Текст кнопки 'Нажми меня!'. После сохранения и обновления страницы браузера нам будет доступны поле ввода и кнопка.

simple-form.component.ts
@Component({
  selector: 'app-simple-form',
  template: `<div>
<input type="text">
<button>Нажми меня!</button>
</div>`,
  styles: []
})
Для обработки нажатия на кнопку, необходимо указать название события и поместить его в круглые скобки, пример (click). Далее необходимо присвоить данному обработчику метод класса нашего компонента. Назовем метод onClick.

simple-form.component.ts
<button (click)="onClick()">Нажми меня!</button>
В нашем классе добавим метод onClick и просто вызовем console.log( 'clicked!' ) в теле. Сохраним код. Теперь после нажатия на кнопку, в консоль будет выводится текст 'clicked!'.

simple-form.component.ts
export class SimpleFormComponent implements ngOnInit {
  onClick(){
    console.log('clicked!');  // clicked!
  }
  constructor() { }
  ngOnInit() {
  }
}
Этот синтаксис оборачивание имени события в круглые скобки, работает со всеми DOM событиями. Добавим к нашему полю ввода символ решетка и myInput. Это будет ссылкой на наш элемент input.

simple-form.component.ts
<input #myInput type="text">
<button (click)="onClick()">Нажми меня!</button>
Понимая это, теперь мы имеем доступ к значениям элемента. Чтобы проверить, добавим myInput.value в наш обработчик нажатия на кнопку.

simple-form.component.ts
<input #myInput type="text">
<button (click)="onClick(myInput.value)">Нажми меня!</button>
Назовем параметр value и выведем его в функции log. После сохранения, значение поля ввода будет выводиться в консоль. Если ввести текст в поле и нажать на кнопку, мы увидим это.

simple-form.component.ts
onClick(value){
    console.log(value);  // type
                         // something else
  }
Таким образом, при помощи комбинации событий и ссылок, мы можем получать доступ к элементам и их значениям. А так же управлять ими так, как необходимо нашему приложению.

Создание простого Angular 2 компонента

При работающем сервере, пойдем дальше. Откроем новую вкладку в терминале в той же папке проекта. Сгенерируем новый компонент. Компонент будет называться Simple Form, и мы создадим его с флагами --inline-template и --inline-style. Эти флаги позволят модифицировать компонент в одном файле.

Терминал

$ ng generate component simple-form --inline-template --inline-style

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

Терминал
$ ng g c simple-form -it -is

После нажатия Enter, команда сгенерирует два файла. Файл компонента и файл для тестов. Давайте посмотрим на этот компонент.

В проекте по пути src/app/ находится папка simple-form с нашим новым компонентом внутри. Откроем его и увидим селектор app-simple-form.

simple-form.component.ts

@Component({
  selector: 'app-simple-form',
  template: `
    <p>
      simple-form Works!
    </p>
  `,
  styles:[]
})
export class SiompleFormComponent implements ngOnInit {
  constructor() { }
  ngOnInit(){
  }
}

В нашем AppComponent, в шаблоне просто добавим div и затем <app-simple-form> внутри, для инициализации компонента.

app.component.ts

@Component({
  selector: 'app-root',
  template: `<div>
<app-simple-form></app-simple-form> // simple-form Works!
</div>`
})
export class AppComponent {
  title = `Hello World`;
}

Сохраним изменения. Как только браузер перезагрузится мы увидим текст "simple-form Works!". Надпись приходит из компонента app-simple-form. Нужно заметить, что мы называли компонент simple-form, a префикс app- добавляется из конфигурационного файла Angular CLI-json.

Префикс необходим для предотвращения конфликтов в пространствах имен с другими проектами. Вы можете использовать любые префиксы.

Если вы посмотрите на селектор в simple-form.component, то увидите app-simple-form. В app.component вы увидите app-root, который используется внутри файла index.html.

index.html

<body>
  <app-root>Loading...</app-root>
</body>

Мы видим <app-root>. Если открыть Chrome dev tools, мы увидим такую же иерархию компонентов app-root, app-simple-form, как и в шаблонах.

Скажи Hello World c Angular 2

Установите Angular CLI глобально при помощи npm install -g.