typescript 当 ngIf 为 false 时构建 Angular4 ng-content

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44929726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:41:15  来源:igfitidea点击:

Angular4 ng-content gets built when ngIf is false

htmlangulartypescriptangular2-template

提问by Cabadath

I have a problem with the new ng-contenttransclusion.

我对新的转置有问题ng-content

Let's say I have a component my-componentthat, in its ngOnInit()function does some heavy operation on load (for now, just a console.log()).

假设我有一个组件my-component,它的ngOnInit()功能在负载上执行一些繁重的操作(现在,只是一个console.log())。

I have a wrapper, that displays the content via transclusion (my-wrapper.component.html).

我有一个包装器,它通过嵌入 ( my-wrapper.component.html)显示内容。

<ng-content></ng-content>

If I set the surroundings up like this, the log statement doesn't show:

如果我这样设置环境,日志语句不会显示:

<my-wrapper *ngIf="false">
    <my-component></my-component>
</my-wrapper>

I assume, the my-wrappercomponent does not get built, so the content is ignored.

我假设my-wrapper组件没有被构建,所以内容被忽略。

But if I try to move the logic into the my-wrappercomponent like this (my-wrapper.component.html):

但是,如果我尝试将逻辑移动到my-wrapper像这样 ( my-wrapper.component.html)的组件中:

<ng-container *ngIf="false">
    <ng-content></ng-content>
</ng-container>

I always see the console.log()output. I guess, the my-componentgets built and then stored away until the *ngIfbecomes trueinside my-wrapper.

我总是看到console.log()输出。我想,这些my-component被构建然后存储起来,直到*ngIf变成trueinside my-wrapper

The intention was to build a generic "list-item + detail" component. Say I have a list of N overview-elements (my-wrapper), that get rendered in a *ngForloop. Every of those elements has its own detail component (my-component) that is supposed to load its own data, once I decide to show more infos to a specific item.

目的是构建一个通用的“列表项+详细信息”组件。假设我有一个包含 N 个概览元素 ( my-wrapper)的列表,它们在*ngFor循环中呈现。这些元素中的每一个都有自己的细节组件 ( my-component),一旦我决定向特定项目显示更多信息,它就会加载自己的数据。

overview.html:

概览.html:

<ng-container *ngFor="let item of items">
    <my-wrapper>
        <my-component id="item.id"></my-component>
    </my-wrapper>
</ng-container>

my-wrapper.component.html:

我的包装器.component.html:

<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail">
    <ng-content></ng-content>
</div>

Is there a way to tell Angular, to ignore the transcluded content until it is necessary to be added to the page? Analogously to how it was in AngularJS.

有没有办法告诉 Angular,忽略嵌入的内容,直到有必要将其添加到页面中?类似于它在 AngularJS 中的情况。

采纳答案by Cabadath

Based on the comment of @nsinreal I found an answer. I find it to be a bit abstruse, so I'm trying to post it here:

根据@nsinreal 的评论,我找到了答案。我觉得它有点深奥,所以我想把它贴在这里:

The answer is to work with ng-templateand *ngTemplateOutlet.

答案是使用ng-template*ngTemplateOutlet

In the my-wrappercomponent, set up the template like this (my-wrapper.component.html):

my-wrapper组件中,像这样设置模板 ( my-wrapper.component.html):

<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail" [hidden]="!isInitialized">
    <ng-container *ngTemplateOutlet="detailRef"></ng-container>
</div>

Note, that the [hidden]there is not really necessary, it hides the "raw" template of the child until it decides it is done loading. Just make sure, not to put it in a *ngIf, otherwise the *ngTemplateOutletwill never get triggered, leading to nothing happening at all.

请注意,这[hidden]并不是真正必要的,它会隐藏子项的“原始”模板,直到它决定完成加载。只要确保不要把它放在 a 中*ngIf,否则*ngTemplateOutlet将永远不会被触发,导致什么也不会发生。

To set the detailRef, put this in the component code (my-wrapper.component.ts):

要设置detailRef,请将其放入组件代码 ( my-wrapper.component.ts) 中:

import {?ContentChild, TemplateRef } from '@angular/core';

@Component({ ... })
export class MyWrapperComponent {
    @ContentChild(TemplateRef) detailRef;

    ...
}

Now, you can use the wrapper like this:

现在,您可以像这样使用包装器:

<my-wrapper>
    <ng-template>
        <my-component></my-component>
    </ng-template>
</my-wrapper>

I am not sure, why it needs such complicated "workarounds", when it used to be so easy to do this in AngularJS.

我不确定为什么它需要如此复杂的“解决方法”,而过去在 AngularJS 中这样做很容易。

回答by SrAxi

By doing this:

通过做这个:

<my-wrapper *ngIf="false">
    <my-component></my-component>
</my-wrapper>

You are not calling MyComponentcomponent, because the *ngIfis false. that means, that not calling it you are not instancing it and, therefore, not passing through its ngOnInit. And that's why you are not getting the console log.

您不是在调用MyComponent组件,因为它*ngIffalse. 这意味着,不调用它就不会实例化它,因此不会通过它的ngOnInit. 这就是为什么您没有获得控制台日志的原因。

By doing this:

通过做这个:

<ng-container *ngIf="false">
    <ng-content></ng-content>
</ng-container>

You are inside the component, you are just limiting what to render in your template, but you already instanced your component and, therefore, you passed through your ngOnInitand you get your console log done.

您在组件内部,您只是限制在模板中呈现的内容,但是您已经实例化了您的组件,因此,您通过了您的ngOnInit并完成了控制台日志。

If, you want to limit something (component call with selector or a ng-contentor even a div) until you have some data available, you can do the following:

如果您想限制某些内容(使用选择器或 ang-content甚至 a 的组件调用div),直到您有一些可用数据,您可以执行以下操作:

datasLoaded: Promise<boolean>;

this.getData().subscribe(
       (data) => {
            this.datasLoaded = Promise.resolve(true); // Setting the Promise as resolved after I have the needed data
       }
);

And in your template:

在你的模板中:

<ng-container *ngIf="datasLoaded | async">
   // stuff here
</ng-container>

Or:

或者:

<my-component *ngIf="datasLoaded | async">
   // Didn't test this one, but should follow the same logic. If it doesn't, wrap it and add the ngIf to the wrapper
</my-component>