AngularJS中的重复内容(子模板)

时间:2014-10-15 02:07:06

标签: html angularjs

我有一个模板,其中包含(部分)完全相同的内容重复两次或三次,并对绑定进行微小更改,例如:

<div class="xyz-state0" data-ng-hide="data.error || !data.states[0].name">
    <div class="xyz-content">
        <img data-ng-src="{{data.states[0].image}}" width="48" height="48">
        <span>{{data.states[0].name}}</span>
    </div>
</div>
<div class="xyz-state1" data-ng-hide="data.error || !data.states[1].name">
    <div class="xyz-content">
        <img data-ng-src="{{data.states[1].image}}" width="48" height="48">
        <span>{{data.states[1].name}}</span>
    </div>
</div>

如何编写此代码以避免重复此HTML?这是特定于其父视图(它不会在其他任何地方使用),因此创建一个完整的小部件似乎是错误的。

基本上我想要类似于ngRepeat的东西,但由于以下原因我无法使用它:

  • 我需要在每个父div上使用特定(和不同)的样式。
  • 我需要呈现特定数量的div(在这种情况下为2,在另一个中为3),无论它们是否存在于范围内(即data.states中只能包含1个元素,但它仍然需要创建两个div。)。
  • 在另一种情况下,项目需要按顺序呈现(先是1,然后是0,然后是2)。

我设法在一个单独的HTML文件中获取模板片段,并将其包含在ngInclude中,但我不知道如何在其新范围内获取单个名称以引用一个特定的项目。我的第一次尝试就是这个,它不起作用:

<div class="xyz-state0" data-ng-include="'state.tpl.html'" data-ng-init="state=data.state[0]"></div>
<div class="xyz-state1" data-ng-include="'state.tpl.html'" data-ng-init="state=data.state[1]"></div>

我怀疑我可能会使用自定义控制器,但这似乎也是一个重要的解决方案。什么是正确的方式?

3 个答案:

答案 0 :(得分:2)

这几乎是自定义指令的教科书案例。定义一个指令,然后你可以做

<state ng-repeat="item in data.states" item="item">.

或者,如果自定义指令太过分(取决于您是否会在其他地方重复使用该视图组件),您可以在整个div上添加ng-repeat。唯一真正的问题是class =&#34; xyz-stateN&#34;东西,但我打赌你可以用ng级用法来解决这个问题。

编辑:

如果你进行ng-repeat,你可以只使用$ index键(只要你总是从零开始计数,并且状态类与索引相同)。像

这样的东西
<div ng-class="{{'xyz-state'+$index}}" ng-repeat="state in data.states" data-ng-hide="data.error || !state.name">
    <div class="xyz-content">
        <img data-ng-src="{{state.image}}" width="48" height="48">
        <span>{{state.name}}</span>
    </div>
</div>

可能会正常工作。总而言之,在我看来,几乎总是值得做出指示。代码一直在循环使用,另外,如果这让你感到紧张,你可以对命名空间和模块化保持谨慎。

答案 1 :(得分:0)

好吧,这似乎可以解决问题(感谢提示pfooti)。我仍然不满意它,因为该指令已在全球注册,而我真的只想在这一个地方。

<强> state.tpl.html:

<div class="xyz-content" data-ng-show="state.name">
    <img data-ng-src="{{state.image}}" width="48" height="48" />
    <span>{{state.name}}</span>
</div>

<强> view.tpl.html:

    <div data-xyz-state="data.states[0]" class="xyz-state0"
         data-ng-hide="data.error"></div>
    <div data-xyz-state="data.states[1]" class="xyz-state1"
         data-ng-hide="data.error"></div>

<强> app.js:

app.directive('xyzState', [function() {
    return {
        templateUrl: 'state.tpl.html',
        scope: {
            state: '=xyzState',
        },
    };
}]);

有趣的是,如果我尝试将引用元素声明为<xyz-state ...>而不是<div data-xyz-state="" ...>,那么不会工作,尽管文档说这应该也有效。我假设这里有某种验证的东西在干扰。

答案 2 :(得分:0)

就像一个FYI,我后来重新审视了这段代码,并决定这样做:(我让我的原始答案保持原样,因为这更像我原来的要求,而且它们看起来都很合理在不同的情况下。)

<强> view.tpl.html

    <div data-ng-repeat="state in data.states" data-ng-if="!data.error"
         data-ng-class="state.class">
        <div class="xyz-content" data-ng-show="state.name">
            <img data-ng-src="{{state.image}}" width="48" height="48" />
            <span>{{state.name}}</span>
        </div>
    </div>

<强> app.js

...
while ($scope.data.states.length < 2)
    $scope.data.states.push({});
$scope.data.states[0].class = 'xyz-state1';
$scope.data.states[1].class = 'xyz-state2';
...

我已为其他(3项)案例做了类似的事情,除非我想重新排列项目的顺序,我在控制器中为所需的订单添加了order属性然后在视图中使用data-ng-repeat="button in data.buttons|orderBy:'order'"

这确实意味着一些视图定义(显示顺序和CSS类)已泄漏到控制器中,但我认为代码清晰度的好处超过了这一点。