如何使用更少的代码和良好实践以 Angular 形式处理许多订阅

How to deal with many subscriptions in an Angular form with less code and good practices

我有一个 Angular 表单,其中有许多 select 选项,这些 select 选项由订阅管理,但我发现每个订阅都有太多代码。

有人可以建议我减少代码量的好方法吗?

提前致谢!

这里有一个例子:https://github.com/jreategui07/testing-subscriptions-form

模拟服务器运行:mockserver -p 8080 -m mock

    this.colorSC = this.catalogueService.getColors().subscribe(
      (response: any) => {
        console.log(response.body);
        this.colorsData = response.body;
      },
      error => 
      {
        console.warn('Error', error);
      }
    );

    this.brandSC = this.catalogueService.getSizes().subscribe(
      (response: any) => {
        console.log(response.body);
        this.brandsData = response.body;
      },
      error => 
      {
        console.warn('Error', error);
      }
    );

    this.sizeSC = this.catalogueService.getFruits().subscribe(
      (response: any) => {
        console.log(response.body);
        this.sizesData = response.body;
      },
      error => 
      {
        console.warn('Error', error);
      }
    );

    this.fruitSC = this.catalogueService.getColors().subscribe(
      (response: any) => {
        console.log(response.body);
        this.fruitsData = response.body;
      },
      error => 
      {
        console.warn('Error', error);
      }
    );

您可以将可观察对象连接到 select 的选项作为可观察对象,并使用异步管道绑定数据

为选项声明 Observables

colorSC$ : Observable<any>;
brandSC$ : Observable<any>;
sizeSC$  : Observable<any>;
fruitSC$ : Observable<any>;

注意:使用接口而不是任何接口我不确定数据类型,所以对于这个答案我使用的是任何接口。你可以定义你的接口并在这里使用它们来声明这些 Observable 变量

您现在可以分配这些可观察值,您可以在

中完成
constructor(private fb: FormBuilder, private catalogueService: CatalogueService) { 
  this.anyForm = this.fb.group({
    color: [''],
    brand: [''],
    size: [''],
    fruit: [''],
  });

  this.colorSC$ = catalogueService.getColors();
  this.brandSC$ = catalogueService.getSizes();
  this.sizeSC$  = catalogueService.getFruits();
  this.fruitSC$ = catalogueService.getColors();
}

并在您的模板中使用异步管道获取项目,例如:colorSC$ | async 请注意,对代码和描述进行安全检查,以便模板不会出错 item?.codeitem?.description

<form (ngSubmit)="onSubmit()" [formGroup]="anyForm">
  <label>Color:</label>
  <select formControlName="color">
    <option *ngFor="let item of colorSC$ | async" [value]="item?.code">{{ item?.description }}</option>
  </select>
  <br><br>

  <label>Brand:</label>
  <select formControlName="brand">
    <option *ngFor="let item of brandSC$ | async" [value]="item?.code">{{ item?.description }}</option>
  </select>
  <br><br>

  <label>Size:</label>
  <select formControlName="size">
    <option *ngFor="let item of this.sizeSC$ | async" [value]="item?.code">{{ item?.description }}</option>
  </select>
  <br><br>

  <label>Fruit:</label>
  <select formControlName="fruit">
    <option *ngFor="let item of fruitSC$ | async" [value]="item?.code">{{ item?.description }}</option>
  </select>
  <br><br>

  <button type="submit">Ok</button>
</form>

在您的服务中,您不必映射它们,因为您没有做任何有用的事情,您返回的是同样的东西

export class CatalogueService {
  requestOptions: any;
  constructor(public http: HttpClient) {
    const headers = new HttpHeaders({
      'Content-Type': 'text/plain; charset=utf-8'
    });
    this.requestOptions = {headers, observe: 'response'};
  }
  getColors() {
    return this.http.get('http://localhost:8080/getColors', this.requestOptions).pipe(map(res => res.body));
  }
  getBrands() {
    return this.http.get('http://localhost:8080/getBrands', this.requestOptions).pipe(map(res => res.body));
  }
  getSizes() {
    return this.http.get('http://localhost:8080/getSizes', this.requestOptions).pipe(map(res => res.body));
  }
  getFruits() {
    return this.http.get('http://localhost:8080/getFruits', this.requestOptions).pipe(map(res => res.body));
  }
}

因此您可以摆脱 ngOnInit 和 ngOnDestroy,因为在这个用例中您不需要它们。最好在构造函数级别连接它,因为它们本身可以在构造函数级别运行