Как использовать те же поля проверки в двух компонентах?

Я хочу оптимизировать свое приложение, чтобы не использовать одни и те же поля проверки в двух компонентах. Я использую поля для проверки "title" и "url" в компоненте "GalleryAddComponent" (когда добавляю элемент) и те же поля для проверки "title" и "url" в компоненте "GalleryItemComponent" (когда я редактирую составная часть). В компонентах только кнопки в форме разные, в "GalleryAddComponent" есть кнопка «добавить», которая вызывает метод добавления элемента, а в компоненте "GalleryItemComponent" кнопка «updatePost», которая сохраняет изменения в элементе ,

Я понимаю, что поля должны быть перенесены в отдельный компонент и связаны в виде компонентов: "GalleryAddComponent" и "GalleryItemComponent" . Но как сделать это правильно, чтобы сохранить проверку кнопок и их логики. Помогите пожалуйста понять, как реализовать эту идею, и если вы можете указать пример в «StackBlitz».

Ссылка на структуру моего проекта: StackBlitz

шаблон GalleryAddComponent:

 <h3>Add new product</h3> <div class="card"> <div class="card-body"> <form [formGroup]="angForm" novalidate> <div class="form-group"> <label class="col-md-4">Picture Title</label> <input type="text" class="form-control" formControlName="title" minlength="1" #title/> </div> <div *ngIf="angForm.controls['title'].invalid && (angForm.controls['title'].dirty || angForm.controls['title'].touched)" class="alert alert-danger"> <div *ngIf="angForm.controls['title'].errors.required"> Title is required. </div> </div> <div class="form-group"> <label class="col-md-4">Picture Address (url)</label> <input type="url" class="form-control" formControlName="url" #url pattern="https?://.+" title="Include http://"/> </div> <div *ngIf="angForm.controls['url'].invalid && (angForm.controls['url'].dirty || angForm.controls['url'].touched)" class="alert alert-danger"> Address(url) is required. <div *ngIf="angForm.controls['url'].errors.required "> </div> </div> <div class="form-group but-group"> <button (click)="addPost(title.value, url.value); angForm.reset(title.value, url.value)" [disabled]="angForm.pristine || angForm.invalid" class="btn btn-primary">Add </button> <a routerLink="/gallery" class="btn btn-danger">Back</a> </div> </form> </div> </div> 

Всего 3 ответа


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

Но если вы хотите создать повторно используемый компонент, который содержит всю форму ...

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

 export interface GalleryItem { title: string; url: string; } 

Затем вам нужно создать дочерний компонент, который содержит вашу форму вместе с кнопкой отправки. Роль этого компонента состоит в том, чтобы получить вход от пользователя, проверить его и, если его ok отправит его обратно в родительский компонент, который может быть AddComponent или EditComponent . Родительский компонент решает, что делать с этими данными. Если на странице « Edit родительский компонент должен сначала извлечь предыдущие данные и передать их дочернему компоненту, чтобы заполнить форму. Ярлыки кнопок также могут передаваться от родителя к дочернему.

Существует много способов взаимодействия компонентов, которые вы можете выбрать. Если вы не знакомы с передачей данных между компонентами, я настоятельно рекомендую вам прочитать угловые документы , особенно раздел « Взаимодействие компонентов ».

пример кода на stackblitz


@IgorShvets Для перспективы оптимизации кода я бы предложил попробовать использовать проверку модели на основе Decorator. Я создал образец приложения в соответствии с вашей структурой проекта и необходимостью проверки. Пожалуйста, проверьте Stackblitz .

Основанный на декораторе подход к модели - вам просто нужно объявить свойства в классе и настроить декораторы проверки на свойство. Основное преимущество этого подхода заключается в том, что вам не нужно создавать FormControl с Validator для каждого компонента. Вам просто нужно передать объект модели в RxFormBuilder для создания FormGroup.

Позвольте мне подробно описать, как это делается:

  1. Я создал класс галереи и определяю свойства. Я сконфигурировал декораторы проверки свойств.

Вот код модели галереи.

 import { required } from "@rxweb/reactive-form-validators" export class Gallery { @required() title:string; @required() url:string; } 
  1. Я использовал модель Gallery в GalleryAddComponent и сгенерировал FormGroup.
 export class GalleryAddComponent implements OnInit { galleryFormGroup:FormGroup; gallery:Gallery constructor(private formBuilder:RxFormBuilder){} ngOnInit(){ this.gallery = new Gallery(); this.galleryFormGroup = this.formBuilder.formGroup(this.gallery); } } 
  1. Та же модель, которую я использовал в GalleryItemComponent и сгенерировал FormGroup с данными редактирования.
 export class GalleryItemComponent implements OnInit { galleryFormGroup:FormGroup; gallery:Gallery constructor(private formBuilder:RxFormBuilder){} ngOnInit() { this.gallery = new Gallery(); this.gallery.title = "Electronics"; this.gallery.url = "www.google.com"; this.galleryFormGroup = this.formBuilder.formGroup(this.gallery); } } 

Для этого я использовал « @ rxweb / reactive-form-validators ». Потому что это обеспечивает проверку модели на основе декораторов. 50+ Декораторы валидации доступны. Для получения дополнительной информации о декораторах проверки rxweb

Шаг, который я выполнил, чтобы сделать это:

  1. npm install @ rxweb / reactive-form-validators
  2. Импортируйте ' RxReactiveFormsModule ' в корневой модуль.
  3. Создайте модель и примените декораторы к свойству.
  4. Разрешите службу RxFormBuilder в конструкторе компонента.
  5. Создайте FormGroup с помощью метода formGroup объекта службы RxFormBuilder.

Ваш образец Stackblitz не работает из-за некоторой проблемы с пакетами. Поэтому я создал отдельный пример. Пожалуйста, сделайте свое рабочее приложение на stackblitz, чтобы я мог вносить изменения и в том случае, если возникли путаницы.

Если у вас есть какие-либо вопросы, пожалуйста, дайте мне знать.


import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'
import { FormGroup, FormControl, FormArray, AbstractControl } from '@angular/forms'

@Component({
    selector: 'control-error-message',
    host: {
        '[class.error_msg]': 'showErrorMessage'
    },
    template: `<span *ngIf="showErrorMessage">{{displayMessage}}</span>`
})
export class ErrorMessageComponent {

    @Input() control: FormControl;

    errorMessage: string;
    displayMessage: string;
    showErrorMessage: boolean = false;

    constructor() { }

    ngOnChanges(change: SimpleChanges) {

        if (this.control) {
            this.control.valueChanges.subscribe(
                (res) => {
                    this.setErrorMessage(this.control);
                }
            )
        }
    }

    getControlName(c: AbstractControl): string | null {
        const formGroup = c.parent.controls;
        return Object.keys(formGroup).find(name => c === formGroup[name]) || null;
    }

    setErrorMessage(control: FormControl) {
        this.errorMessage = "";
        if (control.errors) {
            for (let propertyName in control.errors) {
                if (propertyName.toLowerCase() == "required") {
                    this.displayMessage = this.getControlName(control) + " field is required";
                    this.showErrorMessage = true;
                }
            }
        }
    }
}

в html вы можете иметь что-то вроде

<form [formGroup]="angFormEd" novalidate>
<div class="form-group">
     <label class="col-md-4">Picture Title</label>
     <input type="text" class="form-control" formControlName="title" minlength="1" #title/>
     <control-error-message [control]="formGroupObject.get('title')"></control-error-message>
</div>

Это не проверено или рабочий код, я удалил несколько строк кода, чтобы сделать его более простым и понятным. Вам не нужно вводить эту строку в свой html:

<div *ngIf="angForm.controls['title'].invalid && (angForm.controls['title'].dirty || angForm.controls['title'].touched)"
                 class="alert alert-danger">
                <div *ngIf="angForm.controls['title'].errors.required">
                    Title is required.
                </div>
            </div>

Все стили будут обработаны классом «error_msg», применяемым на хосте, если это ошибка. Кроме того, сообщение будет показано чуть ниже поля ввода.

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


Есть идеи?

10000