Angularjs 使用双花括号的插值在 ng-if 下不起作用

Angularjs Interpolation using double curly braces not working under ng-if

UPDATE1: 开发了将重现该问题的 plunker 示例。见下文。

我的项目中有一个奇怪的问题,它只出现在一个地方。最后,我能够使用 plunker 示例重现该问题:

http://plnkr.co/edit/JJbq54?p=preview

在上面的示例中,请参阅 "With ng-if" 和 "Without ng-if" 部分,在输入文本中输入一些内容,然后查看双花括号如何在 ng-if 下不起作用,但是 ng-bind 工作正常。此外,如果您从模板 sites-and-improvements.html 中删除 check-if-required,问题也会得到解决。


更多详情如下:

我有以下 HTML5 代码块:

    <div ng-if="isFullCUSPAP" id="sites_and_imrpovements_comments">
        <div class="form-row">
            <div class="inputs-group">
                <label>WIND TURBINE:</label>
                <div class="input-binary">
                    <label>
                       <input type="radio" id="wind_turbine" 
                              name="wind_turbine"
                              ng-model="$parent.wind_turbine" 
                              value="Yes" force-model-update />
                       Yes
                    </label>
                </div>
                <div class="input-binary">
                    <label>
                      <input type="radio" id="wind_turbine"
                             name="wind_turbine" 
                             ng-model="$parent.wind_turbine" 
                             value="No" force-model-update />
                      No
                    </label>
                </div>
                <span ng-bind="wind_turbine"></span>
                <span>wind_turbine = {{wind_turbine}}</span>
            </div>
        </div>
    </div>

我知道 ng-if 会创建一个新的子作用域。见上面的代码,作用域变量 wind_trubine。只有在这个 HTML5 文件中,花括号 {{}} 不起作用。但是,如果我使用 ng-bind 它工作正常。在其他 HTML5 文件中,我从来没有遇到过任何问题。 HTML5 是使用如下指令实现的:

app.directive('sitesAndImprovements', function() {
    return {
        restrict: 'E',
        replace:true,
        templateUrl: '<path-to-file>/site-and-improvments.html',
        link: function (scope, elem, attrs) {
            //Business Logic for Sites and Improvements
        }
    } 
})

而且,简单地说,我将其放在父级中,如下所示:

<sites-and-improvements></sites-and-improvements>

我能看到的唯一区别是此实现有两层嵌套 ng-if,如下所示:

<div ng-if="some_expression">
    ...
    ...
    <sites-and-improvements></sites-and-improvements>
    ...
    ...
</div>

根据评论,我使用了 controller As 符号并相应地定义了 MainController。请参阅下面的快照。 ng-if嵌套两层好像有问题。范围变量完全混淆了。使用 ng-bind 和双花括号我没有得到相同的结果。

如果你检查上面的快照,即使我使用了 controller As 符号,你会发现 ng-bind 与使用 {{}} 的插值相比给出了不同的结果。

我什至将wind_turbine的默认值更改为在link函数中设置如下:

scope.MainController.wind_turbine = 'Yes';

我注意到在页面加载时,一切看起来都很好,但是当我使用鼠标更改输入元素 wind_trubine 的值时,所有相关参考都会正确更新,除了使用 [=22= 的参考].

可能是因为 ng-if 有两层嵌套?

感谢您的反馈。

塔雷克

sites-and-improvements 指令中删除 replace: true

app.directive('sitesAndImprovements', function() {
    return {
        restrict: 'E',
        ̶r̶e̶p̶l̶a̶c̶e̶:̶t̶r̶u̶e̶,̶
        templateUrl: 'site-and-improvments.html',
        link: function (scope, elem, attrs) {
          //debugger;
        }
    } 
})

它正在对抗 check-if-required 指令:

app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
  return {
    priority: 2000,
    terminal: true,
    link: function (scope, el, attrs) {
      el.removeAttr('check-if-required');

      $timeout(function(){
        //debugger;
        $(':input', el).each(function(key, child) {
          if (child && child.id === 'test_me') {
                angular.element(child).attr('ng-required', 'true');
                }
          if (child && child.id === 'testInput1') {
            //debugger;
                //angular.element(child).attr('ng-required', 'true');
                }
        });
            $compile(el, null, 2000)(scope);
      })
    }
  };
}])

DEMO on PLNKR.


replace:true is Deprecated

来自文档:

replace ([DEPRECATED!], will be removed in next major release - i.e. v2.0)

specify what the template should replace. Defaults to false.

  • true - the template will replace the directive's element.
  • false - the template will replace the contents of the directive's element.

-- AngularJS Comprehensive Directive API - replace deprecated

来自 GitHub:

Caitp-- It's deprecated because there are known, very silly problems with replace: true, a number of which can't really be fixed in a reasonable fashion. If you're careful and avoid these problems, then more power to you, but for the benefit of new users, it's easier to just tell them "this will give you a headache, don't do it".

-- AngularJS Issue #7636

有关详细信息,请参阅 Explain replace=true in Angular Directives (Deprecated)

AngularJS 团队在此处发布的另一个解决方案:

https://github.com/angular/angular.js/issues/16140#issuecomment-319332063

基本上,他们建议将 link() 函数转换为使用 compile() 函数。这是更新代码:

app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
  return {
    priority: 2000,
    terminal: true,
    compile: function (el, attrs) {
      el.removeAttr('check-if-required');
      var children = $(':input', el);
      children.each(function(key, child) {
        if (child && child.id === 'test_me') {
            angular.element(child).attr('ng-required', 'true');
                }
      });
            var compiled = $compile(el, null, 2000);
            return function( scope ) {
                compiled( scope );
            };
    }
  };
}]).directive('sitesAndImprovements', function() {
    return {
        restrict: 'E',
        replace:true,
        templateUrl: 'site-and-improvments.html'
    } 
});

这个解决方案的主要问题是我正在使用传递给 link() 函数的 scope 参数。例如,在上面的 .each() 循环中,我需要使用 {{<angular expre>}}.

获取基于插值的元素 ID 的值

所以我尝试在 scope 可用的 compile 函数中使用 pre-linkpost-link。我注意到当在 pre-link 中执行时,带有 ng-if 的部分被删除,然后不久之后添加。因此,我不得不使用 $watch 来监视对子进程的更改,以便在需要时 运行 所需的进程。我开发了这个 plunker 示例:

http://plnkr.co/edit/lsJvhr?p=preview

经过这么多努力,问题还是没有解决。所以类似情况的底线是,如果你需要使用范围,那么你必须删除 replace: true.

如有任何反馈,我们将不胜感激。

塔雷克