【问题标题】:How to use the same validation fields in two components?如何在两个组件中使用相同的验证字段?
【发布时间】:2019-03-24 11:32:23
【问题描述】:

我想优化我的应用程序,以免在两个组件中使用相同的验证字段。 我使用字段检查组件"GalleryAddComponent" 中的"title""url"(当我添加一个元素时),并使用相同的字段检查组件"GalleryItemComponent" 中的"title""url"(当我编辑零件)。在组件中,只有表单中的按钮不同,在"GalleryAddComponent"中有一个按钮“add”,它调用添加元素的方法,在组件"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>

GalleryAddComponent 代码:

export class GalleryAddComponent {
    angForm: FormGroup;
    isAdded: boolean = false;

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

    createForm(): void {
        this.angForm = this.fb.group({
            title: ['', Validators.required],
            url: ['', Validators.required]
        });
    }

    addPost(title: string, url: string): void {
        this.galleryService.add(title, url).subscribe(res => {
            this.isAdded = true;
        });
    }
}

GalleryItemComponent 的模板:

        <h4>Edit your post</h4>
        <div class="card-body">
            <form [formGroup]="angFormEd" novalidate>
                <div class="form-group">
                    <label class="col-md-4">Picture Title</label>
                    <input type="text" class="form-control" formControlName="titleEd" #titleEd
                    />
                </div>
                <div *ngIf="angFormEd.controls['titleEd'].invalid && (angFormEd.controls['titleEd'].dirty || angFormEd.controls['titleEd'].touched)"
                     class="alert alert-danger">
                    <div *ngIf="angFormEd.controls['titleEd'].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="urlEd" #urlEd pattern="https?://.+"
                           title="Include http://"/>
                </div>
                <div *ngIf="angFormEd.controls['urlEd'].invalid && (angFormEd.controls['urlEd'].dirty || angFormEd.controls['urlEd'].touched)"
                     class="alert alert-danger">
                    Address(url) is required.
                    <div *ngIf="angFormEd.controls['urlEd'].errors.required ">

                    </div>
                </div>
                <div class="form-group but-group">
                    <input type="button"
                           (click)="updatePost(titleEd.value, urlEd.value)"
                           [disabled]=" angFormEd.invalid"
                           class="btn btn-primary" value="Update Post">
                </div>
            </form>
        </div>

GalleryItemComponent 的代码:

export class GalleryItemComponent implements OnInit {
   pic: Picture;
   angFormEd: FormGroup;

     constructor( private route: ActivatedRoute, private galleryService: GalleryService, private fb: FormBuilder,) {

    }

    ngOnInit() {
        this.createFormEd();
        this.showPost();
    }

    createFormEd(): void {
        this.angFormEd = this.fb.group({
            titleEd: ['', Validators.required],
            urlEd: ['', Validators.required]
        });
    }

    showPost(): void {
        this.route.data.subscribe(params => {
            this.pic = params.post;
            this.angFormEd.setValue({titleEd: params.post.title, urlEd: params.post.url});
        })
    }
    updatePost(title: string, url: string): void {
        this.route.params.subscribe(params => {
            this.galleryService.update(title, url, params['id']).subscribe(res => {
                if (res.id === this.pic.id) {
                    this.pic.title = title;
                    this.pic.url = url;
                } 
            });
        });
    }
}

【问题讨论】:

    标签: javascript html angular typescript angular-components


    【解决方案1】:

    如果您只需要创建一个可重用的验证器,请编写一个 Directive 来进行验证。通过这种方式,您可以将验证器附加到任何表单字段,只需向输入添加属性即可。

    但是如果你想创建一个包含整个表单的可重用组件...

    我建议的第一件事是使用表单包含的字段创建一个界面。这有助于您轻松地在组件之间传递数据。

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

    然后您必须创建一个包含表单和提交按钮的子组件。这个组件的作用是从用户那里获取输入,验证它,如果它的ok将它发送回父组件,它可能是AddComponentEditComponent。父组件决定如何处理这些数据。如果是Edit 页面,父组件应该首先获取之前的数据并将其传递给子组件以填写表单。按钮标签也可以从父级传递给子级。

    您可以选择多种组件交互方式。如果您不熟悉在组件之间传递数据,我强烈建议您阅读Angular docs,尤其是Component Interaction 部分。

    sample code on stackblitz

    【讨论】:

    • 我想创建一个包含整个表单的可重用组件。你能在“StackBlitz”中举一些例子吗?我能理解什么
    • @IgorShvets 我在 stackblitz 中创建了一个示例应用程序。
    【解决方案2】:
    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>
    

    如果 dere 出现错误,所有样式都将由应用在主机上的“error_msg”类处理。此外,消息将显示在输入字段的正下方。

    注意:我刚刚复制粘贴了我的代码并删除了一些东西,理解这个想法并根据您的要求实现它

    【讨论】:

      猜你喜欢
      • 2011-01-28
      • 2015-10-22
      • 1970-01-01
      • 2011-02-16
      • 2022-11-18
      • 2018-09-08
      • 1970-01-01
      相关资源
      最近更新 更多