简体   繁体   English

在 angular 中,垫子自动完成功能无法正确过滤

[英]mat autocomplete not filtering properly in angular

I'm customizing angular material select/autocomplete to allow nested dropdowns.我正在自定义 angular 材料选择/自动完成以允许嵌套下拉菜单。

Here, I was trying to search both parent or child values, but it doesn't filtered out.在这里,我试图搜索父值或子值,但它没有被过滤掉。

Also, it should display like Alaska (+2 others).此外,它应该像阿拉斯加(+2 其他)一样显示。

STACKBLITZ堆栈闪电战

<mat-form-field appearance="fill">
  <mat-label>Toppings</mat-label>
    <!-- <input type="text" matInput placeholder="States Group" formControlName="stateGroup" required [matAutocomplete]="autoGroup">
     <mat-autocomplete #autoGroup="matAutocomplete"> -->
           <input type="text" matInput placeholder="Select Users" aria-label="Select Users" matInput [matAutocomplete]="auto" [formControl]="states">
<mat-autocomplete #auto="matAutocomplete">

  <!-- <mat-select [formControl]="states" multiple> -->
    <mat-select-trigger>
      {{states.value ? states.value[0] : ''}}
      <span *ngIf="states.value?.length > 1" class="example-additional-selection">
        (+{{states.value.length - 1}} {{states.value?.length === 2 ? 'other' : 'others'}})
      </span>
    </mat-select-trigger>

  <mat-optgroup *ngFor="let group of stateList">
          <div>
          <mat-checkbox [checked]="group.selected" (change)="toggleParent($event, group)"
            (click)="$event.stopPropagation()">
                    {{group.letter}}
                </mat-checkbox>
          <button mat-button (click)="expandDocumentTypes(group)">
            <mat-icon>keyboard_arrow_down</mat-icon>
          </button>
          </div>  
          <mat-option *ngFor="let name of group.names" [value]="name"
             [ngClass]="isExpandCategory[group.letter] ? 'list-show' : 'list-hide'">
             <mat-checkbox [checked]="group.checked" (change)="toggleSelection($event, name, group)" 
            (click)="$event.stopPropagation()">
                    {{name.type}}
                </mat-checkbox>
          </mat-option>
  </mat-optgroup>

  <!-- </mat-select> -->
</mat-autocomplete>
     <!-- </mat-autocomplete> -->
</mat-form-field>


export class SelectCustomTriggerExample {
  constructor(private _formBuilder: FormBuilder){}

  // stateForm: FormGroup = this._formBuilder.group({
  //   stateGroup: '',
  // });
  // toppings = new FormControl();
  isExpandCategory: boolean[] = [];
  toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
  stateRecord:any = [];
  states = new FormControl();

  expandDocumentTypes(group: any) {
    console.log("expanding dropdown", group);
    this.isExpandCategory[group.letter] = !this.isExpandCategory[group.letter];
    // expand only selected parent dropdown category with that childs
  }

toggleSelection(event:any, name: any, group: any) {
  debugger;
  console.log("toggleSelection", name, event.checked, group);
  if(event.checked) {
    console.log("stastateRecordtelist", this.stateRecord);
    this.stateRecord.push(name.type);
    this.states.setValue(this.stateRecord);
    console.log("toggleselection ", this.states.value);
  }
  else {
      this.stateRecord = this.stateRecord.filter((x:any) => x!== name.type);
      console.log("else toggleselection", name, group, this.states.value);
      this.states.setValue(this.states.value.filter((x:any) => x!== name.type));
      console.log("after filter ", this.states.value);
      //this.states.setValue([]);
  }
}

 toggleParent(event: any, group: any) {
    debugger;
    group.checked = event.checked;
    console.log("event", event.checked, "group", group, "states value", this.states.value);
    let states = this.states.value;
    states = states ? states : [];
    if(event.checked) {
      states.push(...group.names.filter((x: any) => !states.includes(x.type)).map((x: any) => x.type))
    } else {
      console.log("else", states);
      group.names.forEach((x: any) => {
          if(states.indexOf(x.type) > -1) {
            states.splice(states.indexOf(x.type), 1)
          }
        });
    }
    this.states.setValue(states);
    console.log("statesvalue", this.states.value);
      if(!event.checked) {
          this.states.setValue(this.states.value.filter((x:any) => !x.includes(group.names)))
        //this.states.setValue([]);
    }
    console.log("final statesvalue", this.states.value);
    this.stateRecord = this.states.value;
  }

  stateList = [
   {
      "letter":"A",
      "checked":false,
      "names":[
         {
            "id":1,
            "type":"Alabama"
         },
         {
            "id":2,
            "type":"Alaska"
         },
         {
            "id":3,
            "type":"Arizona"
         },
         {
            "id":4,
            "type":"Arkansas"
         }
      ]
   },
   {
      "letter":"C",
      "checked":false,
      "names":[
         {
            "id":8,
            "type":"California"
         },
         {
            "id":9,
            "type":"Colorado"
         },
         {
            "id":10,
            "type":"Connecticut"
         }
      ]
   },
   {
      "letter":"D",
      "checked":false,
      "names":[
         {
            "id":18,
            "type":"Delaware"
         },
         {
            "id":19,
            "type":"Denwer"
         }
      ]
   }
];
}

References:参考:

https://stackblitz.com/edit/angular-evacck-qubgyy https://stackblitz.com/edit/angular-evacck-qubgyy

https://stackblitz.com/angular/eboprqqnooy https://stackblitz.com/angular/eboprqqnooy

Can someone help on this?有人可以帮忙吗?

This task is quite complex and requires more clarifications and maybe can be solved by some dedicated library like https://www.npmjs.com/package/mat-select-autocomplete这个任务非常复杂,需要更多的说明,也许可以通过一些专用库来解决,比如https://www.npmjs.com/package/mat-select-autocomplete

But I like that you're moving forward with this custom control step by step and want to have something better than you already implemented.但我喜欢你一步一步地使用这个自定义控件,并希望拥有比你已经实现的更好的东西。

Let's try to solve two your issues which you pointed out in this question:让我们尝试解决您在此问题中指出的两个问题:

It should filter both parent or child values它应该过滤父值或子值

Angular material allows us to define custom filter . Angular 材料允许我们定义自定义过滤器 You can use similar logic in your example.您可以在示例中使用类似的逻辑。 Just create an Observable which is listener to FormControl changes:只需创建一个Observable来监听FormControl的变化:

this.stateGroupOptions$ = this.states.valueChanges.pipe(
      startWith(EMPTY_STRING),
      ...
      map(value => this._filterGroup(value))
    );
...

private _filterGroup(value: any) {
  if (!this.searching || !value.trim()) {
    return this.stateList;
  }

  value = value.trim().toLowerCase();

  return this.stateList
    .map(group => ({
      ...group,
      names: group.names.filter(item => item.type.toLowerCase().includes(value))
    }))
    .filter(
      group => group.letter.toLowerCase().includes(value) || group.names.length > 0
    );
}

and then use it in your options list然后在您的选项列表中使用它

<mat-optgroup *ngFor="let group of stateGroupOptions$ | async">

It should display like Alaska (+2 others) .它应该像Alaska (+2 others)一样显示。

Again, there is dedicated functionality for this case - displayWith input property同样,这种情况有专门的功能 - displayWith input 属性

@Input() displayWith: ((value: any) => string) | null @Input() displayWith: ((value: any) => string) | null Function that maps an option's control value to its display value in the trigger. @Input() displayWith: ((value: any) => string) | null Function 将选项的控制值映射到触发器中的显示值。

html html

<mat-autocomplete ... [displayWith]="displayWith"

ts ts

displayWith(names: StateName[]) {
  if (!names || !names.length) {
    return "";
  }
  return (
    names[0].type +
    (names.length > 1
      ? ` (+${names.length - 1} ${names.length === 2 ? "other" : "others"})`
      : "")
  );
}

Stackblitz Example Stackblitz 示例

The main trick in this custom implementation is to keep model consistent across different types of data: string (when user starts typying), Array (when you click on checkbox and update control manually) and Object (when you select option from dropdown).此自定义实现中的主要技巧是使 model 在不同类型的数据中保持一致: string (当用户开始输入时)、 Array (当您单击复选框并手动更新控件时)和Object (当您从选项下拉列表中选择 Z99938Z4182F04016EFCF429 时)。

NOTE: you can still optimize it and there are maybe many issue you haven't discovered yet .注意:您仍然可以对其进行优化,并且可能还有很多您尚未发现的问题

Latest version 最新版本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Angular 9 mat-autocomplete 不能与 switchmap 运算符一起正常工作 - Angular 9 mat-autocomplete not working properly with switchmap operator 自动完成不过滤列表项 Angular - AutoComplete not filtering the list items Angular 垫子自动完成中的无限滚动 angular 11 - Infinite scroll in mat-autocomplete angular 11 使用Angular中的服务器过滤功能的Kendo Autocomplete,该如何做? - Kendo Autocomplete with server filtering in Angular, how to? Angular5 - 如何检测垫子自动完成中的空字段或已删除字段? - Angular5 - How to detect empty or deleted field in mat-autocomplete? Angular 6:如何访问 mat-autocomplete 下拉列表中的所有选项值? - Angular 6: how to access ALL option values in mat-autocomplete dropdown? 如何检测在 Angular 中选择了 mat-autocomplete 选项? - How to detect mat-autocomplete option is selected in Angular? Angular 材料自动完成无法正常工作 - Angular material autocomplete doesn't work properly 在JS / Angular中过滤嵌套数组无法正常工作 - Filtering nested arrays in JS/Angular not working properly 按下Tab键时如何选择垫子选项?它应该像垫子自动完成角度6中的输入按钮一样工作 - How can we select mat option when press on tab key?, it should work like enter button in mat-autocomplete angular 6
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM