在指令中监听表单提交事件 [英] Listen for form submit event in directive

查看:31
本文介绍了在指令中监听表单提交事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to listen for form submitting in a directive. Say I have a directive like this:

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

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

With the above method I can watch for first submit, but not the rest. I tried to do something like this:

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

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

But then the problem is, if I use the directive in a form more than once, it works only for the first usage. What I want to know is if there is something like formCtrl.onsubmit(...) or any workaround to get the same functionality. Thanks in advance for any help...

推荐答案

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

Instead of watching the $submitted property, you can create a directive that has the same name as the form directive which is attached with an event handler for form submit that broadcasts an angular event that you can listen in your myDirective directive. You don't have to worry about overriding the angular implementation of the form directive, it will simply append your behavior not overwrite the built-in implementation.

演示

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

Note: You can also choose not to append functionality to the form directive and instead choose another directive name, just make sure to attach that directive name as an attribute in the form tag to trigger the event.

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

更新

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

Update

In light of the question raised in the comment below:

检查元素是否具有最有效的方法是什么?my-directive"属性具有my-form"(如果我将form"指令命名为"myForm") 属性在它的父表单中?所以我可以使用带有或不带有myForm"的myDirective"(并根据当然)

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() 方法.
  1. Use the .data() method in your myForm directive during the compile phase, and access it in the link function in your myDirective using the .inheritedData() method if the data assigned in the form directive exists.

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

Note that I passed the form controller within the broadcast in the myForm directive. This ensures that you receive the parent form controller which is the from the form element. There are certain use cases wherein you would use the myDirective inside a nested form via ng-form, so instead of setting form.$setPristine() to the form element form controller you'd be setting the ngForm form controller.

演示

  .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 指令中创建一个控制器,该指令存储表单事件处理程序,以便在触发表单事件时进行迭代.而不是使用 $broadcast 角度事件,它实际上比下面的实现慢,因为它遍历从 form 元素到最后一个作用域链的每个作用域.下面的 myForm 控制器创建了自己的机制来存储事件处理程序.正如在#1 中实现的那样,当 myDirective 被埋得很深并且嵌套很多时,使用 .data() - inheritedData() 会很慢元素,因为它向上遍历 DOM 直到找到特定的 data.使用下面的实现,您可以检查所需的 ?^myForm 控制器是否存在于父级中,注意 ? 它代表一个可选的要求.此外,在 myForm 指令中将 scope 设置为 true 允许您使指令可重用,例如一个页面中有多个 myForm 指令..
  1. Another way which is probably something that is highly optimized for this specific use case. To create a controller in the myForm directive which stores form event handlers to be iterated when a form event is triggered. Instead of using the $broadcast angular event which is actually slower than the implementation below because it traverses each scope from the form element down to the last scope chain. The myForm controller below creates its own mechanism for storing the event handlers. As implemented in #1, using the .data() - inheritedData() is slow when the myDirective is buried deep and nested from a lot of elements, since it traverses the DOM upwards until it finds that specific data. Using the implementation below, you can check if the required ?^myForm controller exists in the parent, notice the ? it represents an optional requirement. Additionally, setting scope to true in the myForm directive allows you to have the directive reusable, e.g. have multiple myForm directives inside a page..

演示

  .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();
        });
      }
    };
  });

这篇关于在指令中监听表单提交事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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