【问题标题】:Angularjs Interpolation using double curly braces not working under ng-if使用双花​​括号的Angularjs插值在ng-if下不起作用
【发布时间】:2017-07-21 21:10:47
【问题描述】:

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>

基于 cmets,我使用了controller As 表示法并相应地定义了MainController。请参阅下面的快照。如果ng-if 嵌套了两个级别,似乎有问题。范围变量完全混淆了。使用ng-bind 和双花括号我没有得到相同的结果。

如果您检查上面的快照,即使我使用了 controller As 表示法,您也会看到与使用 {{}} 的插值相比,ng-bind 给出了不同的结果。

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

scope.MainController.wind_turbine = 'Yes';

我注意到在页面加载时,一切看起来都很好,但是当我使用鼠标更改输入元素 wind_trubine 的值时,所有相关引用都正确更新,除了使用 {{}} 的引用。

也许这是因为ng-if有两个嵌套级别?

感谢您的反馈。

塔雷克

【问题讨论】:

  • 您依赖wind_turbine 在您的范围内。 ng-if 创建一个新的内部范围,所以你应该做的是在 ng-controller 行中有一个 controllerAs="vm" 或类似的东西(可能是这个语法,但我可能错了),然后使用 vm.wind_turbine 而不是直接使用wind_turbine
  • 这看起来像是 angularjs 的黄金法则适用的情况:在角度绑定中始终使用点。 (换句话说,绑定到对象属性,而不是原语)。
  • 依赖$parent 中的ng-model 到达正确的范围是不明智的。如果两个级别的ng-if 指令创建了两个级别的范围,则该值将放置在绑定不可用的范围内。
  • @GioraGuttsait:我听从了你的建议,但还是同样的问题。请参阅上面的更新说明。

标签: angularjs angularjs-scope interpolation angular-ng-if


【解决方案1】:

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([已弃用!],将在下一个主要版本中删除 - 即 v2.0)

指定模板应该替换的内容。默认为false

  • true - 模板将替换指令的元素。
  • false - 模板将替换指令元素的内容。

-- AngularJS Comprehensive Directive API - replace deprecated

来自 GitHub:

Caitp-- 它已被弃用,因为replace: true 存在已知的非常愚蠢的问题,其中许多问题无法以合理的方式真正解决。如果您小心并避免这些问题,那么您将获得更多权力,但为了新用户的利益,告诉他们“这会让您头疼,不要这样做”会更容易。

-- AngularJS Issue #7636

欲了解更多信息,请参阅Explain replace=true in Angular Directives (Deprecated)

【讨论】:

  • 哇!谢谢......现在只是想知道这种变化将如何影响我的项目。
【解决方案2】:

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'
    } 
});

这个解决方案的主要问题是我使用了scope 参数,该参数传递给link() 函数。例如,在上面的.each() 循环中,我需要使用{{&lt;angular expre&gt;}} 获取基于插值的元素ID 的值。

所以我尝试在compile 可用的scope 函数中使用pre-linkpost-link。我注意到在pre-link 中执行时删除了带有ng-if 的部分,然后不久又添加了它。所以我不得不使用$watch 来监控孩子们的变化,以便在需要时运行所需的进程。我开发了这个 plunker 示例:

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

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

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

塔雷克

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    相关资源
    最近更新 更多