如何在AngularJS中重复使用模板?

3
你如何重复使用模板?考虑以下JavaScript对象:
{
    MyName: '',
    Address: {
        Street: ''
    },
    MyEmployer: {
        CompanyName: '',
        Address: {
            Street: ''
        }
    }
}

还有一个位于 /templates/myTemplate.html 的模板文件:

<div ng-app="someapp" ng-controller="somecontroller">
    MyName: <input type="text" ng-model="MyName" />

    <div ng-include="'/templates/address.html'"></div>

    My Company: <input type="text" ng-model="MyEmployer.CompanyName" />

    <div ng-include="'/templates/address.html'"></div>
</div>

下面是我想象中的地址模板文件,位于 /templates/address.html

<div>
    Street: <input type="text" ng-model="Street" />
</div>

正如您所看到的,我正在尝试在这里重复使用地址模板。那么,如何将适当的对象传递到此模板中?

3个回答

2

答案 我成功地解决了这个问题,并想在这里发布我的解决方案,以便下一个可能正在寻找相同待遇的人。

我的解决方案

在我的OP中,我有一个模型对象,其中包含两个地址,一个是人的家庭地址,另一个是他/她的雇主地址。因此,采用相同的对象模型和相同的地址模板仍位于/templates/address.html,我们可以添加两个附加控制器:

app.controller('personAddressController', ['$scope', function($scope) {
   $scope.Street = function(newValue) { return arguments.length ? model.Address.Street = newValue : model.Address.Street; }
}]);
app.controller('companyAddressController', ['$scope', function($scope) {
   $scope.Street = function(newValue) { return arguments.length ? model.MyEmployer.Address.Street = newValue : model.MyEmployer.Address.Street; }
}]);

下面是我们地址模板中 ng-include 的用法:

<div ng-include="'/templates/address.html'" ng-controller="personAddressController"></div>

<div ng-include="'/templates/address.html'" ng-controller="companyAddressController"></div>

此外,我们需要修改我们的地址模板:
<div>
    Street: <input type="text" ng-model="Street" ng-model-options="{ getterSetter: true }" />
</div>
<!--or add a form if you have more fields like i did-->
<form ng-model-options="{ getterSetter: true }">
    <div>
        Street: <input type="text" ng-model="Street" />
    </div>
</form>

更多关于 ng-model-options 和setter/getter的信息(页面底部): https://docs.angularjs.org/api/ng/directive/ngModel

请注意,在添加表单时,enter键默认会提交表单,但如果您想要控制它,可以轻松地进行设置。

最后,您可以使用指令来实现所有这些功能,正如有人已经建议的那样,但是按照 Angular 的说法,您将使用 Angular 指令作为控制器,而它们并不适用于此。更多信息请参见:AngularJS - Directives vs Controllers


1
在经历了数月的困扰后,我现在使用这种方法来避免模板重复:
在控制器中:
$scope.myelement = {...};
$scope.myelements = [{ ...}, { ... }]

在模板文件myelement.html中:
{{ myelement.name }} {{ myelement.anything }}

在一个模板中:

<div ng-include="'myelement.html'"></div>  <!-- $scope.myelement is used --> 
<div ng-repeat="myelement in myelements track by $index"></div> <!-- $scope.myelements[$index] used myelements.length times --> 

如果您想指定另一个变量,可以这样做:

<div ng-include="'myelement.html'" ng-init="myelement = SomeScopeVariable;"></div>

但在这种情况下,ng-init只有在编译ng-include时才会被调用。你将无法在其中更改“myelement”,只能修改其属性。我不建议使用ng-init,除非你只想在控制器中修改/可视化特定元素。如果你想删除它或创建另一个,请不要使用ng-init。

有几件事情。首先,我不想为任何类型的数组重复使用模板。其次,使用 ng-init 将需要在模板内硬编码变量名,这违背了重用的目的。本质上,我希望像 KnockoutJS 一样提供模板选项! - user3794166
@Hani:你的代码有一个错误:你总是写ng-model="MyName"等等... 但它应该是ng-model="myelement.MyName"。 - Pierre Emmanuel Lallemant
MyName 是 $scope 对象的一个属性,但如果 myelement.MyName 是 $scope 对象的一部分,则可以按照您建议的方式操作。 - user3794166
@Hani:你不必直接将一个对象存储在 $scope 中,而是可以将其存储在 $scope 的属性中,例如 $scope.myelement。这样做可以轻松地在项目的不同部分重用模板。另一个提示:在 ng-model 中,如果没有点“.”,那么你就错了。 - Pierre Emmanuel Lallemant

1

ng-include共享相同的控制器和数据。

因此,解决方案可能是考虑其他事情。也许是一个模板指令。您可以传递一个模板以及不同的值。

// Directive
app.directive('addressTemplate', function() {
    return {
        templateUrl: '/templates/address.html',
        scope: {
            street: '='
        }
    };
});

// My template
<address-template street="MyEmployer.Address.Street"></address-template>

// Template
<div>
    Street: <input type="text" ng-model="street" />
</div>

如果是这样的话,我就不会使用Angular了。任何UI框架都应该促进代码重用,这松散地意味着模板重用。在这里http://knockoutjs.com/documentation/template-binding.html - user3794166
我刚刚创建了一个自定义指令,可以随意修改并重复使用我的代码。 - Hristo Enev
@Hani:每次您需要为可重用项包装异步调用时,都必须将其包装在指令中。像ionic这样的框架定义了许多通用指令。 - Pierre Emmanuel Lallemant
1
如果你不知道如何组织和使用指令,你最终会得到一百个指令。指令非常灵活,是任何目的的好工具。没必要侮辱我的例子,我只是想帮助你并提供更多选项 :) - Hristo Enev
@Histro 此外,我的 OP 只是一个虚拟示例。为了重用各种模板,我最终会编写几百个指令,因为我有数千个具有各种属性名称的域对象。我怀疑这是否应该是这种情况? - user3794166

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接