【问题标题】:Angular: Iterate over ngForm controls?Angular:迭代 ngForm 控件?
【发布时间】:2017-08-16 17:10:10
【问题描述】:

目标是当用户单击按钮转到下一页时,阻止用户继续并在页面部分填写但无效时显示错误指示符。

在模板驱动的表单中,我有几个容器元素使用NgModelGroup 属性来表示表单中的“页面”。在我的组件中,我想引用这个集合,以便可以使用索引访问它们。由于我无法获得这个集合(@AJT_82 cmets 为什么在下面),这是我的方法:

我创建了一个类来保存有关页面的信息。

export class Page
{
    title: string;
    hasError: boolean;  //should the page display an error indicator
}

在我的组件中,我在 ngOnInit 中填充了一个数组 pages: Page[]

ngOnInit()
{
    this.pages = [{title: "Page 1", hasError: false},
                  {title: "Page 2", hasError: false},
                  {title: "Page 3", hasError: false}]
}

@DeborahK 在她的回答中给了我

this.form.form.get('pg1')) 

获取名为'pg' + currentPg+1 的个人ngModelGroup(+1 以匹配视图,因为数组从 0 开始),然后我可以在单击事件中使用它,这将导致 A)转到下一页或 B) 将 hasError 属性设置为 true 并且不转到下一页。

let p = this.form.form.get("pg"+ (this.currentPg+1));
//if the page is partially filled out but not valid
if(p.invalid && p.dirty)
  this.pages[this.currentPg].hasError = true;
else
{
  //even if it's false, re-false it ;)
  this.pages[this.currentPg].hasError = false;

  //continue to next page. 
  //i.e. this.currentPg++ or this.currentPg--
}

返回模板,要在选项卡或页面上显示错误指示符,我只需检查pages[currentPg].hasError 属性。在选项卡元素上分配“有错误”类以设置选项卡的样式。

<div id="tabs">
  <a *ngFor="let p of pages" 
     [ngClass]="(p.hasError ? ' has-error' : '')"><p>{{p.title}}</p></a>
</div>

<form #f="ngForm">
  <div ngModelGroup="pg1"> <!-- pages[0] -->
    <div id="errorBlock" *ngIf="pages[currentPg].hasError">
      You had an error.
    </div>
    <div>
      <input ngModel/>
      <input ngModel/>
    </div>
    <div>
      <input ngModel/>
      <input ngModel/>
    </div>
  </div>
  <div ngModelGroup="pg2"> <!-- pages[1] -->
    <input ngModel/>
  </div>
</form>

这是示例的组件:

...
currentPg: number = 0;
pages: Page[] = [];
@ViewChild('f') public form: NgForm;

ngOnInit()
{
    this.pages = [{title: "Page 1", hasError: false},
                  {title: "Page 2", hasError: false},
                  {title: "Page 3", hasError: false}]
}

NextPage()
{
  let p = this.form.form.get("pg"+ (this.currentPg+1));
  //if the page is partially filled out but not valid
  if(p.invalid && p.dirty)
    this.pages[this.currentPg].hasError = true;
  else
  {
    //even if it's false, re-false it ;)
    this.pages[this.currentPg].hasError = false;

    //Do navigation logic. 
    //i.e. this.currentPg++ or this.currentPg--
  }
}

同样,如果有办法获取 ngModelGroups 的集合并像数组一样使用它,那么很多问题都可以解决。

【问题讨论】:

  • 什么是@ViewChild('f') this.tabs 是什么?
  • 您没有附加对您正在使用的表单的引用查看子
  • 但你可以看到我想要达到的目标:不,我不能。说明您想要实现的目标。
  • 首先,您的 ViewChild 引用是错误的。您在 html 中将其定义为 #form,但在 ts 文件中使用 'f'。
  • 没有表单控件,但试图使表单组的数组给出空数组。但是,如果我把它放在ngAfterViewChecked() 中,它会正确显示数组,但是把它放在那里或任何其他你无法控制何时执行的生命周期钩子是没有意义的。为什么要更改为反应形式的另一个原因:P

标签: angular


【解决方案1】:

这段代码对我有用:

    Object.keys((<FormGroup>this.form.form.get('pg1')).controls).forEach(element => {
        console.log(element);
    });

但关键问题(根据您问题下方的 cmets)是 此代码所在的位置。我将它添加为提交按钮过程的一部分。

在 ngOnInit、ngAfterViewInit 和 ngAfterViewChecked 中,这些元素的值为 null/未定义。

如果你只需要知道表单组是否有效,你可以这样做:

    let isValid = this.form.form.get('pg1').valid;

或者,您可以使用选项卡式页面并在任何出现验证错误的页面上显示错误图标,如下所示:

在这个例子中,我使用的是模板驱动的表单。表单上的每个输入元素如下所示:

        <div class="form-group" 
                [ngClass]="{'has-error': (productNameVar.touched || 
                                          productNameVar.dirty || product.id !== 0) && 
                                          !productNameVar.valid }">
            <label class="col-md-2 control-label" 
                    for="productNameId">Product Name</label>

            <div class="col-md-8">
                <input class="form-control" 
                        id="productNameId" 
                        type="text" 
                        placeholder="Name (required)"
                        required
                        minlength="3"
                        [(ngModel)] = product.productName
                        name="productName"
                        #productNameVar="ngModel" />
                <span class="help-block" *ngIf="(productNameVar.touched ||
                                                 productNameVar.dirty || product.id !== 0) &&
                                                 productNameVar.errors">
                    <span *ngIf="productNameVar.errors.required">
                        Product name is required.
                    </span>
                    <span *ngIf="productNameVar.errors.minlength">
                        Product name must be at least three characters.
                    </span>
                </span>
            </div>
        </div>

您可以在此处找到此示例的完整代码:https://github.com/DeborahK/Angular-Routing 在 APM-Final 文件夹中。 (这是我的“Angular Routing”Pluralsight 课程中的代码。)

【讨论】:

  • 谢谢,我之前尝试过,但正如你所说,它在 ngOnInit 中未定义,所以我认为我做错了。我可以添加一个initialized: boolean 并调用函数NextPage(){ if(!initialized){ initialized = true; /*Object.keys code goes here */} else {//proceed to next page} },这样在转到下一页之前,您可以获得所有控件。但是,那是糟糕的设计。我真的不喜欢这是一个“问题:碰壁;解决方案:重新开始”有点交易,但反应式表单可能是答案..
  • 你到底想做什么?为什么需要获取所有控件名称?你在和他们做点什么吗?
  • 我将表单分成页面(&lt;div ngModelGroup&gt;&lt;!--controls go here--&gt;&lt;/div&gt;),我可以在它们之间来回移动,但是如果当前页面无效,我想阻止用户转到下一页( &lt;button type="button" (click)="pages[currentPg].invalid ? showErrors = true : showErrors=false;Next()"&gt; ),对于属于该页面的控件,使用 *ngIf="showErrors" 显示其验证错误
  • 您应该能够完全做到这一点,而无需遍历表单上的所有控件?另外,只是为了另一种方法......我使用标签来做类似的事情,而不是阻止移动到其他标签,我只是在标签上添加了一个错误图标。我将在我的答案中添加屏幕截图。
  • 我也在使用选项卡,但我不想显示页面的单个错误,而是希望显示属于该页面内部而不是任何其他页面的每个控件的验证元素。我正在使用整数切换页面,因此按索引访问页面元素会很有帮助
【解决方案2】:
foo( f: NgForm ){
    Object.values(f.controls).forEach( ctl => {
          console.log(ctl);
    } );
}

【讨论】:

    猜你喜欢
    • 2017-07-03
    • 1970-01-01
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    相关资源
    最近更新 更多