【问题标题】:mat-selection-list losing selection when paginatingmat-selection-list 分页时丢失选择
【发布时间】:2020-10-23 21:13:19
【问题描述】:

我整天都在尝试让mat-selection-list 在刷新数据时保留选定的对象,即。分页但没有成功。

如果我在第 1 页中选择对象 A ({name, id}),然后切换到第 2 页并返回第 1 页,我希望对象 A 仍被标记为已选中,但这不会发生,我输了我的想法。

我已经尝试了几件事:

  1. 2路绑定[(ngModel)]="selectedOptions" [compareWith]="compareFunction"。但是当我切换到第 2 页时,由于 2 路绑定,mat-selection-list 会自动清除 selectedOptions,因为在我切换到第 2 页时它无法在列表中找到对象。

Stackblitz demo 1

  1. 使用带有[formControl]="itemsControl" (selectionChange)="onSelectionChanged($event)"form.setValue``. This way the mat-selection-listdoesn' clear it but when returning to page 1 objects are no rechecked automatically. If I select one thenonSelectionChange 的响应式表单将当前表单报告为唯一选定的对象。

Stackblitz demo 2

我的想法已经用完了,用谷歌搜索了几个小时,我开始认为这是一个错误?

非常感谢任何帮助。

【问题讨论】:

  • 在将项目插入现有列表时,我看到了非常相似的行为。即使通过[selected]="item.selected" 设置选定项目状态,即使{{ item.selected }} 显然仍然为真,它也会被取消选中。

标签: angular angular-material


【解决方案1】:

您应该仅在选择更改时更新 selectedOptions 变量。

onSelectionChanged(event) 事件类型是MatSelectionListChange,从docs 我们可以看到。您可以访问已选择或未选择的选项。通过这种方式,您可以知道何时选择了一个选项以及哪个选项。

所以我介绍了一个性能技巧。 selectedOptions 是一个对象,其中keytypesOfShoe id,值是typesOfShoes

这将帮助我们比添加-删除数组更快地添加和删除项目。

onSelectionChanged(event) {
    const isSelected = event.option.selected;
    const value = event.option.value;

    if (isSelected) {
      this.selectedOptions[value.id] = value;
    } else {
      delete this.selectedOptions[value.id];
    }

    this.form.setValue({
      selected: Object.values(this.selectedOptions)
    });
  }

工作示例https://stackblitz.com/edit/angular-3fffzf-faqvxp?file=app%2Flist-selection-example.ts

【讨论】:

  • 感谢您提供的信息,但是当我使用您的示例时,如果我只是切换到第 2 页和第 1 页,对象就会被取消选中。
  • 抱歉没有保存.-.请再次检查。
【解决方案2】:

HTML 文件

<mat-selection-list (selectionChange)="changeSelection($event)">
  <mat-list-option [selected]="shoe.isSelected" *ngFor="let shoe of typesOfShoes"  [value]="shoe">
    {{shoe.name}}
  </mat-list-option>
</mat-selection-list>

<button (click)="switchPage(1)">Page 1</button>
<button (click)="switchPage(2)">Page 2</button>

TS 文件

selectedItems: any[] = [];
  typesOfShoes: { name: string, id: number, isSelected: boolean }[] = [
    {name: 'Boots', id: 1, isSelected: false},
    {name: 'Clogs', id: 2, isSelected: false},
    {name: 'Loafers', id: 3, isSelected: false},
    {name: 'Moccasins', id: 4, isSelected: false},
    {name: 'Sneakers', id: 5, isSelected: false}
  ];

  switchPage(page: number): void {
    if (page === 1) {
      this.typesOfShoes = [
        {name: 'Boots', id: 1, isSelected: false},
        {name: 'Clogs', id: 2, isSelected: false},
        {name: 'Loafers', id: 3, isSelected: false},
        {name: 'Moccasins', id: 4, isSelected: false},
        {name: 'Sneakers', id: 5, isSelected: false}
      ];
    } else {
      this.typesOfShoes = [
        {name: 'Flyers', id: 6, isSelected: false},
        {name: 'Dr.Martens', id: 7, isSelected: false},
      ];
    }
    this.selectedItems.forEach(j => {
      this.typesOfShoes.forEach(i => {
     
        if (j.id === i.id) {
          i.isSelected = true;
        }
      });
    });
  }

  changeSelection($event: MatSelectionListChange): void {
    if ($event.options[0].selected) {
      this.selectedItems.push($event.options[0].value);
    } else {
      this.selectedItems.filter(i => i.id !== $event.options[0].value.id);
    }
  }

请不要在这里使用 NgModel 或 Form,因为状态是可变的。 我已将 isSelected 添加到模型中,这是最稳定的方式,也是最受欢迎的方式,经典且不会破坏。

这是最接近您的解决方案的添加数组和操作它们

【讨论】:

    【解决方案3】:

    我会创建一个属性来存储选择并在新的更新时进行新的选择

    下面是我的代码,它使用响应式方法来启用动态数量的项目,而不是对选择中的项目进行硬编码

    export class ListSelectionExample {
      selectedOptions = [{ name: "Boots", id: 1 }];
      selectedOptionsTemp = this.selectedOptions;
      compareFunction = (o1: any, o2: any) => o1.id === o2.id;
    
      typesOfShoes: { name: string; id: number }[] = [
        { name: "Boots", id: 1 },
        { name: "Clogs", id: 2 },
        { name: "Loafers", id: 3 },
        { name: "Moccasins", id: 4 },
        { name: "Sneakers", id: 5 },
        { name: "Flyers", id: 6 },
        { name: "Dr.Martens", id: 7 }
      ];
    
      typesOfShoes$ = of(this.typesOfShoes);
    
      selectedPageSubject$ = new BehaviorSubject(1);
      selectedPage$ = this.selectedPageSubject$.asObservable();
    
      typesOfShoesFiltered$ = combineLatest([
        this.typesOfShoes$,
        this.selectedPage$
      ]).pipe(
        map(([shoes, selected]) => shoes.slice((selected - 1) * 5, selected * 5))
      );
    
      form: FormGroup = this.formBuilder.group({
        selected: [this.selectedOptions]
      });
      get selected(): FormControl {
        return this.form.get("selected") as FormControl;
      }
      @ViewChild("selectionList") selectionList: MatSelectionList;
    
      constructor(private formBuilder: FormBuilder) {}
    
      switchPage = (page: number) => this.selectedPageSubject$.next(page);
    
      onSelectionChanged(event) {
        const selected = [
          ...new Set(
            [...this.selectedOptionsTemp, ...this.selectedOptions].map(item =>
              JSON.stringify(item)
            )
          )
        ].map(item => JSON.parse(item));
        this.selectedOptionsTemp = selected;
        this.selected.setValue(selected);
      }
    }
    
    <form [formGroup]="form">
        <mat-selection-list #selectionList [compareWith]="compareFunction"  [(ngModel)]="selectedOptions"
      [ngModelOptions]="{standalone: true}"
            (selectionChange)="onSelectionChanged($event)">
            <mat-list-option *ngFor="let item of typesOfShoesFiltered$ | async" [value]="item">
                {{item.name}}
            </mat-list-option>
        </mat-selection-list>
    
        <button (click)="switchPage(1)">Page 1</button>
        <button (click)="switchPage(2)">Page 2</button>
    
        <pre>
      form.value: {{form.value | json}}
      <!-- Copyright 2018 Google Inc. All Rights Reserved.
        Use of this source code is governed by an MIT-style license that
        can be found in the LICENSE file at http://angular.io/license -->
    </pre>
    

    Link to stackblitz demo

    【讨论】:

    • 感谢您的详细解释。虽然在示例中,如果我只单击“第 2 页”,然后单击“第 1 页”,您会看到被选中的项目不再是..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2020-03-24
    • 1970-01-01
    • 2021-10-13
    • 2020-05-09
    • 2018-11-11
    • 1970-01-01
    相关资源
    最近更新 更多