模板总是与旧指令范围值编译 [英] Template always compiles with old scope value in directive

查看:95
本文介绍了模板总是与旧指令范围值编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经得到了的工作像这样的指令:

I've got a directive that's working like this:

http://jsfiddle.net/smithkl42/cwrgLd0L/23/

App.directive('prettify', ['$compile', function ($compile) {
    var templateFn;
    return {
        restrict: 'E',
        scope: {
            target: '='
        },
        link: function (scope, element, attrs) {
            if (!templateFn) {
                var template = element.html();
                templateFn = $compile(template);
            }
            scope.$watch('target', function (newVal, oldVal) {
                var compiled = templateFn(scope);
                element.html('');
                element.append(compiled);
                var html = element.html();
                var prettified = prettyPrintOne(html);
                element.html(prettified);
            }, true);
        }
    };
}]);

问题是,当我编译模板,它总是与的的目标值为属性编译。所以它开始呈现这一点,即,它的行事像有什么可替换:

The problem is that when I compile the template, it always compiles with the old value of the target property. So it starts off showing this, i.e., it's acting like there's nothing to replace:

然后,如果我添加一个字符属性,它显示了这一点,即 previous 的价值 scope.organization.message 属性:

Then if I add a character to the property, it shows this, i.e., the previous value of the scope.organization.message property:

调试表明,在目标值的范围指令的财产是在编译时是正确的。

Debugging shows that the values in the target property of the scope directive are correct at the time of the compile.

我是什么做错了吗?有什么有关返回的模板函数编译$ 看起来在老的范围值?还是...?

What am I doing wrong? Is there something about the template function returned by $compile that looks at the old scope values? Or...?

(另见这个问题,这导致了这样一句:<一href=\"http://stackoverflow.com/questions/27509934/using-compile-in-a-directive-triggers-angularjs-infinite-digest-error\">Using $编译指令触发AngularJS无限消化错误。)

(See also this question, which led to this one: Using $compile in a directive triggers AngularJS infinite digest error.)

推荐答案

首先,你的 templateFn 变量在厂级范围,但它是在实例填充水平。这意味着,您使用该指令在第一时间,将填充使用该元素的指令,之后每次使用时也将使用同样的模板,​​即使它实际上有不同的模板。

First off, your templateFn variable is scoped at the factory level, but it is populated at the instance level. This means that the first time you use the directive, it will populate using that element's directive, and every usage after that will also use that same template, even if it actually has a different template.

您似乎延迟绑定问题的原因有消化周期做,以及如何管理角度变化到DOM。当正在处理的范围变更,范围观察家都处理的的任何改变都对DOM的。这样,所有的DOM更改合并为一个批次(对于周期至少)这样你就不会一次过多次更新,从而可能导致多个回流。所以,当你调用 element.html(),你在一个点,在DOM一直没有更新,以反映示波器上的变化值,这样做

The cause of your seemingly delayed binding issue has to do with the digest cycle and how Angular manages changes to the DOM. When a scope change is being processed, the scope watchers are all processed before any changes are made to the DOM. This way, all DOM changes are consolidated into a single batch (for that cycle at least) so you aren't make multiple updates at once, potentially causing multiple reflows. So, when you're calling element.html(), you're doing so at a point where the DOM hasn't been updated to reflect the changed values on the scope.

在这种特殊情况下,你还做了一堆额外的工作 - 调用 templateFn 会给你你所需要的内容的jQuery(或jQLite)对象 - 没有必要将它添加到DOM,然后拿回来了,你可以叫 HTML()直接反对。

In this particular case, you're also doing a bunch of extra work - calling templateFn will give you a jQuery (or jQLite) object with the content you need - there's no need to add it to the DOM, and then take it back out, you can just call html() directly against it.

这逻辑都可能被合并(和正常工作),像这样:

That logic could all be consolidated (and work correctly) like so:

setTimeout(function () {
    var compiled = templateFn(scope).html();
    var prettified = prettyPrintOne(compiled);
    element.html(prettified);
}, 0);

的setTimeout 结束语一切强制逻辑进行评估的之后的消化周期完成。

Wrapping everything in setTimeout forces the logic to be evaluated after the digest cycle is complete.

然而,一般来说,该指令,落实是一个有点尴尬:

However, generally speaking, that implementation of the directive is a bit awkward:


  • 如果有HTML模板(如&LT; pre&GT; &LT; code&GT; 这需要对每个使用标签),应列入通过模板指令本身 templateUrl 属性而不是期望消费者知道它需要

  • 您或许可以蒙混过关,而无需使用 $编译实现这一点 - 你可以把输出 prettyPrintOne 的范围,并且只绑定到它在模板指定的模板 templateUrl 属性,或者你可以使用jQuery去哪个元素将是容器的引用(也就是说,如果它不是顶级元素),并使用 HTML()来设置其内容。

  • 如果你确实需要让其他模板化的HTML内容被指令中定义的,看看在的 transclude 选项=HTTPS:/ /docs.angularjs.org/guide/directive相对=nofollow>指令指南

  • If there's HTML templating (e.g. <pre> and <code> tags) that is required for each usage, that should be included in the the directive itself via the template or templateUrl properties rather than expecting the consumer to know that it's required
  • You can probably get away implementing this without using $compile - you can either put the output of prettyPrintOne on the scope, and just bind to it in the template specified in the template or templateUrl properties, or you can use jQuery to get a reference to whichever element will be the container (that is, if it's not the top-level element) and use html() to set its content.
  • If you do actually need to allow other templated HTML content to be defined inside the directive, look into the transclude option defined in the directive guide.

这篇关于模板总是与旧指令范围值编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆