angular- bind form submit with multiple buttons

Problem

I have a form with multiple submit buttons:

<form name="myForm" customSubmit>
    <input type="text" ng-minlength="2">

    <button type="submit" ng-click="foo1()"></button>
    <button type="submit" ng-click="foo2()"></button>
</form>

and a directive:

angular.module('customSubmit', [])
    .directive('customSubmit', function() {

    return {
        require: '^form',
        scope: {
            submit: '&'
        },
        link: function(scope, element, attrs, form) {
            element.on('submit', function() {
                scope.$apply(function() {
                    form.$submitted = true;
                    if (form.$valid) {
                        return scope.submit();
                    }
                });
            });
        }
    };
});

my goal is to submit the form only when it's valid, with multiple submit buttons (i.e. I can't use the ng-submit directive in the form). The above code doesn't work. What is the correct way to do that? Is that even possible?

Problem courtesy of: Nir Smadar

Solution

The solution was to put the directive on the submit button, and use directive 'require':

<form>
   <button my-form-submit="foo()"></button>
</form>
angular.module('myFormSubmit', [])
    .directive('myFormSubmit', function() {
        return {
            require: '^form',
            scope: {
                callback: '&myFormSubmit'
            },
            link: function(scope, element, attrs, form) {
                element.bind('click', function (e) {
                    if (form.$valid) {
                        scope.callback();
                    }
                });
            }
        };
    });
Solution courtesy of: Nir Smadar

Discussion

I'd suggest you to use one of the simpler way of doing it. Just check your form is valid or not on ng-click & if its valid call the desired method from it.

Markup

<form name="myForm" customSubmit>
    <input type="text" ng-minlength="2">
    <button type="button" ng-click="myForm.$valid && foo1()"></button>
    <button type="button" ng-click="myForm.$valid && foo2()"></button>
</form>

But checking myForm.$valid on each click looks bit repeating code in number of times. Rather than that you could have one method in controller scope which will validate form and call desired method for submitting form.

Markup

<form name="myForm" customSubmit>
    <input type="text" ng-minlength="2">
    <button type="button" ng-click="submit('foo1')"></button>
    <button type="button" ng-click="submit('foo2')"></button>
</form>

Code

$scope.submit = function(methodName){
    if($scope.myForm.$valid){
        $scope[methodName]();
    }
}

In both the cases you could make you button type to button instead of submit

Update

To make it generic you need to put it on each button instead of putting directive on form once.

HTML

<form name="myForm">
  <input type="text" name="test" ng-minlength="2" ng-model="test">
  <button custom-submit type="submit" fire="foo1()">foo1</button>
  <button custom-submit type="submit" fire="foo2()">foo2</button>
</form>

Code

angular.module("app", [])
.controller('Ctrl', Ctrl)
.directive('customSubmit', function() {

  return {
    require: '^form',
    scope: {
      fire: '&'
    },
    link: function(scope, element, attrs, form) {
      element.on('click', function(e) {
        scope.$apply(function() {
          form.$submitted = true;
          if (form.$valid) {
            scope.fire()
          }
        });
      });
    }
  };
});

Plunkr

Discussion courtesy of: Pankaj Parkar

This recipe can be found in it's original form on Stack Over Flow.