在 Angular 中重复包含 - 访问当前项目的最佳实践?
Repeating over a transclusion in Angular - best practice to access current item?
我写了以下指令:
transclude: true,
scope: { items: '=' }
...
<div class="row" ng-repeat="item in items">
<div class="col-xs-9">
<ng-transclude></ng-transclude>
</div>
</div>
使用此指令时执行以下操作是否合法/良好做法?
cakes = [ { name: 'blueberry cheesecake', color: 'blue' }, { name: 'rocky road', color: 'mostly brown' } ]
...
<custom-list items="cakes">
<h5>{{$parent.item.name}}</h5>
</custom-list>
我具体说的是$parent.
方面。
Angular 已经认识到更灵活的 ng-transclude
将是有益的:
https://github.com/angular/angular.js/issues/5489
建议的解决方法之一是为 ng-transclude
定义您自己的覆盖,这样您就可以执行以下操作:
<div ng-transclude="sibling"></div> <!-- Original behaviour -->
<div ng-transclude="parent"></div> <!-- Takes from where transclusion happens -->
<div ng-transclude="child"></div> <!-- Takes from where transclusion happens, but creates a new child scope -->
自定义来源 ng-transclude
:
.config(function($provide){
$provide.decorator('ngTranscludeDirective', ['$delegate', function($delegate) {
// Remove the original directive
$delegate.shift();
return $delegate;
}]);
})
.directive( 'ngTransclude', function() {
return {
restrict: 'EAC',
link: function( $scope, $element, $attrs, controller, $transclude ) {
if (!$transclude) {
throw minErr('ngTransclude')('orphan',
'Illegal use of ngTransclude directive in the template! ' +
'No parent directive that requires a transclusion found. ' +
'Element: {0}',
startingTag($element));
}
var iScopeType = $attrs['ngTransclude'] || 'sibling';
switch ( iScopeType ) {
case 'sibling':
$transclude( function( clone ) {
$element.empty();
$element.append( clone );
});
break;
case 'parent':
$transclude( $scope, function( clone ) {
$element.empty();
$element.append( clone );
});
break;
case 'child':
var iChildScope = $scope.$new();
$transclude( iChildScope, function( clone ) {
$element.empty();
$element.append( clone );
$element.on( '$destroy', function() {
iChildScope.$destroy();
});
});
break;
}
}
}
})
如果要概括您要解决的问题,我会说您正在尝试创建一个 customList
指令,允许用户为每个项目指定模板。
transclude
似乎不是为此目的 - 它是为了从外部范围内嵌入内容 - 而不是向后访问指令的内部范围。
因此,从概念上讲,您可以执行以下操作:
.directive("customList", function() {
return {
scope: {
items: "="
},
templateUrl: function(element){
element.data("customListTemplate", element.find("item-template"));
return "customList.html";
},
compile: function(tElement, tAttrs) {
var template = element.data("customListTemplate");
tElement.find("item-placeholder").replaceWith(template.contents());
}
};
});
customList.html
是:
<div ng-repeat="item in items">
<item-placeholder></item-placeholder>
</div>
用法是:
<custom-list items="cakes">
<item-template>
{{$index}} | {{item.name}}
<hr>
</item-template>
</custom-list>
我写了以下指令:
transclude: true,
scope: { items: '=' }
...
<div class="row" ng-repeat="item in items">
<div class="col-xs-9">
<ng-transclude></ng-transclude>
</div>
</div>
使用此指令时执行以下操作是否合法/良好做法?
cakes = [ { name: 'blueberry cheesecake', color: 'blue' }, { name: 'rocky road', color: 'mostly brown' } ]
...
<custom-list items="cakes">
<h5>{{$parent.item.name}}</h5>
</custom-list>
我具体说的是$parent.
方面。
Angular 已经认识到更灵活的 ng-transclude
将是有益的:
https://github.com/angular/angular.js/issues/5489
建议的解决方法之一是为 ng-transclude
定义您自己的覆盖,这样您就可以执行以下操作:
<div ng-transclude="sibling"></div> <!-- Original behaviour -->
<div ng-transclude="parent"></div> <!-- Takes from where transclusion happens -->
<div ng-transclude="child"></div> <!-- Takes from where transclusion happens, but creates a new child scope -->
自定义来源 ng-transclude
:
.config(function($provide){
$provide.decorator('ngTranscludeDirective', ['$delegate', function($delegate) {
// Remove the original directive
$delegate.shift();
return $delegate;
}]);
})
.directive( 'ngTransclude', function() {
return {
restrict: 'EAC',
link: function( $scope, $element, $attrs, controller, $transclude ) {
if (!$transclude) {
throw minErr('ngTransclude')('orphan',
'Illegal use of ngTransclude directive in the template! ' +
'No parent directive that requires a transclusion found. ' +
'Element: {0}',
startingTag($element));
}
var iScopeType = $attrs['ngTransclude'] || 'sibling';
switch ( iScopeType ) {
case 'sibling':
$transclude( function( clone ) {
$element.empty();
$element.append( clone );
});
break;
case 'parent':
$transclude( $scope, function( clone ) {
$element.empty();
$element.append( clone );
});
break;
case 'child':
var iChildScope = $scope.$new();
$transclude( iChildScope, function( clone ) {
$element.empty();
$element.append( clone );
$element.on( '$destroy', function() {
iChildScope.$destroy();
});
});
break;
}
}
}
})
如果要概括您要解决的问题,我会说您正在尝试创建一个 customList
指令,允许用户为每个项目指定模板。
transclude
似乎不是为此目的 - 它是为了从外部范围内嵌入内容 - 而不是向后访问指令的内部范围。
因此,从概念上讲,您可以执行以下操作:
.directive("customList", function() {
return {
scope: {
items: "="
},
templateUrl: function(element){
element.data("customListTemplate", element.find("item-template"));
return "customList.html";
},
compile: function(tElement, tAttrs) {
var template = element.data("customListTemplate");
tElement.find("item-placeholder").replaceWith(template.contents());
}
};
});
customList.html
是:
<div ng-repeat="item in items">
<item-placeholder></item-placeholder>
</div>
用法是:
<custom-list items="cakes">
<item-template>
{{$index}} | {{item.name}}
<hr>
</item-template>
</custom-list>