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

时间:2014-10-15 13:12:29

标签: 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(...)的内容或任何解决方法来获得相同的功能。提前感谢您的帮助......

4 个答案:

答案 0 :(得分:15)

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

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

更新

根据以下评论中提出的问题:

  

检查元素是否有效的最有效方法是什么   “my-directive”属性具有“my-form”(如果我将“form”命令命名为   “myForm”)属性在它的父表单中?所以我可以使用   “myDirective”有或没有“myForm”(并且相应地表现出来)   当然)

有几种方法可以做到:

  1. 在编译阶段使用.data()指令中的myForm方法,如果分配了数据,则使用myDirective方法在.inheritedData()的链接功能中访问该方法存在form指令。
  2. 请注意,我在form指令的广播中传递了myForm控制器。这可确保您收到来自form元素的父表单控制器。在某些用例中,您可以通过myDirective在嵌套表单中使用ng-form,因此不要将form.$setPristine()设置为您要设置的form元素表单控制器ngForm表单控制器。

    <强> 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指令中创建一个控制器,用于存储表单事件处理程序,以便在触发表单事件时进行迭代。而不是使用实际比下面的实现慢的$broadcast角度事件,因为它遍历每个范围从form元素到最后一个范围链。下面的myForm控制器创建了自己的存储事件处理程序的机制。正如在#1中实现的那样,.data() - inheritedData()myDirective被深埋并嵌套在很多元素中时很慢,因为它向上遍历DOM直到data为止。它找到了特定的?^myForm。使用下面的实现,您可以检查父级中是否存在所需的?控制器,请注意它代表可选要求的myForm。此外,在myForm指令中将范围设置为true允许您使指令可重用,例如在页面中有多个 .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(); }); } }; }); 指令..
    2. <强> DEMO

      {{1}}

答案 1 :(得分:2)

您可以将ng-submit用于广播或类似内容,但可能先尝试$setUntouched(),或者在完成后手动将$submitted设置回false目前的提交。

答案 2 :(得分:0)

https://docs.angularjs.org/api/ng/directive/ngSubmit可能就是你要找的东西。

答案 3 :(得分:-1)

这篇文章可能已经死了但是基于上面的内容,我发现form指令没有正确地向其他指令广播,所以我将所有内容都包含在一个指令中。

这是一个基于表单生成警报的简单函数。如果表单无效,则为$ error: -

// automated handling of form submit errors
myApp.directive('form', [ function() {
    return {
        restrict: 'E',
        require: '^form',
        link: function (scope, elem, attr, form) {
            elem.on('submit', function () {
                if(form.$invalid){
                    console.log('form.$error: ', form.$error);

                    Object.keys(form.$error).forEach(error => {
                        form.$error[error].forEach(elem => {
                            console.log('error elem is: ', elem);
                            alert(error + ' for ' + elem.$name + ' is invalid! Current: ' + elem.$modelValue);
                        })
                    })
                }
                form.$setPristine();
            });
        }
    };
}])