【问题标题】:How to conditionally remove the wrapping div and keep its children?如何有条件地删除包装 div 并保留其子项?
【发布时间】:2020-01-28 15:14:21
【问题描述】:

我想创建一个名为 showWrapperIf 的结构指令,它要么保留整个元素及其所在的子元素,要么当条件为 true 时,删除它所在的元素(包装器),并获取所有子节点并将其保存在 DOM 中。

所以,这个结果

<div *showWrapperIf="true">
    <h2></h2>
    <p></p>
    <any-component></any-component>
</div>

<div>
    <h2></h2>
    <p></p>
    <any-component></any-component>
</div>

但是,如果conditionfalse,则只需要显示孩子。例如:

<h2></h2>
<p></p>
<any-component></any-component>

StackBlitz demo

我知道我可以使用 &lt;ng-template&gt;*ngIf 来做到这一点,但是包装器有很多子级,它会使文件的大小加倍并降低可读性。

【问题讨论】:

标签: angular


【解决方案1】:

这种方法似乎过于复杂,因为您的内容还包含您自己的组件。相反,您可以将此逻辑移动到一个单独的组件中,这将使您的代码简洁明了。创建一个组件,例如conditional-wrapper,并将其添加到您的模块中。在组件中只需放置一个基本的Input 以接受来自父级的wrapperElement

@Input() wrapperElement: boolean;

在模板中,只需添加代码以使用ngSwitch 有条件地将任何element 显示为包装器或没有包装器作为默认值。

<ng-container [ngSwitch]="wrapperElement">
    <div *ngSwitchCase="'div'">
        <ng-container *ngTemplateOutlet="noWrapper"></ng-container>
    </div>
    <h2 *ngSwitchCase="'h2'">
        <ng-container *ngTemplateOutlet="noWrapper"></ng-container>
    </h2>
    <ng-container *ngSwitchDefault>
        <ng-container *ngTemplateOutlet="noWrapper"></ng-container>
    </ng-container>
</ng-container>

<ng-template #noWrapper>
    <ng-content></ng-content>
</ng-template>

现在您只需从父组件递归显示conditional-wrapperng-content 会将您的父组件的数据投影到子组件。

<conditional-wrapper [wrapperElement]="condition ? 'div': ''">
    <h2>Child 1</h2>
    <p>Child 2</p>
    <footer>Child 3</footer>
    <conditional-wrapper [wrapperElement]="condition ? 'div': ''">
        <p>Nested Child 4</p>
    </conditional-wrapper>
</conditional-wrapper>

这是StackBlitz 上的一个工作示例。

【讨论】:

  • 这看起来是最接近的解决方案。问题是 - 在实际项目中(不能分享公司的东西),它“有点”更复杂=D。使用ng-template 也会更改上下文,因此我们需要传递该模板中使用的所有变量,而使用该指令只会删除父级并在该位置渲染其子级。 AngularJS 中有一个replace 选项,但它曾经并且已被弃用,因此它没有进入 Angular2+。此外,为模板命名并不有趣,并且在多次嵌套时使用多个模板 - 这一点都不好玩:D
  • 如何将上下文传递给else 分支?
  • @MCFreddie777 - 我已将答案更新为更简洁的解决方案。
  • 使用额外的组件是我们想要避免的方法,因为函数和整个上下文需要传递给conditional-wrapper。此外,div 是硬编码的,因此不可重复使用。
  • 该上下文问题不应该再存在了,因为每个conditional-wrapper 都会创建自己的实例并仅投影内容,因此数据将真正由父组件本身控制。可以使用ngSwitch 解决div 问题。我已经更新了我的答案和 StackBlitz 以显示相同。
【解决方案2】:

我认为你做不到。请注意,当有据可查的角度方式不够用时,您可能会走错方向!

无论如何,可能接近您需要的东西(我认为)是在宿主元素上添加一个类!

你可以这样做

this.viewContainer.clear();
this.viewContainer.createEmbeddedView(this.templateRef);

if (this.condition) {
  const elementRef = (this.viewContainer.get(0) as any)
     .rootNodes[0] as ElementRef;
  this.renderer.addClass(elementRef, "myclass");
}

stackblitz

你可以用 css 做剩下的事情

【讨论】:

  • 我需要去掉包裹它的元素。
  • 为什么不简单地将ngTemplate*ngIf 一起使用:stackblitz.com/edit/angular-a6rbwr 可能比我的答案中的解决方案更好:)
  • 因为不是所有的项目都那么简单,而且 ngTemplates - 无论是使用 ngIf 还是 ngSwitch 都会使 HTML 的数量增加一倍/三倍,我们希望保持我们的代码库清晰。 (看html:stackblitz.com/edit/…
  • 这会让你的代码变得复杂,我会为了可读性而不是更少的 html/复杂性,而 componentFactory 并没有解决你的问题(我认为)。无论如何,我有最后一个简单的解决方案,使用一个组件:stackblitz.com/edit/… 你的主要组件仍然有更少的 html 并且是超级可读的,我认为 :)
  • 抱歉,stackblitz 不正确,component stackblitz
猜你喜欢
  • 1970-01-01
  • 2023-01-02
  • 1970-01-01
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 2015-11-22
相关资源
最近更新 更多