【问题标题】:Angular router.navigate won't work from Material AutocompleteAngular router.navigate 不适用于 Material Autocomplete
【发布时间】:2019-07-09 02:45:45
【问题描述】:

我正在为搜索创建一个自动完成控件,我可以在其中查找产品,一旦有人点击其中一个产品,他们应该导航到 URL 中包含该产品 ID 的单个产品页面。

我当前的尝试使用 Angular Material 自动完成功能 (v 7.3.7),并且我已经为这个示例建模 (https://itnext.io/using-angular-6-material-auto-complete-with-async-data-6d89501c4b79)。

虽然搜索部分工作正常并在我尝试从回调方法路由时选择了一个产品,但我收到了一个错误。我怀疑问题是路由器对象对自动完成不可见,可能是因为它在 FormGroup 中。

一些注意事项:

首先,虽然我希望它最终路由到产品页面,但我已将路由简化为仅路由到主页。

我已经将路由器注入到构造函数中,并从一个单独的测试按钮进行了尝试,它工作正常。我在 FormGroup 内外都尝试了测试按钮。

我也尝试过公开路由对象。

工作代码与教程示例非常接近,但我将在这里展示我能做的:

HTML

<form [formGroup]='prodForm'>
  <mat-form-field class="example-full-width">
    <input matInput [matAutocomplete]="auto" formControlName='prodInput'>
  </mat-form-field>

  <mat-autocomplete #auto="matAutocomplete" [displayWith]="navToProd">
    <mat-option *ngIf="isLoading" class="is-loading"><mat-spinner diameter="25"></mat-spinner></mat-option>
    <ng-container *ngIf="!isLoading">
      <mat-option *ngFor="let prod of filteredProds" [value]="prod">
        <img class="example-option-img" [src]="prod.productImage.imagePath" height="35">
        <span>{{ prod.productName }}</span>
        <small> | {{prod.brand.brandName}} | {{prod.category.categoryName}}</small>
      </mat-option>
    </ng-container>
  </mat-autocomplete>

  <div>selected product: {{prodForm.get('prodInput').value | json}}</div>

  <!-- just a test button to see if routing is working outside the control -->
  <button class="btn" (click)="test()">TEST</button>

</form>


还有 ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { FormBuilder, FormGroup } from '@angular/forms';
import { switchMap, debounceTime, tap, finalize } from 'rxjs/operators';

import { CatalogService } from '../shared-services/catalog.service';
import { SrfProduct } from '../data-objects/srf-obj-product';

@Component({
  selector: 'app-test-alpha',
  templateUrl: './test-alpha.component.html',
  styleUrls: [
    '../app.component.scss',
    './test-alpha.component.scss'    
  ]
})
export class TestAlphaComponent implements OnInit {

  filteredProds: SrfProduct[] = [];
  prodForm: FormGroup;
  isLoading = false;  

  constructor(
    private router: Router,
    private fb: FormBuilder,
    private catalogService: CatalogService) { }

  ngOnInit() {
    this.prodForm = this.fb.group({
      prodInput: null
    })

    // ===== GET by search term    
    this.prodForm.get('prodInput').valueChanges
      .pipe(
        debounceTime(300),
        tap(() => this.isLoading = true),
          switchMap(value => this.catalogService.getProductsBySearchTerm(value, 0, 10)
          .pipe(
            finalize(() => this.isLoading = false),
          )
        )
      )
      .subscribe(prods => this.filteredProds = prods);

  }

  navToProd(prod: SrfProduct) {
    if (prod) {
      this.router.navigate(['/home']);   // <- this throws the error
      return prod.productName;
    }
  }

  test() {
    this.router.navigate(['/home']);  // <- but this works ok
  }

}

在所有情况下,当我从 [displayWith]="navToProd" 函数路由时,我都会收到 Cannot read the property navigate' of undefined 错误。

【问题讨论】:

    标签: angular autocomplete angular-material angular-router


    【解决方案1】:

    您收到未定义错误的原因是 此上下文。当您将navToProd 绑定为[displayWith]="navToProd" 之类的输入时,this context 会丢失并给出未定义的错误。阅读一下 javascript 中的此上下文

    事件虽然你修复了未定义的错误,但你仍然以完全错误的方式使用[displayWith]="navToProd"displayWith 用于将选项控制值映射到显示值,如 in docs 所述,这意味着它计算(基于选项值)并返回一个字符串以用作显示文本。它与选择无关。

    如果你想在用户选择一个选项时采取一些行动,你应该使用optionSelectedMatAutoComplete的事件

    如下修改你的html代码

    <mat-autocomplete #auto="matAutocomplete" (optionSelected)="navToProd($event)">
    

    并修改navToProd方法如下

      navToProd(event: MatAutocompleteSelectedEvent) {
        const prod = event.option.value;
        if (prod) {
          this.router.navigate(['/home']); // change the url according to prod
        }
      }
    

    【讨论】:

    • 我在模拟 ng-bootstrap typeahead 替代品时无意中发现了这一点,并在此处的 api 注释中找到了 (selectItem) 事件处理程序。这导致我回过头来更仔细地查看材料 api 说明中的类似事件。无论如何感谢您的回复和解释。
    猜你喜欢
    • 2017-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多