AngularJS指令作用域和$compile - 变量返回空白

3

我遇到了一个与Angular相关的小问题,但无法解决。我怀疑这可能与作用域有关,但我并不完全确定。

以下是我的HTML代码:

<i class="icon-question-sign" popover data-placement="top" data-trigger="hover" data-title="Top 10 clients" data-content-compile="<ul><li ng-repeat='client in user.clients | limitTo: 10'>{{client}}</li></ul>"></i>

这里是我的指令:

app.directive('popover', function($timeout, $compile) {
var linker = function (scope, element, attrs) {
    $timeout(function() {
        var content = $compile(element.data('content-compile'))(scope);
        element.popover({
            'html': true,
            'content': content
        });
    }, 200);
}

return {
    restrict: 'A',
    link: linker
}

});

结果正确地重复了li,长度为{{user.clients}},但没有呈现{{client}}。出于某种原因,它显示为空白,然而它有一个字符串值,并且在直接添加到HTML并未经过指令编译时可以正常工作。它当前在DOM中的显示如下:

<ul class="ng-scope"><!-- ngRepeat: client in user.clients | limitTo: 10 --><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li></ul>

如果我将{{client}}替换为{{user.email}},它会正确列出。不确定这里出了什么问题 - 我可能漏掉了一些明显的东西!

如果您写成“{{user.clients[$index]}}”而不是“{{client}}”,它是否有效?或者,如果您将“ng:repeat”写成“client in user.clients track by $index”(这需要AngularJS> = 1.15),它是否有效?这只是两个尝试,如果其中一个有帮助,我会不确定原因。 - Juliane Holzt
用户.客户端只是一个字符串数组吗? - kreek
@kju不幸地没有起作用 :( - tinyBIGideas
@kreek 是的,它是一个字符串数组 - 这是问题吗? - tinyBIGideas
我也这么想,但还是值得一试的,因为通过一些推理,它可能是问题的原因。 - Juliane Holzt
@kju 绝对值得一试,谢谢您的回复! - tinyBIGideas
2个回答

2

解决问题的关键是找到它的原因:{{client}}data-content-compile中被编译,这发生在指令启动之前,因此在控制器上下文中,client将未定义。目前,您传递给$compile的字符串是:

<ul><li ng-repeat='client in user.clients | limitTo: 10'></li></ul>

为了防止这种情况发生,模板必须以其他方式发送到指令中。以下是一些方法:
  1. 将模板作为字符串存储在控制器中。我认为这样做比较丑陋。
  2. 将模板存储在template中,并从$templateCache中检索它。
我使用第二种方法做了一个示例:在这里
<div ng-controller="ctrl">
    <script type="text/ng-template" id="client.html">
        <div><ul><li ng-repeat='client in user.clients'>{{client.name}}</li></ul></div>
    </script>
    <i
        popover
        class="glyphicon glyphicon-user"
        data-placement="bottom"
        data-trigger="hover"
        data-title="Top 10 clients"
        data-content-template="client.html"
    ></i>
</div>

angular.module("app", [])
.controller("ctrl", function($scope, User) {
    $scope.user = User;
})
.directive("popover", function($compile, $timeout, $templateCache) {
    return function(scope, el, attr) {
        $timeout(function() {
            el
            .popover({
                html: true,
                content: $compile($templateCache.get(attr.contentTemplate))(scope)
            })
            .popover("show")
        });    
    };
})
.value("User", {
    clients: [
        { name: "John", age: 22},
        { name: "Ann", age: 13},
        { name: "Maria", age: 62},
        { name: "Ivan", age: 44}
    ]
});

谢谢您的回复!我尝试了您提供的两种方法,但不幸的是遇到了同样的问题。不过,您指出了正确的方向,这帮助我解决了问题!由于我的数据分为两部分,第二部分创建了{{user.clients}},需要更多时间来解析。所以我使用了$q,并将$compile内容移出了$timeout,现在可以正确地显示客户端了。虽然不是100%确定原因,但现在一切都正常了!再次感谢您! :) - tinyBIGideas

0

看起来答案比我预期的要简单明了一些,我只需要将指令更改为:

// popover
app.directive('popover', function($timeout, $compile) {
    var linker = function (scope, element, attrs) {
        var content = $compile(element.data('content-compile'))(scope);
        $timeout(function() {
            element.popover({
                'html': true,
                'content': content
            });
        }, 400);
    }

    return {
        restrict: 'A',
        link: linker
    }

});

唯一的区别是我将 $timeout 周期加倍,并将已编译的变量移到其外面。确保在调用数据之前进行编译。
不确定这是否是正确的方法,但测试后它在所有情况下都能正确返回。尽管如此,如果您有类似的问题,请带着一点怀疑来使用此解决方案。

1
我认为这不是一个好的解决方案,因为基本上你在这里创建了一个竞态条件。 - Juliane Holzt
2
你是否有一个fiddle或plunkr,包含你当前(可工作的)代码,以便他人可以与之互动,并可能提出更好的解决方案? - Juliane Holzt
我觉得这很有趣,@tinyBIGideas你在使用.data('content-compile')做什么? - Kristian

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