Первая часть туториала была хорошим введением в DORF, результатом которого стало следующее приложение (примерно):
Шаг за шагом
Основные проблемы, обозначенные в первой части:
- Нет индикаторов на обязательных полях; в нашем случае все поля обязательны, но все же…
- Видны 2 кнопки, и только первая что-то делает
- Первая кнопка
'Save'
вместо'Submit'
- Функция
update
не является идеальным способом работы с DORF Object.
Обязательные поля
Поставить характерную красную звездочку после метки требуемого поля в DORF действительно тривиально. Все, что вам нужно, это установить requiredWithStar
в true
где-то внутри метода DorfModule.forRoot
в app.module
.
Кнопки стиля
В настоящее время у нас есть 2 кнопки, и одна из них не нужна. К тому же они некрасивые. Решение для этого — еще раз — является модификацией метода DorfModule.forRoot
. Конечный результат может выглядеть так:
DorfModule.forRoot({ css: { section: 'row', wrapper: 'form-group col-12 row', label: 'col-2 col-form-label', fieldGeneralization: 'col-10', htmlField: 'form-control', buttons: { save: 'btn btn-primary', reset: 'hidden-xs-up' } }, dorfFields: [{ tag: DorfField.CHECKBOX, css: { wrapper: 'checkbox col-12 row', htmlField: 'checkbox' } }], requiredWithStar: true })
Стили берутся прямо из Bootstrap.
Изменение кнопок
Время для чего-то посложнее. В текущей версии DORF нет механизмов настройки текста кнопок. Но мы все еще можем достичь нашей цели следующим образом:
- Переопределение компонента(ов) DORF
- Разговор с ДОРФом по-другому
Давайте рассмотрим первый вариант.
Переопределение компонентов DORF
DORF написан модульным способом. Зависимости представлены ниже:
Есть 3 основных модуля:
DorfCoreModule
— сущность, которая экспортирует конфигурацию,ReactiveFormsModule
из Angular и абстрактных классов TypeScript, используемых в дальнейшем полями.DorfFieldsModule
— модуль, который собирает информацию, связанную с полем: ввод, выбор, радио, флажок и обобщение поля. Идея одного модуля для всех полевых компонентов проста — он должен позволять легко переключаться. Например. можно определить компоненты с помощью DORF-подобных селекторов, которые используют, например. Angular Material за кулисами. Затем новый модуль, содержащий их, следует использовать поверхDorfCoreModule
. Рано или поздно DORF необходимо будет улучшить, чтобы обеспечить еще более простой способ переопределения полей по умолчанию.DorfModule
— финальный модуль, который использует предыдущие и добавляет обертки и кнопки.
Как написано выше, DorfModule
хранит компонент кнопок. Давайте посмотрим на это глубже:
Что нужно сделать аналогично тому, что произошло в примере definition-extras
из официального репозитория DORF. DorfButtonsComponent
имеет HTML-шаблон, который является источником нашей проблемы. И решение состоит в том, чтобы создать новый компонент, например. src/app/ext/custom-buttons-component.ts
:
import { Component } from '@angular/core'; import { DorfButtonsComponent } from 'dorf'; @Component({ selector: 'dorf-buttons', template: ` <section [ngClass]="config.css.buttons?.group"> <button (click)="submit()" [ngClass]="config.css.buttons?.save" [disabled]="!form || !form.valid">Submit</button> </section> ` }) export class CustomButtonsComponent extends DorfButtonsComponent { }
HTML был изменен, чтобы соответствовать нашим требованиям. Мы даже убрали ненужную кнопку «Сброс». Подсказки:
- Селектор должен соответствовать исходному селектору
- Может быть полезно расширить исходный компонент
Новый компонент должен быть зарегистрирован в модуле:
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { DorfFieldsModule, DorfField, DorfFieldWrapperComponent, DorfGroupWrapperComponent } from 'dorf'; import { CustomButtonsComponent } from './ext/custom-buttons-component'; import { UserFormComponent } from './user/user-form.component'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ UserFormComponent, AppComponent, CustomButtonsComponent, DorfFieldWrapperComponent, DorfGroupWrapperComponent ], imports: [ BrowserModule, FormsModule, HttpModule, DorfFieldsModule.forRoot({ css: { section: 'row', wrapper: 'form-group col-12 row', label: 'col-2 col-form-label', fieldGeneralization: 'col-10', htmlField: 'form-control', buttons: { save: 'btn btn-primary' } }, dorfFields: [{ tag: DorfField.CHECKBOX, css: { wrapper: 'checkbox col-12 row', htmlField: 'checkbox' } }], requiredWithStar: true }) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Обратите внимание, что мы перешли с DorfModule
на DorfFieldsModule
, поэтому DorfFieldWrapperComponent
и DorfGroupWrapperComponent
нужно было прописать «вручную».
Конечный результат этой части доступен здесь: http://embed.plnkr.co/38WWfdqRICzB4zlzmKon/
Разговор с ДОРФ по-другому
Переопределение частей DORF — мощная техника, но в нашем случае это слишком много. Давайте отменим последние изменения и изменим декоратор DorfForm
на UserFormComponent
:
@DorfForm({ renderWithoutButtons: true })
Затем добавим <button class="btn btn-primary">Submit</button>
вручную в шаблон AppComponent
.
Лучший способ работы с DORF Object
Что, если я скажу вам, что вы можете использовать DORF и получать удовольствие от [(ngModel)]
? Начнем модификацию с удаления функции update
из нашей модели. Затем для каждого поля, которое мы хотим немедленно обновить, мы должны добавить опцию updateModelOnChange: true
:
@DorfObject() export class User { @DorfInput({ label: 'Username', type: 'input' as InputType, validator: Validators.required, updateModelOnChange: true }) private _login: string; @DorfInput({ label: 'Password', type: 'password' as InputType, validator: Validators.required, updateModelOnChange: true }) private _password: string; @DorfCheckbox({ innerLabel: 'I accept the terms and conditions', validator: Validators.requiredTrue, updateModelOnChange: true }) private _acceptance: boolean; constructor(options?: IUser) { if (options) { this._login = options._login; this._password = options._password; this._acceptance = options._acceptance; } } get login() { return this._login; } get password() { return btoa(this._password); } get acceptance() { return this._acceptance; } get basicAuth() { if (this._login && this._password) { return btoa(`${this._login}:${this._password}`); } } }
Бонус: вы можете указать параметр debounce
, чтобы отложить обновление. Он ожидает количество миллисекунд в качестве значения. Аналогичен одному из ngModelOptions
параметров из Angular 1.3.
Вот и все. Имея такое обновление, можно потреблять user
прямо в AppComponent
.
Резюме
Мы выполнили все требования из предыдущей части и расширили наши знания о DORF:
- метод
DorfModule.forRoot
позволяет назначать CSS-классы не только полям, но и кнопкам; он также имеет дополнительные параметры, например. для установки красной звезды на обязательные поля - DORF является модульным, и его компоненты можно довольно легко переопределить.
- DORF позволяет выполнять
[(ngModel)]
подобное обновление. За кулисами немедленное обновление использует события, поэтому это реактивный способ, а не двусторонняя привязка.
Готовое приложение представлено здесь:
Будущее
DORF все еще находится в разработке, но его код уже позволяет обрабатывать множество вариантов использования и сценариев, которые еще не представлены в руководствах.
Запланированные уроки
- Дополнительные параметры и дальнейшее переопределение компонентов DORF
- Вложенные объекты и расположение столбцов
- Добавление настраиваемых полей
- Тестирование ДОРФ