How to manually trigger AngularJS validation from a button outside of the form tags?


Given this code:

<div ng-controller="MyCtrl">
    <form ng-submit="onSubmitted()">

    Header inputs:
        <input type="name" ng-model="sample" required/>
        <input type="name" ng-model="sampleX" required/>

        <input type="submit" value="This submit triggers validation. But I wanted to put this button at the end of the page"/>
    </form>

    <hr/>

    Some other form here. Think line items

    <hr />
    <a class="btn" ng-click="/* what could should be put here, so this can trigger the firt form's validation, then submit? */">Wanted this submit button to trigger the validation+submit on the form in which this button doesn't belong</a>


</div>


var app = angular.module('myApp', []);

function MyCtrl($scope) {

    $scope.onSubmitted = function() {
        alert('submitted!');
    };
}

I want the last button to trigger the validation(then submit when things are valid) on first form. As of now, only the button inside the form can trigger that form's validation and submission. Is there any possible way for a button outside the form to do that?

Live test: http://jsfiddle.net/dzjV4/1/

You can create directive which you can then attach to <a class="btn".... Check this jsfiddle

http://jsfiddle.net/dzjV4/2/

Note that I added to <input type='submit' id='clickMe'... and linked it with link at the bottom <a class='btn' linked="clickMe"...


Ideally there'd be a programmatic way to cause validation to re-run across a form. I have not investigated that completely but had a situation that required multiple controls to be re-validated based on different data in the scope -- without the user interacting with the individual controls. This arose because the form had two action buttons which each required different validation rules be in play when they were clicked.

The UI requirement changed before I fully implemented forcing re-validation but before it did I got most of what I needed by copying and then re-setting the form's data. This forced re-validation across the form within the current scope. Basically, it's along the lines of the following (not tested, but taken from the code that was working). In this case the form's data was bound to the properties in one object.

var formData = $parse(<form's model>); 
var dataCopy = angular.copy( formData($scope) ); 
formData.assign( $scope, dataCopy );

This may or may not be acceptable, but if you can get away with the SUBMIT button being disabled until the form is completed, you can do this:

<form name="formName">
 <input ng-required="true" />
</form>
<button ng-click="someFunction()" ng-disabled="formName.$invalid" />

It's also worth noting that this works in IE9 (if you're worried about that).


    for (control of $scope.[form name].$$controls) {
        control.$setDirty();
        control.$validate();
    }

You can try the above codes. Make it running before submit.


Give your form a name:

<div ng-controller="MyCtrl">
    <form name="myForm">
        <input name="myInput" />
    </form>
</div>

So you can access your form validation status on your scope.

app.controller('MyCtrl', function($scope) {
    $scope.myForm.$valid // form valid or not
    $scope.myForm.myInput // input valid or not
    // do something with myForm, e.g. display a message manually
})

angular doc

There is no way to trigger browser form behavior outside of a form. You have to do this manually.


Since my form fields only show validation messages if a field is invalid, and has been touched by the user:

<!-- form field -->
<div class="form-group" ng-class="{ 'has-error': rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched && rfi.rfiForm.stepTwo.Parent_Suffix__c.$invalid }">

    <!-- field label -->
    <label class="control-label">Suffix</label>
    <!-- end field label -->
    <!-- field input -->
    <select name="Parent_Suffix__c" class="form-control"
        ng-options="item.value as item.label for item in rfi.contact.Parent_Suffixes"
        ng-model="rfi.contact.Parent_Suffix__c" />
    <!-- end field input -->
    <!-- field help -->
    <span class="help-block" ng-messages="rfi.rfiForm.stepTwo.Parent_Suffix__c.$error" ng-show="rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched">
        <span ng-message="required">this field is required</span>
    </span>  
    <!-- end field help -->
</div>
<!-- end form field -->

I was able to use this code triggered by a button to show my invalid fields:

// Show/trigger any validation errors for this step
angular.forEach(vm.rfiForm.stepTwo.$error, function(error) {
    angular.forEach(error, function(field) {
        field.$setTouched();
    });
});
// Prevent user from going to next step if current step is invalid
if (!vm.rfiForm.stepTwo.$valid) {
    isValid = false;
}