【问题标题】:Refer to autocomplete inputs generated dynamically with ngFor loop请参阅使用 ngFor 循环动态生成的自动完成输入
【发布时间】:2019-10-27 21:01:42
【问题描述】:

我正在设置一个发票 Angular 页面,其中行是动态添加的,每一行都应该有一个自己的自动完成输入和其他不同的输入。如何在我的组件内独立引用每个自动完成输入,这样我就可以在里面使用正确的输入我的 displayWith 函数?

我的问题与this 类似,但我在那里找不到正确答案:(

HTML

<tr *ngFor="let ligneFacture of facture.lignesFacture; let i =index;">
    <td width="5%" align="center">
        <button type="button" class="button btn-primary"
                style="border-radius: 50px;" disabled><span>{{i+1}}</span>
        </button>
    </td>
    <td width="25%">
        <form>
            <mat-form-field>
                <input type="text" class="form-control" matInput
                       (ngModelChange)="watchChangesArticle($event)"
                       (focus)="cursorFocusArticle($event)"
                       [matAutocomplete]="autoArticle"
                       [ngModelOptions]="{standalone: true}"
                       [(ngModel)]="ligneFacture.articleId">
                <mat-autocomplete #autoArticle="matAutocomplete"
                                  [displayWith]="displayFnArticle.bind(this)"
                                  [autoActiveFirstOption]="true">
                    <mat-option *ngFor="let article of articles;"
                                [value]="article.id">
                        {{article.libelle}}
                    </mat-option>
                </mat-autocomplete>
            </mat-form-field>
        </form>
    </td>
    <td width="10%"><input type="text" class="form-control"
                           style="text-align: center"
                           [ngModelOptions]="{standalone: true}"
                           [(ngModel)]="ligneFacture.unite"/>
    <td width="10%"><input type="number" class="form-control" #quantity
                           id="quantity{{i+1}}"
                           [ngModelOptions]="{standalone: true}"
                           [(ngModel)]="ligneFacture.quantite"/>
    </td>
    <td width="13%">
        <div class="input-group">
            <input type="number" class="form-control"
                   [ngModelOptions]="{standalone: true}"
                   [(ngModel)]="ligneFacture.tauxTva" readonly/>
            <div class="input-group-append">
                <span class="input-group-text">%</span>
            </div>
        </div>
    </td>

    <td width="15%"><input type="number" class="form-control"
                           [ngModelOptions]="{standalone: true}"
                           [(ngModel)]="ligneFacture.prixUnitaire" tabindex="-1"
                           [value]="updateChanges(ligneFacture)"
                           readonly/></td>

    <td width="15%"><input type="number" class="form-control"
                           [ngModelOptions]="{standalone: true}"
                           [(ngModel)]="ligneFacture.prixTotal" tabindex="-1" readonly/>
    </td>
    <td>
        <div>
            <button type="button" class="btn btn-danger"
                    (click)="removeLine(ligneFacture)" tabindex="-1">
                <span>[X]</span>
            </button>
        </div>
    </td>
</tr>
<br>
<tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td colspan="2" align="right">
        <button type="button" class="btn btn-primary" (click)="addLine()">
            <span>[+] Ajouter une ligne</span>
        </button>
    </td>
</tr>

TS:

export class FactureUpdateComponent implements OnInit {
    @ViewChild('autoArticle') matAutocompleteArticle: MatAutocomplete;
    //
    //

    displayFnArticle(item) {
        const matOptions = this.matAutocompleteArticle.options.filter(x => x.value === item);
        if (matOptions.length !== 0) {
            setTimeout(() => {
                const element = document.getElementById('quantity' + this.facture.lignesFacture.length);
                element.focus();
            }, 0);
            return matOptions.map(x => x.viewValue)[0];
        } else {
            return this.facture.lignesFacture.filter(x => x.articleId === item).map(x => x.articleLibelle);
        }
    }

    watchChangesArticle(event, ligneFacture: ILigneFacture) {
        this.articleService.queryByKeyword(event, this.req).subscribe(
            (res: HttpResponse<IArticle[]>) => {
                ligneFacture.articles = res.body;
            },
            (res: HttpErrorResponse) => this.onError(res.message)
        );
    }

    cursorFocusArticle(event, ligneFacture: ILigneFacture) {
        if (event.target.value === '') {
            this.articleService.queryByKeyword('', this.req).subscribe(
                (res: HttpResponse<IArticle[]>) => {
                    ligneFacture.articles = res.body;
                },
                (res: HttpErrorResponse) => this.onError(res.message)
            );
        }
    }
}

预期结果:在 displayFnArticle 函数中,我可以访问当前行的自动完成输入

Actual result:我刚刚访问了相同的第一个自动完成输入 id,这可能导致 following dysfunction

【问题讨论】:

    标签: angular viewchild mat-autocomplete


    【解决方案1】:

    您可以在那里使用模板引用。文档:https://angular.io/guide/template-syntax#template-reference-variables--var-.

    示例在这里:https://stackblitz.com/edit/angular-template-ref-with-fn

    所以你有这样的 HTML:

    <button *ngFor="let i of array" #ref (click)="doStuff(ref)" class="{{ 'a' + i }}">{{ 'a' + i }}</button>
    

    你可以这样处理:

    doStuff(instance: HTMLElement) {
      console.log('>> stuff', instance.classList);
    }
    

    这只是一个简单元素的示例,但您可以使用 MatAutocomplete 来做同样的事情。

    【讨论】:

    • 感谢您的回复,但这不适用于 DisplayWith 函数,因为我无法传递引用参数我只能传递 articleId 参数(我的代码 TS 中的项目)
    • 你不能修改你的代码吗? :) 无论如何,您可以根据需要以任何方式装饰显示屏。就像displayFnArticle(item, ref)displayFnArticleDecorated(item, ref) 一样,它会用item 调用原始displayFnArticle
    • 实际上,虽然我之前尝试在模板中使用 displayWith 函数传递多个参数,但现在通过一些尝试和您对模板引用的帮助,我得到了一个解决方案,我现在可以使用当前的自动完成输入,谢谢!
    【解决方案2】:

    我在 cmets 中找到了有关模板引用变量的一些帮助的解决方案:

    现在,我可以直接在我的组件中访问当前的自动完成功能,不再需要 @ViewChild

    HTML:

      <mat-autocomplete #autoArticle="matAutocomplete" #currentAutocomplete
            [displayWith]="displayFnArticle.bind(this, currentAutocomplete)" [autoActiveFirstOption]="true">
              <mat-option *ngFor="let article of articles;"
                                    [value]="article.id">
                            {{article.libelle}}
              </mat-option>
      </mat-autocomplete>
    

    TS:

        displayFnArticle(autocomplete: MatAutocomplete, item) {
            const matOptions = autocomplete.options.filter(x => x.value === item);
            if (matOptions.length !== 0) {
                setTimeout(() => {
                    const element = document.getElementById('quantity' + this.facture.lignesFacture.length);
                    element.focus();
                }, 0);
                return matOptions.map(x => x.viewValue)[0];
            } else {
                return this.facture.lignesFacture.filter(x => x.articleId === item).map(x => x.articleLibelle);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-02
      相关资源
      最近更新 更多