[英]Angular 1.x Directive With A Template
I'm trying to create an angular directive for forming sentences. 我正在尝试创建一个用于形成句子的角度指令。 The goal is to take a list and iterate through them as necessary.
目标是获取一个列表并根据需要迭代它们。 The result of the directive would be something like:
该指令的结果如下:
shoes, pants and socks
鞋子,裤子和袜子
or 要么
shoes, pants and +5 more
鞋子,裤子和+5更多
I have the basic directive setup to work with a array of strings - but I'd like to customize it to allow custom templates for each sentence element (ie hyperlinks, styling, etc). 我有基本的指令设置来处理字符串数组 - 但我想自定义它以允许每个句子元素的自定义模板(即超链接,样式等)。 That is:
那是:
<sentence values="article in articles">
<strong>{{article.title}}</strong> by <span>{{article.author}}</span>
</sentence>
The HTML the user sees in the browser needs to be something like: 用户在浏览器中看到的HTML需要类似于:
$scope.articles = [
{ title: '...', author: '...'},
{ title: '...', author: '...'},
...
]
<span><strong>ABC</strong> by <span>123</span></span>
<span>, </span>
<span><strong>DEF</strong> by <span>456</span></span>
<span>and</span>
<span>+5 more</span>
I'm guessing it has something to do with transclude
but cannot figure out the API. 我猜它与
transclude
但无法弄清楚API。 I've also experimented with using ng-repeat
instead of the directive template but wasn't able to find a solution. 我也尝试过使用
ng-repeat
而不是指令模板但是无法找到解决方案。
Something like this should work where maxArticles
is a number defined on your scope 这样的东西应该适用于
maxArticles
是在你的范围上定义的数字
<sentence values="article in articles | limitTo: maxArticles">
<strong>{{article.title}}</strong> by <span>{{article.author}}</span>
<span ng-if="$index < maxArticles - 2">, </span>
<span ng-if="$index === articles.length - 1 && articles.length <= maxArticles">and</span>
</sentence>
<span ng-if="articles.length > maxArticles">
and +{{articles.length - maxArticles}} more.
</span>
Iterating AND providing dynamic content is a common use for a custom directive with the compile
function + the $compile
service. 迭代和提供动态内容是使用
compile
函数+ $compile
服务的自定义指令的常见用法。 Watch out: essentially you are repeating the functionality of ng-repeat
, you may want to consider alternatives. 注意:基本上你是在重复
ng-repeat
的功能,你可能想要考虑替代方案。
Eg instead of the articles
list, use another one (perhaps named articlesLimited
). 例如,而不是
articles
列表,使用另一个(可能名为articlesLimited
)。 The new list is constructed dynamically and contains the first elements from articles
. 新列表是动态构建的,包含
articles
中的第一个元素。 A flag (eg hasMore
) indicates whether the original articles
has more elements, simply as: $scope.hasMore = articles.length > 5
. 标志(例如
hasMore
)指示原始articles
是否具有更多元素,简单如下: $scope.hasMore = articles.length > 5
。 You use the hasMore
flag to show/hide the "+N more" message. 您使用
hasMore
标志来显示/隐藏“+ N more”消息。
For what it's worth however, below is an implementation of the sentence
directive. 然而,对于它的价值,下面是
sentence
指令的实现。 See the comment for weak points! 看弱点的评论!
app.directive('sentence', ['$compile', function($compile) {
var RE = /^([a-z_0-9\$]+)\s+in\s([a-z_0-9\$]+)$/i, ONLY_WHITESPACE = /^\s*$/;
function extractTrimmedContent(tElem) {
var result = tElem.contents();
while( result[0].nodeType === 3 && ONLY_WHITESPACE.test(result[0].textContent) ) {
result.splice(0, 1);
}
while( result[result.length-1].nodeType === 3 && ONLY_WHITESPACE.test(result[result.length-1].textContent) ) {
result.length = result.length - 1;
}
return result;
}
function extractIterationMeta(tAttrs) {
var result = RE.exec(tAttrs.values);
if( !result ) {
throw new Error('malformed values expression, use "itervar in list": ', tAttrs.values);
}
var cutoff = parseInt(tAttrs.cutoff || '5');
if( isNaN(cutoff) ) {
throw new Error('malformed cutoff: ' + tAttrs.cutoff);
}
return {
varName: result[1],
list: result[2],
cutoff: cutoff
};
}
return {
scope: true, // investigate isolated scope too...
compile: function(tElem, tAttrs) {
var iterationMeta = extractIterationMeta(tAttrs);
var content = $compile(extractTrimmedContent(tElem));
tElem.empty();
return function link(scope, elem, attrs) {
var scopes = [];
scope.$watchCollection(
function() {
// this is (IMO) the only legit usage of scope.$parent:
// evaluating an expression we know is meant to run in our parent
return scope.$parent.$eval(iterationMeta.list);
},
function(newval, oldval) {
var i, item, childScope;
// this needs OPTIMIZING, the way ng-repeat does it (identities, track by); omitting for brevity
// if however the lists are not going to change, it is OK as it is
scopes.forEach(function(s) {
s.$destroy();
});
scopes.length = 0;
elem.empty();
for( i=0; i < newval.length && i < iterationMeta.cutoff; i++ ) {
childScope = scope.$new(false, scope);
childScope[iterationMeta.varName] = newval[i];
scopes.push(childScope);
content(childScope, function(clonedElement) {
if( i > 0 ) {
elem.append('<span class="sentence-sep">, </span>');
}
elem.append(clonedElement);
});
}
if( newval.length > iterationMeta.cutoff ) {
// this too can be parametric, leaving for another time ;)
elem.append('<span class="sentence-more"> +' + (newval.length - iterationMeta.cutoff) + ' more</span>');
}
}
);
};
}
};
}]);
And the fiddle: https://jsfiddle.net/aza6u64p/ 小提琴: https : //jsfiddle.net/aza6u64p/
This is a tricky problem. 这是一个棘手的问题。 Transclude is used to wrap elements but when using transclude you don't have access to the directive scope, only to the scope of where the directive is being used:
Transclude用于包装元素,但是当使用transclude时,您无权访问指令范围,只能访问指令的使用范围:
AnglularJS: Creating Custom Directives AnglularJS:创建自定义指令
What does this transclude option do, exactly?
这个转换选项究竟做了什么? transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.
transclude使得带有此选项的指令的内容可以访问指令之外的范围而不是内部。
So a solution is to create another component to inject the template's scope inside the directive, like this: 因此,解决方案是创建另一个组件以在模板中注入模板的范围,如下所示:
.directive('myList', function() {
return {
restrict: 'E',
transclude: true,
scope: { items: '=' },
template: '<div ng-repeat="item in items" inject></div>'
};
})
.directive('inject', function() {
return {
link: function($scope, $element, $attrs, controller, $transclude) {
$transclude($scope, function(clone) {
$element.empty();
$element.append(clone);
});
}
};
})
<my-list items="articles">
<strong>{{item.title}}</strong> by <span>{{item.author}}</span>
</my-list>
This was taken from this discussion: #7874 这是从这个讨论中得出的: #7874
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.