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

s.a*_*lem 7 javascript forms angularjs 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');
            });
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

通过上面的方法,我可以看到第一次提交,但不是其余的.我试着这样做:

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

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

rye*_*lar 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();
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

更新

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

什么是检查是否有"我的指示性"属性的元素有"我型"的最有效的方式(如果我的名字"形式"指令"myForm会")属性,它的父窗体?所以我可以使用"myDirective",有或没有"myForm"(当然也有相应的行为)

有几种方法可以做到:

  1. 使用.data()在你的方法myForm指令在编译阶段,并访问它的链接功能时,您在myDirective使用该.inheritedData()方法,如果在指定的数据form存在指令.

请注意,我formmyForm指令中的广播中传递了控制器.这可确保您收到来自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();
        });
      }
    };
  });
Run Code Online (Sandbox Code Playgroud)
  1. 另一种可能针对此特定用例进行了高度优化的方法.在myForm指令中创建一个控制器,用于存储表单事件处理程序,以便在触发表单事件时进行迭代.而不是使用$broadcast实际比下面的实现慢的角度事件,因为它遍历从form元素到最后一个范围链的每个范围.myForm下面的控制器创建自己的机制来存储事件处理程序.正如在#1中实现的那样,当深埋并嵌套来自许多元素时,使用.data()- inheritedData()是很慢的myDirective,因为它遍历DOM向上直到找到特定的元素data.使用下面的实现,您可以检查?^myForm父级中是否存在所需的控制器,请注意?它代表可选的要求.此外,在myForm指令中将scope设置为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();
        });
      }
    };
  });
Run Code Online (Sandbox Code Playgroud)