0

更新1:添加更多细节。
更新 2:添加了 plunker 代码以重现问题。请参阅下面的链接。
更新 3:我在 github 上收到了 Angular 团队的回复。在这里检查。
更新 4:应 AngularJS 团队的要求在 github 上发布更新。此外,我之前添加的建议解决方案结果证明它正在创建一个新的视觉问题。请参阅下面的详细信息。
更新 5:从 Angular 团队获得另一个反馈。我认为我们已经接近找到解决方案的 80%。

我在我的项目中实现了Angular UI datepicker,过了一会儿,我注意到当我打开弹出框并单击月份更改为另一个月份时,另一个弹出窗口会显示在现有弹出窗口的顶部。请参阅下面的快照以获取更多详细信息:

在此处输入图像描述

最初,当我单击月份时,当前弹出窗口应该消失,并且应该显示另一个弹出窗口以选择新月份。

但是,当我在该月单击两次(下面以黄色突出显示)时,弹出窗口将消失,并且可以正常工作。但是,在我选择了一个日期之后,问题就会再次出现。

我正在使用来自 angular ui datepicker 官方演示网站的相同示例代码。在下面找到相关网站和 plunker 代码:

http://angular-ui.github.io/bootstrap/versioned-docs/1.3.3/#/datepickerPopup http://plnkr.co/edit/lEgJ9eC9SzBWsgVhhQkq?p=preview

我的代码与上面 plunker 示例中的代码完全相同。唯一的区别是我使用$compile服务来动态添加必填字段验证。

经过广泛的故障排除后,发现该$compile()服务会导致此行为。我做了一些研究,发现该$compile服务还会导致下拉列表或select元素中的重复项。我使用了建议的解决方法,它奏效了。请参见下面的代码:

$compile(child)(elmScope, function (clone) {
    angular.element(child).after(clone);     
    angular.element(child).remove();
});

我使用的原因是在这里$compile使用这种方法将动态验证规则从 DB 添加到元素。

在我得到github 上 Angular 团队的回复后,我发现他们提出了这个修复建议

.directive('checkIfRequired', ['$compile', function ($compile) {
    return {
      priority: 1000,
      terminal: true,
        /*require: '?ngModel',*/
        //JIRA: NE-2535 - inject the current 'ngForm' controller with this directive
        //      This is required to add automatice error message when the Form Field is invalid.
        require: '?^form',
      link: function (scope, el, attrs, ngForm) {
        el.removeAttr('check-if-required');
        el.attr('ng-required', 'true');
        $compile(el, 1000)(scope);
      }
    };
}]);

当我尝试应用建议的修复程序时,我遇到了大量错误。似乎当使用terminal=truethen 时,'ng-init' 下的内部元素中的所有代码都没有执行。我注意到许多范围变量变得“未定义”。

这是github上试图找到解决方案的最后更新。请参见下面的代码:

app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
  return {
    priority: 2000,
    terminal: true,
    /*link: function (scope, 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');
                }
      });
      $compile(children)(scope);
    },*/
    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(children, null, 2000);
        return function( scope ) {
            compiled( scope );
        };
    }
  };
}]);

感谢您在我的项目中以正确的方式应用修复程序的帮助。在此处查看代码的相关部分


我之前发布了一个解决方案,但后来我删除了它。后来我注意到它引起了一个有趣的堆叠效果,比我之前报道的更糟糕。

这是 github 上的更新,包含完整的详细信息:

https://github.com/angular/angular.js/issues/15956#issuecomment-300324812

当我收到 AngularJS 团队的回复时,我会继续更新。

在我找到永久解决方案之前,请耐心等待。


旧建议的解决方案:

为了避免这个问题不能使用$compile服务,或者如果你必须使用这个代码示例来解决这个问题:

$compile(child)(elmScope, function (clone) {
    angular.element(child).after(clone);     
    angular.element(child).remove();
});

希望这对面临同样问题的其他人有价值。

4

2 回答 2

0

这是我从 github 的 AngularJS 团队获得的另一个解决方案。点击这里在 github 上查看答案

请参阅此处的代码部分作为此建议解决方案的基础:

如果无效,则需要对具有字段突出显示的字段组进行角度动态验证

基本上,您可以使用以下代码示例来避免$compile在指令链接函数中使用时出现双重编译问题:

app.directive('checkIfRequired', ['$compile', '$timeout', function ($compile, $timeout) {
    return {
        priority: 2000,
        terminal: true,
        link: function (scope, el, attrs) {
            el.removeAttr('check-if-required');
            $(':input', el).each(function(key, child) {
                if (child && child.id === 'test_me') {
                    angular.element(child).attr('ng-required', 'true');
                }
            });
            $compile(el, null, 2000)(scope);
        }
    };
}]);

这是必需的,因为您有一个循环将遍历与指令相关的父元素的子元素check-if-required

于 2017-05-11T23:42:48.530 回答
0

这是为了进行校正。之前添加的解决方案没有按预期工作。

有关完整的详细信息,请查看 github 上的更新:

https://github.com/angular/angular.js/issues/15956#issuecomment-300324812

现在我可以提出一种不同的方法来使用存储在数据库中并使用 AngularJS 表单加载的动态验证规则。

请参阅此处的代码部分作为此建议解决方案的基础:

如果无效,则需要对具有字段突出显示的字段组进行角度动态验证

代替使用$compile, 在指令check-if-required中,为字段创建一个新scope变量,child.id如下所示:

if (scope.isFieldRequired(child.id)) {
    //angular.element(child).attr('ng-required', "true");
    //$compile(child)(elmScope);
    scope.RootController.ngRequired[child.id] = true;
} else {
    scope.RootController.ngRequired[child.id] = false;
}

定义元素时,请确保它类似于以下内容:

<input id="customer_id" name="customer_id" ng-model="customer_id" ng-required="RootController.ngRequired.customer_id"/>

基本上,所有验证规则都必须链接到必须在根 Angular 控制器RootController'. For simplicity, the required validation will be underRootController.ngRequired 中定义的范围变量。

有必要在最顶层的外部控制器上RootController使用符号进行定义。controller as否则,上述解决方案将不起作用。以下是根控制器的示例元素定义:

<body ng-app="myApp" ng-controller="formMainController as RootController">
...
</body>

如果我在使用 Angular 团队发现的问题上没有得到满意的答复$compile,我将切换到上述方法。我几乎可以肯定上述方法会奏效。

如果您有任何反馈,请这样做。

塔雷克

于 2017-05-01T22:38:25.100 回答