【问题标题】:Curious case of "Unexpected closing tag" in modern Angular [closed]现代Angular中“意外的结束标签”的好奇案例[关闭]
【发布时间】:2020-09-10 19:41:02
【问题描述】:

假设我们有一个数据模型,一个代表要在模板中呈现的文本项的对象列表。每个都带有一个文本和一个类型。类型可以是HEADERPARAGRAPHLIST。每个都对应一个相似的 HTML 标签,所以HEADER 将由<h1> 呈现,PARAGRAPH 将是<p>LIST 将是一个<li>,最终包装在一个<ul></ul> 中。我们有一组给定的这些对象。例如:

[
 { textType: 'HEADER', text: 'Welcome!' },
 { textType: 'PARAGRAPH', text: 'Lorem ipsum is a lie, here are the facts:' },
 { textType: 'LIST', text: 'List item #1' },
 { textType: 'LIST', text: 'List item #2' },
 { textType: 'LIST', text: 'List item #3' },
 { textType: 'HEADER', text: 'Welcome again!' },
 { textType: 'PARAGRAPH', text: 'Lorem ipsum is not a lie after all, counterpoints:' },
 { textType: 'LIST', text: 'Another List item #1' },
 { textType: 'LIST', text: 'Another List item #2' },
 { textType: 'LIST', text: 'Another List item #3' },
 { textType: 'PARAGRAPH', text: 'That\'s all, folks!' }
]

问题很明显——HEADERPARAGRAPH 都可以用带有 HTML 内容的单闭标签来表示。但是LIST 不仅需要一个标准的<li> 元素,还需要一个<ul>(如果我们假设需要严格的HTML)。如何在 Angular 模板中渲染它?我采用了一种我能想到的最自然的方法——*ngFor,并添加了一些额外的、不寻常的但合理的逻辑。在某种程度上,它看起来像是老式 PHP 风格的渲染。

<ng-container *ngFor="let textItem of summaryText; let index = index">
    <h1 *ngIf="textItem.textType === 'HEADER'">{{ textItem.text }}</h1>
    <p *ngIf="textItem.textType === 'PARAGRAPH'">{{ textItem.text }}</p>
    <ng-container *ngIf="textItem.textType ==='LIST'">
        <ng-container *ngIf="(index === 0) || (summaryText[index-1] && (summaryText[index-1].textType !== 'LIST'))">
        <ul>
        </ng-container>
        <li>{{ textItem.text }}</li>
        <ng-container *ngIf="(index === (summaryText.length - 1)) || (summaryText[index+1] && (summaryText[index+1].textType !== 'LIST'))">
        </ul>
        </ng-container>
    </ng-container>
</ng-container> 

得知这无法编译时,我感到有些惊讶。结果为Unexpected closing tag "ng-container"。而且,果然,当你想到它时,这是有道理的。 Angular 强制执行正确的 HTML,因此它期望指令中的 &lt;ul&gt; 闭包在没有时。这点我很理解。

但这仍然给我留下了一个未解决的问题 - 当我不知道它何时会在初始模型中发生时,如何呈现包含在 &lt;ul&gt; 中的列表?我不能在任何地方假设&lt;ul&gt;。我什至无法假设该模型中项目的顺序 - 它可能只是一个 PARAGRAPH、LIST、PARAGRAPH、LIST 等等(这将导致两个列表,每个列表都有一个项目)。

有没有办法在不影响数据模型的情况下实现?我知道我理论上可以更改模型,在里面制作一个单独的列表,检测到它,启动ul 等等。但在这种情况下,出于某种原因(请假设这是合理的并且我知道我在说什么)我无法更改模型。

我想知道是否有任何方法可以使 Angular 正确渲染。或者,如果这可能是一种错误的方法,是否有另一种方法可以直接在模板中解决这个问题?

【问题讨论】:

  • 这不是真正的 Angular 问题;在到达模板之前,您需要对数组中的项目进行分组,以便将所有列表项放在一起,这样您就有了一个数组,其中应该以 lis 结尾进行迭代。这似乎也更适合ngSwitch
  • 我假设您的意思是“请假设合理并且我知道我在说什么”?当很明显,一个小的改变会让这变得如此容易时,这样做是相当困难的(如果你的情况是那个特殊的,这不太可能对其他人有用,因此不是一个好适合SO)。 提供上下文而不是断言。
  • 我已经提供了所有需要的上下文。其他什么都不需要。我的问题不是以另一种方式解决问题——我知道如何做到这一点。提出我的问题是为了了解是否有一些我仍然不熟悉的 Angular 内部/技巧,并且可能(即使有点牵强)应用于这种或类似情况。如果您在这里没有其他要补充的,我很高兴您只说“没有,对不起”或“我不知道”——然后去做你的事情,而不是在互联网上使用最古老的东西但是你为什么要这样做……”。
  • 你回答了你自己的问题:“Angular 强制执行正确的 HTML,因此它期望指令中的
      闭包,但实际上没有。”我想 Angular 团队认为强制关闭标签是一个好主意 - 这个想法是创建一个 DOM 并创建一个您需要搜索到一个指令(带有打开和关闭标签)的 DOM,在您寻找另一个指令的指令内(总是带有打开和关闭标签)等。对我来说是正常的,例如Blazor 中也反映了同样的想法。
  • 想象一下,您想要从“特殊 XML”解析到 Json。但是您的 XML 是“一些特殊的”,因为可以有“if”和“for”。当然,我无法想象如果不强制标签成对消失怎么办。好吧,我不是“所有人”,但是,我个人认为这是确定的

标签: javascript html angular


【解决方案1】:

我在 Stackblitz 上为您创建了一个已修复错误的版本。

错误是因为您的模板中违反了HTML 嵌套标记规则:

<ng-container *ngIf="(index === 0) || (summaryText[index-1] && (summaryText[index-1].textType !== 'LIST'))">
  <ul>
</ng-container>

在关闭内部标签&lt;ul&gt;之前有一个结束标签&lt;/ng-container&gt;

此外,您必须更改 JSON 对象数据以获得更好的 &lt;li&gt; 项目结构,如下所示:

  this.summaryText = [
      { textType: 'HEADER', text: 'Welcome!' },
      { textType: 'PARAGRAPH', text: 'Lorem ipsum is a lie, here are the facts:' },
      { textType: 'LIST', text: ['List item #1', 'List item #2', 'List item #3'] },
      { textType: 'HEADER', text: 'Welcome again!' },
      { textType: 'PARAGRAPH', text: 'Lorem ipsum is not a lie after all, counterpoints:' },
      { textType: 'LIST', text: ['Another List item #1', 'Another List item #2', 'Another List item #3'] },
      { textType: 'PARAGRAPH', text: 'That\'s all, folks!' }
    ]

【讨论】:

  • 是的,这些我都知道。好吧,无论如何,谢谢你的时间,我猜?我想 SO 毕竟不是提出高级开放性问题的好平台。但话说回来,Angular 的 Github 也不是,所以我在这方面没有太多选择。
  • “SO 不是提出高级开放式问题的好平台”。真的。根据定义。请参阅有关主题问题定义的帮助中心。如果不够专注,那就跑题了。
猜你喜欢
  • 2018-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多