Angular - 等到我收到数据后再加载模板

新手上路,请多包涵

我有一个使用此模板动态呈现多个组件的组件:

 <div [saJquiAccordion]="{active: group.value['collapsed']}" *ngFor="let group of filterGroupsTemplate | keysCheckDisplay;">
    <div>
        <h4>{{group.key | i18n}}</h4>
        <form id="ibo-{{group.key}}" class="form-horizontal" autocomplete="off" style="overflow: initial">
            <fieldset *ngFor="let field of group.value | keys">
                <ng-container *ngComponentOutlet="fieldSets[field.value.template];
                                    ngModuleFactory: smartadminFormsModule;"></ng-container>
            </fieldset>
        </form>
    </div>
</div>

问题是填充这些组件所需的数据是我从 API 调用中获取的:

       this.getFiltersSubscription = this.getFilters().subscribe(
            (filters) => {
                this.filters = filters;
                log.info('API CALL. getting filters');

                // Sending data to fieldform components
                this.iboService.updateIBOsRankList(filters['iboRank'].data);
                this.iboService.updateIBOsNewsletterOptions(filters['iboNewsletter'].data);
                this.iboService.updateIBOsTotalOrders(filters['iboTotalOrders'].data);
            }
        );

所以,一旦我有了我的数据,我就会触发我的组件订阅的服务 Observable,然后他们将处理收集到的数据。

问题

如果在所有组件加载之前进行 API 调用,我将触发这些传递数据的服务方法,但没有人会订阅这些 Observable。

一种方法是:

首先加载数据,并且只有当我加载数据时,我才会渲染模板,因此,动态渲染所有这些组件,然后我才会触发这些服务方法(Observables)。

我不想为每个组件进行 API 调用,因为它可以像 60 个组件一样,我宁愿放松对代码的抽象,但我更喜欢这样做:

 // Listens to field's init and creates the fieldset triggering a service call that will be listened by the field component
        this.iboService.initIBOsFilters$.subscribe(
            (fieldName) => {
                if (fieldName === 'IBOsRankSelectorFieldComponent') {
                    log.data('inside initIBOsFilters$ subscription, calling updateIBOsFilters()', fieldName);
                    this.iboService.updateIBOsRankList(this.filters['iboRank'].data); // HERE I'M PASSING DATA TO THE COMPONENT RENDERED DYNAMICALY. BUT IF this.filters IS UNDEFINED, IT BREAKS
                }
            }
        );

为了做到这一点,我需要确保 this.filters 被定义,因此,我得出结论:

我如何才能等到 API 调用结束并在呈现我的模板 html 之前定义 this.filters

抱歉,如果我的问题有点长,如果您需要更多详细信息,请告诉我。

谢谢!

原文由 SrAxi 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 454
2 个回答

在研究了人们给我的不同方法后,我在 async 管道上找到了解决方案。但是,我花了一段时间才明白如何实现它。

解决方案:

 // Declaring the Promise, yes! Promise!
filtersLoaded: Promise<boolean>;

// Later in the Component, where I gather the data, I set the resolve() of the Promise
this.getFiltersSubscription = this.getFilters().subscribe(
    (filters) => {
        this.filters = filters;
        log.info('API CALL. getting filters');

        this.filtersLoaded = Promise.resolve(true); // Setting the Promise as resolved after I have the needed data
    }
);

// In this listener triggered by the dynamic components when instanced,
// I pass the data, knowing that is defined because of the template change

// Listens to field's init and creates the fieldset triggering a service call
// that will be listened by the field component
this.iboService.initIBOsFilters$.subscribe(
    (fieldName) => {
        if (fieldName === 'IBOsRankSelectorFieldComponent') {
            log.data('inside initIBOsFilters$ subscription, calling updateIBOsFilters()', fieldName);
            this.iboService.updateIBOsRankList(this.filters['iboRank'].data);
        }
    }
);

在模板中,我使用需要 ObservablePromiseasync 管道

<div *ngIf="filtersLoaded | async">
    <div [saJquiAccordion]="{active: group.value['collapsed']}" *ngFor="let group of filterGroupsTemplate | keysCheckDisplay;">
        <div>
            <h4>{{group.key | i18n}}</h4>
            <form id="ibo-{{group.key}}" class="form-horizontal" autocomplete="off" style="overflow: initial">
                <fieldset *ngFor="let field of group.value | keys">
                    <ng-container *ngComponentOutlet="fieldSets[field.value.template];
                                    ngModuleFactory: smartadminFormsModule;"></ng-container>
                </fieldset>
            </form>
        </div>
    </div>
</div>

笔记:

  • async pipe need an Observable or a Promise from what I understood, that’s why the only way to make it work was by creating a Promise
  • 我没有使用 resolver 方法,因为当您通过 Angular 的路由到达组件时使用它。该组件是较大组件的一部分,它不像任何其他普通组件那样通过路由实例化。 (虽然尝试了这种方法,用它做了一点工作,但没有完成这项工作)

原文由 SrAxi 发布,翻译遵循 CC BY-SA 4.0 许可协议

替代 async 将创建变量 isLoading = true 。虽然它是由 angular 而不是使用 * ngIf 的内容提供的真正的显示微调器。当您的订阅触发时,分配 isLoading = false 。这样,您将不会收到有关丢失数据的任何错误,因为在技术上使用它的内容尚不存在。

原文由 Max Tuzenko 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进