【问题标题】:Assigning JSON response to mat-autocomplete将 JSON 响应分配给 mat-autocomplete
【发布时间】:2020-05-05 08:32:16
【问题描述】:

我有一个自动完成功能,可以与下面组件中的 options 变量一起使用,但我无法让它指向 JSON 对象 this.posts this.posts 中有一个字段名为 artistName 我是试图以列表形式返回自动完成。如果我尝试将 this.posts 分配给

  <mat-option *ngFor="let option of this.posts| async" [value]="option">
                {{option}}
              </mat-option>

这是不允许的。我不明白如何从 JSON 响应中获取我的结果以显示在自动完成中。我意识到this.posts 是一个对象,我正在寻找特定的字段artistName,但我想我无法弄清楚如何正确连接它。感谢您的帮助

示例输入和返回(arti 是类型值)

     arti
     [ { _id: 5e20c5a139a92512cc7df63c, artistName: 'artist' },   {
         _id: 5e2350c7f88cfb331c4f67de, artistName: 'artist1' } ]

组件

  import {
  Component,
  HostListener,
  OnDestroy,
  OnInit,
  Input,
  AfterViewInit
} from "@angular/core";
import { AuthService } from "../auth.service";
import { Router } from "@angular/router";
import { SearchService } from "./search.service";
import { DeviceDetectorService } from "ngx-device-detector";
import { Subject } from "rxjs";
import { takeUntil, startWith, map } from "rxjs/operators";

import { Store } from "@ngrx/store";
import { Observable } from "rxjs";
import { SubmitListingService } from "../submit-listing/submit-auction.service";
import { Listing } from "../submit-listing/listing.model";
import { FormControl } from "@angular/forms";

interface AppState {
  message: string;
}
@Component({
  selector: "app-header",
  templateUrl: "./header.component.html",
  styleUrls: ["./header.component.css"]
})
export class HeaderComponent implements OnInit, OnDestroy, AfterViewInit {
  message: string;
  destroy = new Subject();
  userIsAuthenticated = false;
  searchField: string;
  posts: Listing[] = [];
  mobile: boolean;
  userId: string;
  test: string;
  isValid = false;
  message$: Observable<string>;
  timeout: any = null;
  isOpen = false;
  myControl = new FormControl();
  options: string[] = ["One", "Two", "Three"];
  filteredOptions: Observable<string[]>;

  constructor(
    private authService: AuthService,
    private searchService: SearchService,
    public router: Router,
    private mobileDetect: DeviceDetectorService,
    private store: Store<AppState>,
    private submitListingService: SubmitListingService
  ) {
    this.message$ = this.store.select("message");
  }

  click() {
    if (!this.isOpen) {
      this.store.dispatch({ type: "true" });
      this.isOpen = true;
    } else if (this.isOpen) {
      this.store.dispatch({ type: "false" });
      this.isOpen = false;
    }
  }

  onLogout() {
    this.authService.logout();
  }

  hideLogoutButton() {
    if (
      (this.userIsAuthenticated &&
        !this.mobile &&
        this.router.url !== "/listings") ||
      (this.userIsAuthenticated &&
        !this.mobile &&
        this.router.url === "/listings")
    ) {
      return true;
    } else {
      return false;
    }
  }
  ngAfterViewInit() {}

  ngOnInit() {
    this.mobile = this.mobileDetect.isMobile();
    this.userId = this.authService.getUserId();
    this.test = this.router.url;
    this.userIsAuthenticated = this.authService.getIsAuth();
    this.authService
      .getAuthStatusListener()
      .pipe(takeUntil(this.destroy))
      .subscribe(isAuthenticated => {
        this.userIsAuthenticated = isAuthenticated;
      });

    this.searchService.currentMessage
      .pipe(takeUntil(this.destroy))
      .subscribe(message => (this.message = message));

    this.filteredOptions = this.myControl.valueChanges.pipe(
      startWith(""),
      map(value => this._filter(value))
    );

    console.log(this.filteredOptions);
  }
  private onKeySearch(event: any) {
    clearTimeout(this.timeout);
    var $this = this;
    this.timeout = setTimeout(function() {
      if (event.keyCode !== 13) {
        $this.executeListing(event.target.value);
      }
    }, 1000);
  }

  private executeListing(artistName: string) {
    if (artistName.length > 3) {
      //  alert(artistName);
      this.submitListingService.getArtistId(artistName).subscribe(res => {
        console.log("res");
        console.log(res);
        this.posts = res.posts;
        console.log(this.posts);
      });
    }
  }
  ngOnDestroy() {
    this.destroy.next();
    this.destroy.complete();
  }
  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.options.filter(
      option => option.toLowerCase().indexOf(filterValue) === 0
    );
  }
}

html

   <form class="example-form">
          <mat-form-field class="searchField" [ngStyle]="{'font-size.px': 12}" appearance="outline">
            <mat-label id="placeholder">Find Artist</mat-label>
            <input type="text" placeholder="Pick one" name="artistName" aria-label="Number" matInput
              [formControl]="myControl" (keyup)="onKeySearch($event)" [matAutocomplete]="auto">
            <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
              <mat-option *ngFor="let option of filteredOptions | async" [value]="option">
                {{option}}
              </mat-option>
            </mat-autocomplete>
          </mat-form-field>
        </form>


【问题讨论】:

    标签: angular mat-autocomplete


    【解决方案1】:

    不要在模板中使用 this 引用 TypeScript 变量(它是隐式的)。此外,您的posts 属性不是Observable,因此您不需要async 管道。最后一件事,您的 option 变量引用了具有 _idartistName 属性的 Listing,因此您必须将它们正确设置为 [value] 和插值显示文本。

    另一个对解决方案没有影响的细节(只是清洁问题):在您的“等待用户停止输入”实现中,使用箭头功能,然后您可以参考this而不保留参考用var $this = this;就可以了

    您的 HTML 应该是:

    <mat-option *ngFor="let post of posts" [value]="post._id">
        {{post.artistName}}
    </mat-option>
    

    您的onKeySearch 函数可能是:

    private onKeySearch(event: any) {
        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
            if (event.keyCode !== 13) {
                this.executeListing(event.target.value);
            }
        }, 1000);
    }
    

    【讨论】:

      【解决方案2】:

      您无法访问 .html 文件中的this 运算符。

      替换,

      <mat-option *ngFor="let option of this.posts| async" [value]="option">
                      {{option}}
                    </mat-option>
      

      <mat-option *ngFor="let option of posts| async" [value]="option"> //remove this from this.posts
                      {{option}} //Here option will the object from the Array posts , therefore you need to provide like {{option.key}} here key will be any key of value you want to display.
                    </mat-option>
      

      如果

      posts = [ { _id: 5e20c5a139a92512cc7df63c, artistName: 'artist' },   {
               _id: 5e2350c7f88cfb331c4f67de, artistName: 'artist1' } ]
      

      那么

      <mat-option *ngFor="let option of posts" [value]="option"> //remove this from this.posts
                          {{option.artistName}}
                        </mat-option>
      

      【讨论】:

      • 如果我用你最后的代码 sn-p 替换我的代码,那么我得到"InvalidPipeArgument: '' for pipe 'AsyncPipe'"
      • 从代码中删除| async ,它将起作用。 @user6680
      【解决方案3】:

      posts: Listing[] = []; 帖子不可观察,请使用

      <mat-option *ngFor="let option of posts" [value]="option">
                          {{option.artistName}}
                        </mat-option>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-19
        • 2019-10-11
        • 2018-04-03
        • 1970-01-01
        • 2018-09-16
        • 2018-12-20
        • 2016-04-20
        • 1970-01-01
        相关资源
        最近更新 更多