【问题标题】:AngularJS: Inheritance for HTML TemplatesAngularJS:HTML 模板的继承
【发布时间】:2016-11-29 13:44:23
【问题描述】:

问题:

如何防止类似 HTML 模板中的代码重复?

说明

对于同一个视图/指令,我有几个不同的模板,我想根据环境进行更改。模板大多相同,但包含一些需要根据环境进行更改的部分。

示例:

对于管理员来说,输入用户数据的视图可能如下所示:

<p> Username: </p>
<input ng-model="ctrl.username"></input>

<p> Firstname: </p>
<input ng-model="ctrl.firstname"></input>

<p> Lastname: </p>
<input ng-model="ctrl.lastname"></input>

<p> Authorization-level: </p>
<input ng-model="ctrl.authlevel"></input>

但是我需要向用户显示基本相同的视图,而不允许他更改其授权级别:

<p> Username: </p>
<input ng-model="ctrl.username"></input>

<p> Firstname: </p>
<input ng-model="ctrl.firstname"></input>

<p> Lastname: </p>
<input ng-model="ctrl.lastname"></input>

<p> Authorization-level: </p>
{{ctrl.authlevel}}

我想防止两个模板的代码重复。

可能的解决方案:

ng-if

显然,我可以根据条件使用ng-if 在模板中交换 html 块。但是,这不能很好地扩展。上面的例子很简单,但想象一下我有 5-10 个不同版本的模板。随着该模板的版本数量增加,代码变得越来越难以阅读。此外,理想情况下,我希望防止将管理视图的代码发送给用户,如果它包含在同一个 html 文件中,我不能这样做。

自定义指令

我可以将需要替换的每个 HTML 节点包装在它自己的指令中。这将保持主模板干净,我可以根据环境将 HTML 模板交换为指令。然而,所有这些额外的指令都会导致大量的样板代码。

(虽然这似乎最接近 Angular2 的组件)

第三方库角块

我发现angular-blocks 似乎很好地解决了我想要解决的问题。但是,它似乎不是很受欢迎,并且在查看实现时,我担心这可能会导致大型应用程序出现性能问题(由于多个嵌套的$compile-calls)。

有没有我遗漏的选项?你知道这方面的任何最佳实践或风格指南吗?

【问题讨论】:

  • 为什么不直接使用 ng-disabled??
  • 在 ng-formly 的模式上创建一个自定义指令,对你有很大帮助...

标签: javascript html angularjs templates


【解决方案1】:

制作模板并与ng-include一起使用

我的项目中有类似的情况,我使用ng-include 和几个三元组或ng-switches 来实现与您正在寻找的类似的东西。

将您的第一个代码块放在一个文件中,并将其命名为userTemplate.js。但是更改您的 authlevel 部分以考虑变化。在这种情况下,我会使用ng-switch(但有时您只需要一个三元组):

<p> Username: </p>
<input ng-model="ctrl.username"></input>

<p> Firstname: </p>
<input ng-model="ctrl.firstname"></input>

<p> Lastname: </p>
<input ng-model="ctrl.lastname"></input>

<p> Authorization-level: </p>
<div ng-switch="ctrl.authlevel">
  <p ng-switch-when="user">{{ ctrl.authlevel }}</p>
  <input ng-switch-when="admin" ng-model="ctrl.authlevel"></input>
</div>

然后每次你需要这段代码时,你可以在另一个视图中使用它ng-include。例如,在用户编辑表单中:

<form class="user-form" ...>
  <div class="basic-info" ng-include="/path/to/userTemplate.js"></div>
  <input type="submit" />
</form>

这种方法的好处在于,只要稍加考虑和精心设计,您就可以使这些模板用途广泛,以便用于创建新资源或查看或编辑现有资源。

【讨论】:

    【解决方案2】:

    一个选项是使用ng-switch,在新的 Angular 1.6 候选版本中有一个名为ng-switch-when-separator 的选项。 https://code.angularjs.org/1.6.0-rc.2/docs/api/ng/directive/ngSwitch。 有了它,您可以为一个ng-switch-when 提供多个选项:

    <div ng-switch="$ctrl.view">
      <p> Username: </p>
      <input ng-model="ctrl.username"></input>
    
      <p> Firstname: </p>
      <input ng-model="ctrl.firstname"></input>
    
      <p> Lastname: </p>
      <input ng-model="ctrl.lastname"></input>
    
      <p> Authorization-level: </p>
      <input ng-model="ctrl.authlevel" ng-switch-when="version1|version2|version3" ng-switch-when-separator="|"></input>
      <span ng-bind="ctrl.authlevel" ng-switch-when="version4|version5" ng-switch-when-separator="|"></span>
    </div>
    

    另一个很酷的选项可能是多槽嵌入(我从未使用过)https://docs.angularjs.org/api/ng/directive/ngTransclude

    【讨论】:

    • 我认为 ng-switch 与使用 ng-if 的问题大多相同,但更具可读性。我在这里看到的主要问题是我必须将所有版本发送给每个客户。多槽嵌入似乎是一个非常可行的选择。遗憾的是,我无法使用其中任何一个,因为 Angular 1.5 中引入了 Multi-Slot 嵌入,而我现在只能使用旧版本。 ://
    【解决方案3】:

    是什么阻止您将顶部部分包裹在它自己的模板中?这适用于动态内容高于或与静态内容并排的情况。

    用户信息模板.html

    <p> Username: </p>
    <input ng-model="ctrl.username"></input>
    
    <p> Firstname: </p>
    <input ng-model="ctrl.firstname"></input>
    
    <p> Lastname: </p>
    <input ng-model="ctrl.lastname"></input>
    

    用户视图.html

    <user-info></user-info>
    <p> Authorization-level: </p>
    {{ctrl.authlevel}}
    

    Admin-view.html

    <user-info></user-info>
    <p> Authorization-level: </p>
    <input ng-model="ctrl.authlevel"></input>
    

    当动态内容是静态内容的子内容时,此方法有效:

    用户信息模板.html

    <div>
        <p> Username: </p>
        <input ng-model="ctrl.username"></input>
    
        <p> Firstname: </p>
        <input ng-model="ctrl.firstname"></input>
    
        <p> Lastname: </p>
        <input ng-model="ctrl.lastname"></input>
    
        <!--Note that this dynamic piece is a child, so (as you noted)
        the above approach won't work-->
        <dynamic-piece></dynamic-piece>
    </div>
    

    Dynamic-piece-user.html

    <p> Authorization-level: </p>
    {{ctrl.authlevel}}
    

    Dynamic-piece-admin.html

    <p> Authorization-level: </p>
    <input ng-model="ctrl.authlevel"></input>
    

    我相信基于组件的方法足够灵活,可以适应大多数情况。但是,对于某些事情来说,这可能是矫枉过正。我(作为一个新手 Angular 开发人员)倾向于使用 ng-ifs 开始,当它们变得太复杂时,我会将它们分解为组件。我建议你这样做。一旦掌握了将组件重构为不同组件的窍门,这确实是一个流畅的工作流程。

    【讨论】:

    • 我的印象是为静态部分编写自定义指令会导致与为模板的动态部分编写自定义指令相同(或相似)的问题:只要我需要替换多个 HTML-节点和节点位于文件中间的某个位置,而不是在开头或结尾我需要管理多个指令,如果以后添加任何新更改,我需要进一步拆分。
    • 还可以想象自定义输入被添加为另一个 HTML 节点的内容。这意味着&lt;user-info&gt; 指令需要后跟另一个自定义指令才能生成正确的 HTML,因为它缺少关闭的 HTML-Tags 或需要包含相当复杂的结构以进行多重转入。
    • 等一下,我举个例子。最好的组件方法取决于父级在 DOM 中的位置
    • 这就是我在“自定义指令”解决方案中所描述的。我不太担心工作流程。尽管我需要为此编写数百个不可重用的指令,但我相当担心。由于样板代码和附加文件的数量,这对我来说似乎不是最佳选择。
    【解决方案4】:

    使用自定义指令并将数据类型(用户或管理员)作为单独的属性传递。这是一个使用自定义指令的示例,其中表单的 html 结构根据“数据类型”属性中传递的值而变化。因此输入字段将仅显示 data-type='user' 或者您也可以检查 authlevel 值是否可用并相应地显示输入字段。

    example: 
    

    https://plnkr.co/edit/YXkYgh73Kfn94O8wvA55?p=preview

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 2013-12-13
      • 2010-10-04
      • 2011-04-08
      • 2016-01-19
      • 2016-11-14
      相关资源
      最近更新 更多