Angular material Chips Autocomplete

Chips Autocomplete 官网的例子我没法正常使用,无法实现搜索

我的select是个通用组件,现在贴代码:

component.ts

javascript 复制代码
import {
  Component,
  ElementRef,
  forwardRef,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  SimpleChanges,
  ViewChild,
} from '@angular/core';
import { Tag } from '../../models/tag/tag';
import { map, startWith, takeUntil } from 'rxjs/operators';
import { ControlValueAccessor, UntypedFormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
// import { MatChipInputEvent } from '@angular/material/chips';
import { TagService } from '../../services/tag/tag.service';
import { TagType } from '../../enums/TagType';
import { ISearchOptions } from '../../interfaces/SearchOptions';
import { SubscriberWrapperComponent } from '../subscriber-wrapper/subscriber-wrapper.component';

@Component({
  selector: 'app-tags-select',
  templateUrl: './tags-select.component.html',
  styleUrls: ['./tags-select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TagsSelectComponent),
      multi: true,
    },
  ],
})
export class TagsSelectComponent
  extends SubscriberWrapperComponent
  implements ControlValueAccessor, OnChanges, OnInit, OnDestroy
{
  @Input() title: string;
  @Input() disabled: boolean;
  @Input() color: 'primary' | 'accent' | 'warn';
  @Input() type: TagType;
  @Input() tags: Tag[];

  filteredTags: Tag[];
  selectedTags: Tag[] = [];
  separatorKeysCodes: number[] = [ENTER, COMMA];
  tagCtrl = new UntypedFormControl('');
  hideComponent: boolean;

  @ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
  @ViewChild('chipList') chipList: ElementRef;

  constructor(private tagService: TagService) {
    super();
  }

  onChange = (_: any) => {};
  onTouched = () => {};

  async ngOnInit() {
    this.initTags();
    const conditions = [];
    if (this.type) {
      conditions.push({
        key: 'type',
        value: this.type,
        operator: '=',
      });
    }
    this.tags = await this.listTags('', {
      conditions,
    });
    await this.updateFilterTags();
  }

  async listTags(query: string = '', options: ISearchOptions = {}) {
    if (!this.tags) {
      const response = await this.tagService.list(query, options);
      return response.entities;
    } else {
      return this.tags;
    }
  }

  // add(event: MatChipInputEvent): void {
  //   event.chipInput!.clear();

  //   this.tagCtrl.setValue(null);
  // }

  remove(tag: Tag): void {
    const index = this.selectedTags.indexOf(tag);
    if (index >= 0) {
      this.selectedTags.splice(index, 1);
    }
    this.filteredTags.push(tag);
    // this.onChange(this.selectedTags);  
  }

  selected(event: MatAutocompleteSelectedEvent): void {
    this.selectedTags.push(event.option.value);
    this.tagInput.nativeElement.value = '';
    this.tagCtrl.setValue(null);
    // this.onChange(this.selectedTags);
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  writeValue(selectedTags: Tag[] = []): void {
    this.selectedTags = selectedTags ?? [];
    this.updateFilterTags();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.disabled?.currentValue) {
      this.tagCtrl.disable();
    }

    if (changes.tags?.currentValue) {
      this.updateFilterTags();
    }
  }

  initTags() {
    this.tagCtrl.valueChanges
      .pipe(
        takeUntil(this.unsubscribeAll),
        startWith(null),
        map(async (value?: string) => {
          await this.updateFilterTags(value);
        })
      )
      .subscribe();
  }

  async updateFilterTags(value?: string) {
    const conditions = [];
    if (this.type) {
      conditions.push({
        key: 'type',
        value: this.type,
        operator: '=',
      });
    }
    const response = value
    ? this.tags?.filter((tag: Tag) => {
        const regex = new RegExp(`^${value}`, 'i'); 
        return regex.test(tag.title?tag.title:'');
      }) || []
    : this.tags?.slice() || [];
    
    const selectedTagIds = this.selectedTags.map((tag: Tag) => tag.id);
    this.filteredTags = response.filter((tag: Tag) => !selectedTagIds.includes(tag.id));
  }
}

页面.html

html 复制代码
<mat-label>{{title}}</mat-label>
<mat-form-field class="tag-chip-list" *ngIf="!hideComponent">
  <mat-chip-list #chipList aria-label="Tag selection" [disabled]="disabled">
    <mat-chip [color]="color" [class]="color"
              *ngFor="let tag of selectedTags; let i=index"
              (removed)="remove(tag)">
      <button matChipRemove>
        <mat-icon svgIcon="CloseBlue" class="close-icon"></mat-icon>
      </button>
      {{tag.name}}
    </mat-chip>
    <input
      placeholder="Add another tag..."
      #tagInput
      [formControl]="tagCtrl"
      [matAutocomplete]="auto"
      [matChipInputFor]="chipList"
      [matChipInputSeparatorKeyCodes]="separatorKeysCodes">
  </mat-chip-list>
  <mat-autocomplete #auto="matAutocomplete"
                    (optionSelected)="selected($event)">
    <mat-option *ngFor="let tag of filteredTags" [value]="tag"
                [innerHTML]="tag.name">

    </mat-option>
  </mat-autocomplete>
</mat-form-field>
相关推荐
Lee川3 小时前
Milvus 实战:当 RAG 遇上向量数据库,从"玩具 Demo"到"生产可用的"那一步
前端·数据库·人工智能
anOnion4 小时前
构建无障碍组件之Toolbar Pattern
前端·html·交互设计
惊鸿一博4 小时前
图标加载方式_zeroIcon_是否加前缀mdi
开发语言·前端·javascript
2501_940041744 小时前
前端工程化进阶:5个高交互与可视化项目提示词
前端
你很易烊千玺4 小时前
JS 异步 从零讲(大白话 + 真实场景 + 可运行案例)
前端·javascript·vue.js
华洛6 小时前
讲讲如何在传统产品中挖掘AI需求
javascript·产品经理·产品
why技术6 小时前
AI Coding开始进入第四个时代,我还没上车呢!
前端·人工智能·后端
大家的林语冰7 小时前
CSS 已死?DOM 性能黑洞!Pretext 排版革命让你在文本间跳舞,没有 DOM 也能纵享丝滑~
前端·javascript·css
vipbic7 小时前
我也该升级了,陪伴了我7年的博客
前端
Lee川8 小时前
RAG 实战:从一篇掘金文章出发,拆解检索增强生成的全链路
前端·人工智能·后端