分离然后附加 AngularJS 表单更改有效性状态 [英] Detach then append AngularJS form change validity status

查看:26
本文介绍了分离然后附加 AngularJS 表单更改有效性状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以在此 jsFiddle 中对其进行测试:HERE(最好在新的 jsFiddle 上查看,请参阅 编辑这篇文章的一部分)

You can test it in this jsFiddle: HERE (better is to see on new jsFiddle, see EDIT part of this post)

我认为 AngularJS 中存在一个错误,或者至少不是预期的结果.如果我分离一个表单然后重新附加它,它的类 ng-invalid 切换到 ng-valid 将它重新附加到 DOM.即使数据无效,这也会导致启用表单的提交按钮.当然,我期待有效性状态没有切换.

I think there is a bug in AngularJS or at least not an expected result. If i detach a form then re-append it, it's class ng-invalid switch to ng-valid on re-append it to the DOM. This has for consequence to enable the submit button of the form even data aren't valid. Of course, i was expecting that validity status didn't switch.

我认为这是一个角度错误,但可能是一个 jquery 错误.我可以使用 jquery 检查附加表单是否有效,然后强制表单类,但它似乎无法作为有效表单获取无效状态.这很奇怪,因为我不知道在分离之前不使用某种数据来保存状态表单的任何其他解决方法.

I think it's a angular bug, but maybe a jquery one. I could use jquery to check on append if form was valid or not and then forcing form class but it's seems not working as a valid form get then the status of invalid. It's quite weird as i don't know any other workaround without using kind of data to saved status form before detaching it.

那么有人遇到过这个问题吗?是否有任何方法(如果可能,使用 AngularJS 指令)来消除此错误?

So anyone has already encountered this problem? Is there any method (if possible using AngularJS directive) to get rid of this bug?

PS:我需要在单页 Web 应用程序中分离表单(和任何其他元素)以保持 DOM 尽可能干净.

PS: i need to detach form (and any other elements) in a single page web application to keep DOM as clean as possible.

编辑

我做了一个新的 jsFiddle,它更能说明我的问题,在内部网站导航上分离内容:http://jsfiddle.net/EWVwa/

I've done a new jsFiddle that is illustrating more my problem, detaching content on internal site navigation: http://jsfiddle.net/EWVwa/

更新

我来到这个临时解决方案(感谢CaioToOn)

I come to this temporary solution (thanks to CaioToOn)

http://plnkr.co/edit/KIgMz2

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});


app.directive('customValidation', function() {
  return {
    require: ['ngModel', '^?form'],
    link: function(scope, element, attr, ctrls) {
      console.log(ctrls);
      var ngModelCtrl = ctrls[0],
          formCtrl = ctrls[1];


      ngModelCtrl.$parsers.push(function(viewValue) {
        if (viewValue === 'test') {
          ngModelCtrl.$setValidity('name', true);
          formCtrl.$setValidity('name', true);
          return viewValue;
        } else {
          ngModelCtrl.$setValidity('name', false);
          formCtrl.$setValidity('name', false);
          return undefined;
        }
      });


      // custom event
      element.bind('$append', function() {
        formCtrl && formCtrl.$addControl(ngModelCtrl);
        /*** TEST for to keep form's validation status ***/
        formCtrl.$setValidity('name', ngModelCtrl.$valid);
        //ngModelCtrl.$setValidity('name', ngModelCtrl.$valid);
        console.log(formCtrl.$valid);
      });
      //binding on element, not scope. 
      element.bind('$destroy', function() {
        console.log("gone haven");        
      });
    }
  };
});

这需要更多关于多输入验证的测试.当所有测试完成后,我肯定会更新答案.

This need more testing regarding multiple inputs validation. I'll certainly updating answer when all tests will be done.

推荐答案

出现问题是因为 input 指令 从表单控件中移除自身.由于它不会再次链接您的 ngModel 和表单控制器,因此表单不再考虑您的输入.

The problem happens because input directive removes itself from the form controls when the element is removed from DOM. As it doesn't link your ngModel and form controller again, your input is not being considered by the form anymore.

你基本上有two三个选项:

  • 更改元素可见性而不是删除它
  • (更喜欢下面的那个)暴露一个relink"函数,可以将它重新添加到原始表单中
  • 在所有控件上触发自定义事件,以便他们可以重新链接自己

更改元素可见性 意味着您将在 DOMTree 中拥有不必要的 DOM 元素.这并不是很糟糕,因为无论如何您都会保留对 $compile 元素的引用,因此它仍然会参与 $digest 循环和DOM"修改.

Changing element visibility means you will have unnecessary DOM elements in DOMTree. This is not quite bad, as you are keeping a reference to the $compile element anyway, so it will yet participate the $digest cycles and "DOM" modifications.

(想了想,新的方案比这个稍微好一点,所以不要暴露relink函数) 暴露relink函数 很奇怪(虽然功能强大),这不是最可靠的解决方案.实现它的一种方法是要求表单控制器(require: ['ngModel', '^?form'])并将重新链接函数绑定到元素的数据:

(After thinking for a while, the new solution is slightly better than this one, so don't expose a relinking function) Exposing a relink function is quite weird (although functional) and this is not the most reliable of the solutions. One way to achieve it consists in requiring form controller (require: ['ngModel', '^?form']) and binding a relinking function to the element's data:

element.data('relink', function(){
  formCtrl && formCtrl.$addControl(ngModelCtrl);
});

当您再次将元素添加到屏幕时,您将不得不调用所有控件重新链接功能:

And when you add the element to the screen again, you gonna have to call all your controls relink function:

$('.controls').data('relink')();

此处查看示例.

它不太可靠,但可能适用于您的情况.

It's not quite reliable, but might work for your case.

触发自定义事件 与之前的几乎相同,但您会在所有应该重新链接的元素上分派自定义事件.这样更有条理,但仍然不太可靠,因为表单和其他链接也可能已损坏(同样,应该满足您的情况).基本上听听指令上的自定义事件:

Triggering a custom event is pretty much the same as the previous, but you would dispatch a custom event on all elements that should relink theirselves. This is way more organized, but still not quite reliable, because the form and other links might also have been broken (again, should sufice your case). Basically listen to the custom event on your directive:

element.bind('$append', function(){
  formCtrl && formCtrl.$addControl(ngModelCtrl);
});

而在更改为表单后,只需在所有控件上触发自定义事件:

And after changing to the form, just trigger the custom event on all controls:

$('.control').triggerHandler('$append');

这个更好的原因是指令仍然决定何时重新链接组件,并且事件是一种通用".这是一个正在工作的 plunker.

The reason why this one is better is that the directive still decides when to relink the component, and the event is kind of "generic". Here is a working plunker.

作为最后的努力,您可以覆盖 jQuery.fn.append 并递归触发所有子元素上的自定义事件(这就是 Angular 在删除元素时会).这是最有条理的,但它会影响您在所有 append 调用中的性能.

As a last effort, you could override jQuery.fn.append and trigger the custom event on all element children recursively (this is what Angular does when removing elements). This is the most organized, but it would impact yoour performance on ALL append calls.

这篇关于分离然后附加 AngularJS 表单更改有效性状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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