项目

列表操作指南

ListService 是一个实用服务,可轻松实现分页、排序和搜索功能。

快速开始

ListService 未在根注入器中提供。这种方式可以在组件销毁时自动清理所有订阅。您可以使用可选的 LIST_QUERY_DEBOUNCE_TIME 令牌来调整防抖行为。

import { ListService } from '@abp/ng.core';
import { BookDto } from '../models';
import { BookService } from '../services';
import { inject } from '@angular/core';

@Component({
  /* 类元数据 */
  providers: [
    // [必需]
    ListService,

    // [可选]
    // 如需不同的防抖时间可提供此令牌
    // 默认值为300,不能为0,不建议低于100
    { provide: LIST_QUERY_DEBOUNCE_TIME, useValue: 500 },
  ],
  template: `
    
  `,
})
class BookComponent {
  items: BookDto[] = [];
  count = 0;

  public readonly list = inject(ListService);
  private bookService = inject(BookService);

  constructor() {
    // 在此处修改 ListService 默认值
    this.list.maxResultCount = 20;
  }

  ngOnInit() {
    // 接收查询参数并返回可观察对象的函数
    const bookStreamCreator = query => this.bookService.getList(query);

    this.list.hookToQuery(bookStreamCreator).subscribe(
      response => {
        this.items = response.items;
        this.count = response.count;
        // 如果使用 OnPush 变更检测策略,
        // 请在此处调用 ChangeDetectorRef 的 detectChanges 方法
      }
    ); // 订阅会在销毁时自动清理
  }
}

注意到 listpublicreadonly 了吗?这是因为我们将在组件模板中直接使用 ListService。这可能被视为反模式,但实现起来更快。您也可以使用公共组件成员来暴露 ListService 实例。

ListService 绑定到 ngx-datatable 的方式如下:

<ngx-datatable
  [rows]="items"
  [count]="count"
  [list]="list"
  default
>
  <!-- 列模板 -->
</ngx-datatable>

使用自定义变量扩展查询

您可以扩展 ListServicehookToQuery 方法的查询参数。

首先,应按如下所示将自己的类型传递给 ListService

public readonly list = inject(ListService<BooksSearchParamsDto>);

然后按以下方式更新 bookStreamCreator 常量:

const bookStreamCreator = (query) => this.bookService.getList({...query, name: '名称'});

您也可以创建自己的参数对象。

定义如下变量:

booksSearchParams = {} as BooksSearchParamsDto;

更新 bookStreamCreator 常量:

const bookStreamCreator = (query) => this.bookService.getList({...query, ...this.booksSearchParams});

然后在 HTML 中添加输入框:

<div class="form-group">
  <input
    class="form control"
    placeholder="名称"
    (keyup.enter)="list.get()"
    [(ngModel)]="booksSearchParams.name"
  />
</div>

当您调用 this.list.get() 方法时,ListService 会发出 hookToQuery 流。

与可观察对象结合使用

您也可以结合使用 Angular 的 AsyncPipe。以下是几种可能的方式:

  book$ = this.list.hookToQuery(query => this.bookService.getListByInput(query));
<!-- 模板简化表示 -->

<ngx-datatable
  [rows]="(book$ | async)?.items || []"
  [count]="(book$ | async)?.totalCount || 0"
  [list]="list"
  default
>
  <!-- 列模板 -->
</ngx-datatable>

<!-- 无需担心,只会发出一个请求 -->

处理请求状态

为处理请求状态,ListService 提供了 requestStatus$ 可观察对象。该可观察对象会发出请求的当前状态,可能为以下值之一:idle(空闲)、loading(加载中)、success(成功)或 error(错误)。这些状态让您可以基于请求状态轻松管理 UI 流程。

请求状态

import { ListService } from '@abp/ng.core';
import { AsyncPipe } from '@angular/common';
import { Component, inject } from '@angular/core';
import { BookDto, BooksService } from './books.service';

@Component({
  selector: 'app-books',
  templateUrl: './books.component.html',
  providers: [ListService, BooksService],
  imports: [AsyncPipe],
})
export class BooksComponent {
  list = inject(ListService);
  booksService = inject(BooksService);

  items = new Array<BookDto>();
  count = 0;

  // 这是一个可观察变量
  requestStatus$ = this.list.requestStatus$;

  ngOnInit(): void {
    this.list
      .hookToQuery(() => this.booksService.getList())
      .subscribe(response => {
        this.items = response.items;
        this.count = response.totalCount;
      });
  }
}
<div class="card">
  <div class="card-header">
    @if (requestStatus$ | async; as status) {
      @switch (status) {
        @case ('loading') {
          <div style="height: 62px">
            <div class="spinner-border" role="status" id="loading">
              <span class="visually-hidden">加载中...</span>
            </div>
          </div>
        }
        @case ('error') {
          <h4>发生错误</h4>
        }
        @default {
          <h4>书籍列表</h4>
        }
      }
    }
  </div>
  <table class="table">
    <thead>
      <tr>
        <th>ID</th>
        <th>名称</th>
      </tr>
    </thead>
    <tbody>
      @for (book of items; track book.id) {
        <tr>
          <td>{{ book.id }}</td>
          <td>{{ book.name }}</td>
        </tr>
      }
    </tbody>
  </table>
</div>

如何在创建/更新/删除时刷新表格

ListService 暴露了 get 方法来使用当前查询触发请求。因此,基本上,当创建、更新或删除操作完成时,您可以调用 this.list.get();,它将再次调用已连接的流创建器。

  this.bookService.createByInput(form.value)
    .subscribe(() => {
      this.list.get();

      // 其他订阅逻辑
    });

如何在表格中实现服务端搜索

ListService 暴露了 filter 属性,该属性将使用当前查询和给定的搜索字符串触发请求。您只需将其与输入元素进行双向绑定即可。

<!-- 简化表示 -->

<input type="text" name="search" [(ngModel)]="list.filter">

ABP 没有内置的过滤机制。您需要自行实现并在后端处理 filter 属性。

在本文档中