我正在使用预先存在的模板尝试对其进行Angularize。
我有3个指令,基本上是卡片,卡片头和卡片体:
<card>
<card-header title="My Card">
<input type="text" ng-model="userSearch" />
</card-header>
<card-body>
<card ng-repeat="item in object | filter:userSearch">
<card-body>{{ item.name }}</card-body>
</card>
</card-body>
</card>
我确信你可以看到这个问题......由于范围问题我无法让过滤器拿起模型。因为我在指令中有自己的html,所以我需要使用transclude: true
,并根据我的理解创建自己的范围。
卡:
return {
restrict: 'AE',
transclude: true,
replace: true,
scope: false,
template: '<div class="card" ng-transclude></div>',
}
卡片标题:
return {
restrict: 'AE',
requires: 'card',
transclude: true,
replace: true,
scope: false,
scope: {
title: '@',
secondary: '@',
theme: '@'
},
template: '<div class="card-header" ng-class="theme"><h2 ng-if="title">{{ title }}<small>{{ secondary }}</small></h2><div ng-transclude></div></div>',
}
卡身:
return {
restrict: 'AE',
requires: '^card',
transclude: true,
replace: true,
scope: false,
scope: {
padding: '@',
theme: '@'
},
template: '<div class="card-body" ng-class="theme" ng-transclude></div>',
link: function($scope, $element, $attributes) {
if($scope.padding)
angular.element($element[0]).addClass('card-padding');
}
}
似乎它应该是一个简单的概念,但是当我拥有自己的范围项目时,我不知道如何解决这个问题,但需要转换并拥有自己的范围项目。
答案 0 :(得分:1)
首先,我想也许你有一个标记问题。这就是我认为你的意思:
<card>
<card-header title="My Card">
<input type="text" ng-model="userSearch" />
</card-header>
<card-body>
<card ng-repeat="item in object | filter:userSearch">
<card-body>{{ item.name }}</card-body>
</card>
</card-body> <!--this was card-header, which doesn't make sense -->
</card>
当您在指令中使用ng-transclude时,被转换的内容使用 新范围 ,这是指令的 兄弟范围 即可。因此,如果您要分析范围树,那么您将拥有(A是整个块的父范围,()表示隔离范围):
<card A>
<card-header A.B.(C)>
<input A.B.D ng-model="A.B.D.userSearch">
</card-header>
<card-body A.E.(F)>
<card A.E.G.H ng-repeat="A.E.G.H.item in A.E.G.object | filter: A.E.G.userSearch">
<card-body A.E.I.(J)>{{A.E.I.K.item.name}}
</card>
</card-body>
</card>
注意一些事情(除了明显的“这是很多范围!):
A.B.D.userSearch是一个与A.E.G.userSearch完全不同的属性。 A.E.G没有从A.B.D原型继承。这就是过滤器不起作用的原因。
另请注意,A.E.G.H.item也是A.E.I.K.item的另一个属性 - 这也不起作用。
如何解决:
最简单的修复方法是不使用ng-transclude,而是使用手动转换并控制已转换内容使用的范围。
例如,卡片转换将更改为:
template: '<div class="card" transclude-target></div>'
link: function(scope, element, attr, ctrl, transclude) {
transclude(scope, function(clone, scope){
element.find('[transclude-target]').append(clone);
}
}
除此之外:ng-transclude基本上可以:
link: function(scope, element, attr, ctrl, transclude) { transclude(scope.$parent.$new(), function(clone, scope){ element.find('[ng-transclude]').append(clone); } }
这样做是为了使转换使用指令范围而不是指令范围的兄弟(甚至是新范围)
范围树变为:
<card A>
<card-header A.(B)>
<input A.(B) ng-model="A.(B).userSearch">
</card-header>
<card-body A.(C)>
<card A.(C) ng-repeat="A.(C).D.item in A.(C).object | filter: A.(C).userSearch">
<card-body A.(C).D>{{A.(C).D.item.name}}</card-body>
</card>
</card-body>
</card>
仍然不太正确(孤立的指令打破了我们需要的继承链)。
更改其他两个指令(card-header和card-body)以使用范围。$ parent:
link: function(scope, element, attr, ctrl, transclude) {
transclude(scope.$parent, function(clone, scope){
element.find('[transclude-target]').append(clone);
}
}
Yield是以下范围树(现在您的过滤器将起作用{{item.name}}应该显示正确的版本)
<card A>
<card-header A.(B)>
<input A ng-model="A.userSearch">
</card-header>
<card-body A.(C)>
<card A.E ng-repeat="A.E.item in A.object | filter: A.userSearch">
<card-body A.E.(D)>{{A.E.item.name}}
</card>
</card-body>
</card>
我确定我在某个地方犯了一个错误,但我认为它应该解释发生了什么。我希望我的解释更简单,但这是我能做的最好的。
答案 1 :(得分:0)
这是我对你的问题的理解:
如果检查你的最后一个指令,我看到的是模板中没有定义模型。
现在,当您指定模板时,它会替换指令元素中的html,因此这是模型不显示的原因。
话虽如此,如果 item.name 位于 card-body 指令中,则必须在模板中包含模型。
现在当你使用ng-transclude时,它会把原来的html放回去,这就是你能够在某种程度上解决问题的原因(但是导致问题的范围)。
您必须按如下方式更改模板,并且还必须在隔离的范围定义中包含项目。
template: '<div class="card-body" ng-class="theme">{{item.name}}</div>'
如果您不想修改它并希望使用ng-transclude,有两种方法可以从子范围调用父范围变量,
所以没有
作为$ scope.items的itmes你可以改为使用一个对象并拥有项目
作为财产:$scope.itemModel.items
现在,如果你修改这些,他们 也将反映在父范围内。它的性质更快 的javascript。
检查这些是否适合您。