Декораторы @Input и @Output
В ситуациях, когда мы хотим отправить некоторый контент от родительского к дочернему компоненту, нам нужно использовать декоратор @Input
в дочернем компоненте, чтобы обеспечить привязку свойств между этими компонентами. Более того, у нас могут быть некоторые события в дочернем компоненте, которые отражают его поведение обратно в родительский компонент. Для этого мы собираемся использовать декоратор @Output
с EventEmitter
.
Для обработки сообщений об успешном выполнении и сообщений об ошибках (которые не являются сообщениями 500 или 404) мы собираемся создать дочерние компоненты модального окна. Мы собираемся повторно использовать их в каждом компоненте, который требует отображения сообщений такого типа. Если вы хотите зарегистрировать свой повторно используемый компонент, рекомендуется создать общий модуль, а также зарегистрировать и экспортировать свои компоненты внутри этого модуля. Затем вы можете использовать эти повторно используемые компоненты в любом компоненте более высокого уровня, который вы хотите, зарегистрировав общий модуль внутри модуля, ответственного за этот компонент более высокого уровня.
Создание общего модуля
Начнем с создания общего модуля в общей папке:
ng g module shared
Затем изменим файл shared.module.ts
:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [
CommonModule
],
declarations: [
],
exports: []
})
export class SharedModule { }
Затем, включите SharedModule в наш файл owner.module.ts
:
import { SharedModule } from './../shared/shared.module';
imports: [
CommonModule,
SharedModule,
Модальный компонент ошибки
Выполним команду AngularCLI
для создания модального компонента ошибки:
ng g component shared/modals/error-modal --skipTests
Помимо создания файлов компонентов, эта команда импортирует новый компонент в shared-module. Но нам нужно экспортировать его вручную:
declarations: [
ErrorModalComponent
],
exports: [
ErrorModalComponent
]
В папке modals
мы собираемся создать еще один файл CSS с именем modal-shared.component.css
. Мы создаем этот файл, потому что у нас будет один и тот же CSS для модальных окон ошибки и успеха без повторения одного и того же кода в двух разных файлах CSS.
Теперь изменим файл error-modal.component.ts
:
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-error-modal',
templateUrl: './error-modal.component.html',
styleUrls: ['./error-modal.component.css', '../modal-shared.component.css']
})
export class ErrorModalComponent implements OnInit {
@Input() public modalHeaderText: string;
@Input() public modalBodyText: string;
@Input() public okButtonText: string;
constructor() { }
ngOnInit() {
}
}
Мы украшаем наши свойства декоратором @Input
, и, таким образом, наш родительский компонент может устанавливать значения для этих свойств с помощью привязки свойств.
Давайте продолжим, изменив файл error.modal.component.html
:
<div id="errorModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{modalHeaderText}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>{{modalBodyText}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">{{okButtonText}}</button>
</div>
</div>
</div>
</div>
Затем изменим файл modal-shared.component.css
:
.modal-title {
margin: 0;
line-height: 1.42857143;
font-size: 30px;
text-align: center;
}
.modal-body p {
text-align: center;
margin-top: 10px;
}
@media (min-width: 768px){
.modal-dialog {
width: 500px;
margin: 20% auto;
}
}
Создание модального компонента success
Теперь у нас есть модальное окно ошибки, и давайте продолжим создание модального окна success таким же образом, как мы это делали с модальным окном ошибки:
ng g component shared/modals/success-modal --skipTests
Мы должны экспортировать модальный компонент успеха из файла shared.module.ts
.
Затем изменим наш файл success-modal.component.ts
:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-success-modal',
templateUrl: './success-modal.component.html',
styleUrls: ['./success-modal.component.css', '../modal-shared.component.css']
})
export class SuccessModalComponent implements OnInit {
@Input() public modalHeaderText: string;
@Input() public modalBodyText: string;
@Input() public okButtonText: string;
@Output() public redirectOnOK = new EventEmitter();
constructor() { }
ngOnInit() {
}
public emitEvent = () => {
this.redirectOnOK.emit();
}
}
Декоратор @Ouput
с EventEmitter
используется для генерации события от дочернего к родительскому компоненту, и это именно то, что мы хотим сделать. Мы собираемся использовать компонент успеха с успешно выполненными действиями create, update или delete, и, нажав кнопку OK, мы собираемся перенаправить пользователя в компонент списка владельцев. Чтобы этот эмиттер работал, нам нужно сделать подписку в родительском компоненте на эту функцию emmitEvent
.
Затем, изменим файл success-modal.component.html
:
<div id="successModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{modalHeaderText}}</h5>
<button type="button" class="close" data-dismiss="modal" (click)="emitEvent()" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>{{modalBodyText}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal" (click)="emitEvent()">{{okButtonText}}</button>
</div>
</div>
</div>
</div>
Вызов дочернего компонента
Теперь у нас есть оба дочерних компонента, которые можно использовать повторно. На данный момент у нас все еще нет места для вызова наших дочерних компонентов, но, например, если вы хотите вызвать свой модальный компонент ошибки в какой-либо родительский компонент, все, что вам нужно сделать, это добавить его селектор в родительский компонент:
<app-error-modal [modalHeaderText]="'some string in here'"
[modalBodyText]="some property from a component in here without single quotes"
[okButtonText]="'OK'"></app-error-modal>
Мы включаем селектор <app-error-modal>
из нашего дочернего компонента и настраиваем свойства @Input
в квадратных скобках (привязка свойств). Чтобы установить значение для привязки свойств, всегда используйте двойные кавычки, а затем указывайте значение между ними. Если мы хотим передать строку, она должна быть сначала заключена в одинарные кавычки.
Теперь, вы знаете, как использовать дочерние компоненты, вы можете разделить компонент сведений о владельце на отношения родитель-потомок. Попробуйте сделать это самостоятельно, потому что практика - лучший способ научиться чему-то. Конечно, вы можете найти эту реализацию в исходном коде этого сообщения в блоге.
Директивы
Как вы могли заметить, у нашего владельца есть свойство dateOfBirth
, с которым нам нужно работать в формах создания и обновления. Это будет просто элемент ввода текста в форме, но он будет иметь другое поведение. Мы собираемся использовать его как средство выбора даты. Мы можем изменить его поведение в обоих компонентах (Create и Update) по отдельности, но мы этого делать не будем. Для этого мы создадим директиву Angular, чтобы мы могли изменить поведение этого поля ввода.
В общей папке создайте новые директивы папки и внутри создайте новый файл datepicker.directive.ts:
ng g directive shared/directives/datepicker --skipTests
Давайте изменим этот файл:
import { Directive, ElementRef, Output, EventEmitter, OnInit } from '@angular/core';
@Directive({
selector: '[appDatepicker]'
})
export class DatepickerDirective implements OnInit {
@Output() public change = new EventEmitter();
constructor(private elementRef: ElementRef) { }
public ngOnInit() {
$(this.elementRef.nativeElement).datepicker({
dateFormat: 'mm/dd/yy',
changeYear: true,
yearRange: "-100:+0",
onSelect: (dateText) => {
this.change.emit(dateText);
}
});
}
}
Просто добавьте в файл styles.css
file (глобальный файл стилей) этот стиль:
.ui-widget-header {
color: #564040;
}
Не забудьте экспортировать эту директиву из файла общего модуля.
Теперь наша директива готова для внедрения в любой элемент HTML. Мы собираемся использовать его позже, но, например, вы можете использовать его так:
<input type="text" class="form-control" appDatepicker>
Заключение
Прочитав этот пост, вы узнали:
- Для чего нужны декораторы ввода-вывода Angular
- Как поделиться компонентами в проекте в Angular
- Способ создания дочерних компонентов
- Как вызвать дочерний компонент в родительский компонент в Angular
- Как создавать директивы в Angular
Спасибо, что прочитали этот пост, надеюсь, он был вам полезен.
В следующей статье, мы начнем с создания владельца и проверки формы.