【问题标题】:How to display the summary of error message on top of the form in angular reactive forms如何以角度反应形式在表单顶部显示错误消息的摘要
【发布时间】:2019-05-18 17:26:21
【问题描述】:

我有如下验证摘要组件:

以下组件获取 ngform 但无法订阅 statuschanges/Valuechanges 并显示错误消息摘要。

export class ValidationSummaryComponent implements OnInit {
  @Input() form: NgForm;
  errors: string[] = [];

 constructor() { }

ngOnInit() {
  if (this.form instanceof NgForm === false) {
  throw new Error('You must supply the validation summary with an NgForm.');
}
this.form.statusChanges.subscribe(status => {
  this.resetErrorMessages();
  this.generateErrorMessages(this.form.control);
});
}

 resetErrorMessages() {
this.errors.length = 0;
}

generateErrorMessages(formGroup: FormGroup) {
Object.keys(formGroup.controls).forEach(controlName => {
  const control = formGroup.controls[controlName];
  console.log('control.......... ', control);
  const errors = control.errors;
  console.log('control.errors.......... ', control.errors);

  if (errors === null || errors.count === 0) {
    return;
  }
  // Handle the 'required' case
  if (errors.required) {
    this.errors.push(`${controlName} is required`);
  }
  // Handle 'minlength' case
  if (errors.minlength) {
    this.errors.push(`${controlName} minimum length is ${errors.minlength.requiredLength}.`);
  }
  // Handle custom messages.
  if (errors.message) {
    this.errors.push(`${controlName} ${errors.message}`);
  }
});

} }

和验证-summary.component.html

<div *ngIf="errors?.length > 0" class="validation-summary">
    <p>Please fix the following errors:</p>
<ul>
  <li *ngFor="let error of errors">{{ error }}</li>
</ul>

dynamic-form.component.ts

constructor(public formBuilder: FormBuilder) {
}
productFormGroup: FormArray;

ngOnInit() {

this.productFormGroup = this.formBuilder.array([]);
  this.ProductList.forEach(product => {
      this.productFormGroup.push(this.formBuilder.group({
        productId: [product.productId],
        displayName: [product.displayName],
        productName: [product.productName, Validators.required]
      }));
    });

} }

使用验证摘要的dynamic-form.component.html。

    <div id="mainWrapper">
      <app-validation-summary-component [form]="userForm"></app-validation-summary-component> 
    <form #userForm="ngForm">
<div [formGroup]="product" *ngFor="let product of 
         productFormGroup.controls>
      <label>{{product.get('displayName').value}}</label>
         <input  class="form-control" 
       name="product.get('displayName').value" 
        formControlName="productName" required/>
 </div>
      <button class="btn btn-primary" type="submit" 
              [disabled]="!productFormGroup.valid">Submit </button>
       <button class="btn btn-primary" style="margin-left: 30px" type="reset" 
       (click)="reset()"> Reset </button>
       </form>
</div>

需要在显示空白/无效标签名称列表的动态表单组件顶部显示错误消息摘要。

【问题讨论】:

  • 你可以在 node 中使用 flash 之类的东西,这取决于你在服务器端使用的平台。
  • resetErrorMessages() 函数应该是{this.errors=[]},你不能改变“数组的长度”,你应该改变数组

标签: angular validation angular-reactive-forms customvalidator


【解决方案1】:

这里是循环遍历 FormGroup 的每个 FromControls 的函数组,包括 FormArray 中的嵌套 FormControls 和生成验证摘要。

  getFormSummaryHtml(formGroup, fg_discription){
    let allErrors = this.getFormSummary(formGroup, '');
    let error_obj = this.setErrorFormat(allErrors, fg_discription)
    if (error_obj){
      let html = this.getHtmlFromObject(error_obj, '')   
  
      return html;
    }
  }

  getHtmlFromObject(error_obj, html) {
    if (error_obj.value) {
      for (let index = 0; index < error_obj.value.length; index++) {
        const element = error_obj.value[index];
        html += `<ul> <li>`;
        html += element.text;

        if (element.value) {
          html = this.getHtmlFromObject(element.value, html)
        }
        html += ` </li> </ul>`;
      }
    }
    else if (error_obj.length > 0) {
      html += `<ul>`;
      for (let index = 0; index < error_obj.length; index++) {
        const element = error_obj[index];
        html += element.text;
        if (element.value) {
          html = this.getHtmlFromObject(element.value, html)
        }
        else {
          // to Remove last appended text
          html = html.substring(0, html.length - element.text.length);
          html += `<li> ${element.text} </li>`
        }
      }
      html += `</ul>`;
    }
    else {
      html += error_obj.text;
    }
    return html
  }

  getFormSummary(formGroup, parentGroup) {
    let errors = []
    for (const key in formGroup) {
      if (Object.prototype.hasOwnProperty.call(formGroup, key)) {
        const element = formGroup[key];
        if (element instanceof FormGroup) {
          parentGroup = parentGroup == '' ? key : parentGroup + '>' + key;
          let terror = this.getFormSummary(element.controls, parentGroup)
          errors = [...errors, ...terror]
        }
        if (element instanceof FormArray) {
          parentGroup = parentGroup == '' ? key : parentGroup + '>' + key;
          for (let index = 0; index < element.controls.length; index++) {
            let ele = element.controls[index];
            let terror = this.getFormSummary(ele["controls"], parentGroup)
            errors = [...errors, ...terror]            
          }
        }
        if (element instanceof FormControl && element.valid == false && element.errors && Object.keys(element.errors).length > 0) {
          for (const errorTypes in element.errors) {
            errors.push(parentGroup + '>' + key + ':' + errorTypes)
          }
        }
      }
    }    
    return errors;
  }

  setErrorFormat(errors,discription){
    let errorObj: { text: string, key: string, value: Array<any>};

    for (let index = 0; index < errors.length; index++) {
      let element = errors[index];
      let elements = element.split(':');
      let error_elements = elements[0].split('>')
      error_elements.forEach((ele,idx) => {
        if(errorObj == null){
          errorObj = { text: discription[ele], key: ele, value: null };
        }
        else if (idx > 0){
          let error_t_obj = this.getErrorElement(errorObj, ele);

          let error_ele_obj = this.getErrorElement(errorObj, error_elements[idx - 1]);
          if (error_ele_obj && (error_t_obj == null || error_t_obj.key != error_elements[idx])) {
            let obj = { text: discription[ele], key: ele, value: null };
            error_ele_obj.value = error_ele_obj.value && error_ele_obj.value.length > 0 ? error_ele_obj.value : new Array();
            error_ele_obj.value.push(obj)
          }
        }        
      });      
    }
    return errorObj;
  }

  getErrorElement(error,s_key){
    if (error.key == s_key) {
      return error;
    }
    else if (error.value && error.value.length > 0) {
      for (let index = 0; index < error.value.length; index++) {
        let ele = error.value[index];
        let objerror = this.getErrorElement(ele, s_key);
        if (objerror != null ){
          return objerror;
        }
      }
    }
  }

这个怎么称呼?

getFormSummary(){
// This array contains FromControls name and Names of controls that user can understand
let fg_discription = {
  saleGroup: "Sales",
  sale_date: "Sale date",
  sale_type_id: "Sale type",
  deal_type_id: "Deal type",
  lender_id: "Lender",
  wholesaler_id: "Wholesaler",
  published_price: "Published price",
  pack: "Pack",
  allowance: "Allowance"
};
let html = this.getFormSummaryHtml(this.addSalesForm.controls, fg_discription)
return html;
}

validateFormOnSubmission() {
let form = this.addSalesForm.value;
let html = this.getFormSummary()
if (html == undefined) {
// Submit Form
    this.onSubmitAddSales();
}
else { // Show Html in POP message
  this.popMessage({ detail: "Following fields are  mandatory: ", data: { html }, key: "popup" })
}

}

【讨论】:

  • 尝试以“更多角度的方式”显示错误:不要使用 .html 创建文本,否则直接在 .html 中使用 *ngFor
  • 如果你想要对象并使用 ngFor 显示它,那么let error_obj = this.setErrorFormat(allErrors, fg_discription) 有错误对象。
【解决方案2】:

在validation-summary.component 中循环formarray formgroup 控件的方式不正确。 Created stackblitz 解释了解决方案。

https://stackblitz.com/edit/angular-mr49zh

【讨论】:

  • 非常感谢苏雷什!这正是我想要的....但是在显示错误消息时,它会选择相同的名称,如“需要显示名称”,而是应该选择唯一值并说需要 angular。或者需要 React 可以请指导。
  • 您应该使用“显示名称”。投票对他人很有帮助。
  • 我投了赞成票,因为我只有 3 个声誉 :(,我实际上想显示错误消息,如 Angular 是必需的,目前它显示所有 3 个字段都需要显示名称,如果它有错误,相反,它应该纠正每个字段的唯一名称,并说需要 angular 或需要 react ....
  • 我想我用下面的代码找到了解决方案.... if (formInnerControl && (_formControl.status === 'INVALID' || formInnerControl.errors) && formElement === 'displayName ') { me.errors.push(formInnerControl.value + is required); } 希望对其他人有所帮助....
猜你喜欢
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 2023-03-13
相关资源
最近更新 更多