javascript - 在指令中监听表单提交事件

标签 javascript angularjs forms angularjs-directive

我想在指令中监听表单提交。假设我有这样的指令:

app.directive('myDirective', function () {
    return {
        restrict: 'A',
        require: '^form',
        scope: {
            smth: '='
        },
        link: function (scope, el, attrs, formCtrl) {
            scope.$watch(function(){
                return formCtrl.$submitted;
            },function(currentValue){
                console.log('submitted');
            });
        }
    }
});

用上面的方法我可以看到第一次提交,但不能看到其余的。我试图做这样的事情:

scope.$watch(function () {
    return formCtrl.$submitted;
}, function (currentValue) {
    if (currentValue) {
        console.log('submitted');
        formCtrl.$setPristine(); // Watch this line!
    }
});

但问题是,如果我在一个表单中多次使用该指令,它只对第一次使用有效。 我想知道的是是否有类似 formCtrl.onsubmit(...) 的东西或任何解决方法来获得相同的功能。在此先感谢您的帮助...

最佳答案

您可以创建一个与 form 指令同名的指令,而不是观察 $submitted 属性,该指令附加了一个表单提交的事件处理程序广播一个 Angular 事件,您可以在 myDirective 指令中收听该事件。您不必担心覆盖 form 指令的 Angular 实现,它只会附加您的行为,不会覆盖内置实现。

DEMO

注意:您也可以选择不将功能附加到 form 指令,而是选择另一个指令名称,只需确保将该指令名称附加为表单标记中的属性即可触发事件.

Javascript

.directive('form', function() {

  return {
    restrict: 'E',
    link: function(scope, elem) {
      elem.on('submit', function() {
         scope.$broadcast('form:submit');
      });
    }
  };

})

.directive('myDirective', function() {
  return {
    require: '^form',
    link: function(scope, elem, attr, form) {
      scope.$on('form:submit', function() {
        form.$setPristine();
      });
    }
  };
});

更新

鉴于下面评论中提出的问题:

what's the most efficient way to check if the element that has "my-directive" attribute has "my-form" (if I name "form" directive to "myForm") attribute in it's parent form? So I can either use "myDirective" with or without "myForm" (and behave accordingly of course)

有几种方法可以做到这一点:

  1. 在编译阶段使用 myForm 指令中的 .data() 方法,并在 myDirective 的链接函数中访问它如果在 form 指令中分配的数据存在,则使用 .inheritedData() 方法。

请注意,我在 myForm 指令的广播中传递了 form Controller 。这确保您收到来自 form 元素的父表单 Controller 。在某些用例中,您可以通过 ng-form 在嵌套表单中使用 myDirective,而不是设置 form.$setPristine() 到您要设置 ngForm 表单 Controller 的 form 元素表单 Controller 。

DEMO

  .directive('myForm', function() {

    return {
      require: 'form',
      compile: function(tElem, tAttr) {

        tElem.data('augmented', true);

        return function(scope, elem, attr, form) {
          elem.on('submit', function() {
             scope.$broadcast('form:submit', form);
          });
        }
      }
    };

  })

  .directive('myDirective', function() {
    return {
      link: function(scope, elem, attr) {

        if(!elem.inheritedData('augmented')) {
          return;
        }

        scope.$on('form:submit', function(event, form) {
          console.log('submit');
          form.$setPristine();
        });
      }
    };
  });
  1. 另一种方式可能是针对此特定用例高度优化的方式。在 myForm 指令中创建一个 Controller ,该指令存储要在触发表单事件时迭代的表单事件处理程序。而不是使用 $broadcast Angular 事件,它实际上比下面的实现慢,因为它遍历从 form 元素到最后一个范围链的每个范围。下面的 myForm Controller 创建了自己的机制来存储事件处理程序。正如#1 中所实现的,使用 .data() - inheritedData() 很慢,因为 myDirective 被埋得很深并且嵌套在很多地方元素,因为它向上遍历 DOM,直到找到特定的 data。使用下面的实现,您可以检查父级中是否存在所需的 ?^myForm Controller ,注意 ? 它代表可选要求。此外,在 myForm 指令中将范围设置为 true 允许您使指令可重用,例如在一个页面中有多个 myForm 指令..

DEMO

  .directive('myForm', function() {

    return {
      require: ['form', 'myForm'],
      scope: true,

      controller: function() {

        this.eventHandlers = {
          submit: [],
          change: []
        };

        this.on = function(event, handler) {
          if(this.eventHandlers[event]) {
            this.eventHandlers[event].push(handler);
          }
        };

      },

      link: function(scope, elem, attr, ctrls) {
        var form = ctrls[0],
            myForm = ctrls[1];


        angular.forEach(myForm.eventHandlers, function(handlers, event) {
          elem.on(event, function(eventObject) {
            angular.forEach(handlers, function(handler) {
              handler(eventObject, form);
            });
          });
        });

      }

    };

  })

  .directive('myDirective', function() {
    return {
      require: '?^myForm',
      link: function(scope, elem, attr, myForm) {

        if(!myForm) {
          return;
        }

        myForm.on('submit', function(event, form) {
          console.log('submit');
          form.$setPristine();
        });
      }
    };
  });

关于javascript - 在指令中监听表单提交事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26383507/

相关文章:

javascript - 如何显示两天之间的表格行?

javascript - 在移动设备上隐藏 div 中的项目

javascript - AngularJS 如何与 JS minifiers 一起工作

javascript - 为什么表单上的提交按钮不起作用?

django - 删除Django Crispy表单中的标签

javascript - Zclip不复制文本

javascript - JavaScript 中的 JSON 到 Excel 文件

javascript - 循环遍历 Angular HTTP 请求中的对象,等待响应后再运行下一个循环

javascript - Angular : dynamic value issue

forms - CFML 从 form.zipcode 中仅选择 3 个整数