简体   繁体   English

使用@ngrx/data 和@ngrx/entity 在存储中格式化数据,而不是在组件(订阅者)中

[英]Format data in store with @ngrx/data and @ngrx/entity, not in component (subscriber)

While working with ngrx/data I find myself parsing and formatting data from the store in multiple places: converting strings to date objects or formatting strings.在使用ngrx/data时,我发现自己在多个地方解析和格式化来自商店的数据:将字符串转换为日期对象或格式化字符串。 I recently discovered filterFn which lets me fetch only the entities that are relevant for my use case from the store, but I can't seem to find anything which lets me apply formatting to all of the entities of a certain kind.我最近发现了filterFn ,它可以让我只从商店中获取与我的用例相关的实体,但我似乎找不到任何东西可以让我将格式应用于某种类型的所有实体。

Here is an example where I have to format and parse my data in my component before subscribing to it.这是一个示例,我必须在订阅它之前在我的组件中格式化和解析我的数据。 Ideally this should not be done here, but in a more central place...any ideas of how to deal with this issue in ngrx?理想情况下,这不应该在这里完成,而是在更中心的地方......关于如何在 ngrx 中处理这个问题的任何想法?

entity.data.config.ts实体.data.config.ts

// I would like to parse and format data here. Is that a good idea?
const entityMetadata: EntityMetadataMap = {
    letter: {
        // https://ngrx.io/guide/data/entity-metadata#filterfn
        filterFn: (entities, clientId) => {
            return entities.filter(entity => entity.clientId === Number(clientId));
        },
    },
};

my.component.ts我的.component.ts

@Component({
    selector: 'my-component',
    templateUrl: './my.component.html',
})
export class MyComponent implements OnInit {
    public letters$: Observable<LetterParsed[]>;
    public clientId: string;

    public constructor(public letterDataService: LetterDataService) {}

    public ngOnInit(): void {
        this.clientId = '1';

        // call API, GET letter voor current clientId and add to store
        this.letterDataService.getWithQuery({
            clientId: this.clientId,
        });

        // set filter and fetch only filtered letter entities from store
        this.letterDataService.setFilter(this.clientId);
        this.letters$ = this.letterDataService.filteredEntities$.pipe(
            // this is where I do the parsing, which ideally I want to avoid...
            map((letters: Letter[]) => letters.map(letter => this.parseLetter(letter))),
        );
    }

    private parseLetter(letter: Letter): LetterParsed {
        return {
            ...letter,
            status: this.formatStatus(letter.status),
            date: new Date(letter.date),
        };
    }

    /**
     * @param status e.g 'I_LOVE_ANGULAR'
     * @returns 'I love angular'
     */
    private formatStatus(status: string): string {
        const splitLowercase = status.split('_').join(' ').toLowerCase();
        return splitLowercase[0].toUpperCase() + splitLowercase.slice(1);
    }
}

You can extend the default DataService to write a custom data service and format your entities there.您可以扩展默认的 DataService 以编写自定义数据服务并在那里格式化您的实体。 That way, you'll only need to format them once per entity type.这样,您只需为每个实体类型格式化一次。

Refer to the documentation here: https://ngrx.io/guide/data/entity-dataservice#custom-entitydataservice请参阅此处的文档: https://ngrx.io/guide/data/entity-dataservice#custom-entitydataservice

Here's how you might do this for your use case:以下是您可以如何针对您的用例执行此操作:

@Injectable()
export class LetterDataService extends DefaultDataService<Letter> {
  constructor(
    http: HttpClient,
    httpUrlGenerator: HttpUrlGenerator,
    logger: Logger
  ) {
    super("Letter", http, httpUrlGenerator);
  }

  getWithQuery(params: string | QueryParams): Observable<Letter[]> {
    return super
      .getWithQuery(params)
      .pipe(
        map((entities) => entities.map((entity) => this.mapEntity(entity)))
      );
  }

  private mapEntity(entity: Letter): Letter {
    return {
      ...entity,
      status: this.formatStatus(letter.status),
      date: new Date(letter.date),
    };
  }

  /**
   * @param status e.g 'I_LOVE_ANGULAR'
   * @returns 'I love angular'
   */
  private formatStatus(status: string): string {
    const splitLowercase = status.split("_").join(" ").toLowerCase();
    return splitLowercase[0].toUpperCase() + splitLowercase.slice(1);
  }
}

You'll also need to register this custom data service, like so:您还需要注册此自定义数据服务,如下所示:

import { EntityDataService } from '@ngrx/data'; // <-- import the NgRx Data data service registry
import { LetterDataService } from './letter-data-service';

@NgModule({
  imports: [ ... ],
  providers: [ LetterDataService ] // <-- provide the data service
})
export class EntityStoreModule {
  constructor(
    entityDataService: EntityDataService,
    letterDataService: LetterDataService,
  ) {
    entityDataService.registerService('Letter', letterDataService); // <-- register it
  }
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM