There's one field in the form which has strict format (validator is already in place).
How to make form submit automatically in AngularJS as soon as it becomes valid?
I am assuming you are talking about ajax post of form data (model data).
You can do a $watch on the $valid property of a form field and submit the form as soon as it becomes true.
See my fiddle here
Something like
$scope.$watch('myForm.userName.$valid',function(newValue,oldvalue) {
if(newValue) {
alert('Model is valid');
//Can do a ajax model submit.
}
});
You can get mode details from the form directive documentation
Related
I am using angular-schema-form, and ran into a problem that when I load a schema and a form from a server using REST, the validation sometimes did not kick in. I could post a schema even though some fields were required.
How can I always be sure that the required fields in the form has to be filled in by the user before posting?
I found that using $scope.$broadcast('schemaFormValidate'); before submitting the form works (from the docs).
$scope.onSubmit = function(form) {
// First we broadcast an event so all fields validate themselves
$scope.$broadcast('schemaFormValidate');
// Then we check if the form is valid
if (form.$valid) {
// ... do whatever you need to do with your data.
}
}
However, we can not disable any buttons beforehand.
#John you can set a value in your model that is part of a display condition. That allows you to hide the buttons on submit and then re-enable them when you are ready for the user to submit the form again for any reason.
After submitting the form, the pristine state of the input is still "false". I don't know how to reset the pristine state to be true. In Angular 1, I would use the $setPristine function.
I looked at the API and developer guide. There is no API to reset input to pristine.
Instead developer guide on forms (section "Add a hero and reset the form"), shows a mechanism to reset form to pristine by adding a active flag on the component. And then binding it on form tag with ngIf
active = true;
newHero() {
this.model = new Hero(42, '', '');
this.active = false;
setTimeout(()=> this.active=true, 0);
}
and
<form *ngIf="active">
This regenerates the form, setting its controls back to pristine.
There is a pull request waiting to be added https://github.com/angular/angular/pull/6679
See also this related issue https://github.com/angular/angular/issues/4933
The usually used workaround is to recreate the form.
I have a login form that has a username and password. Both are required to trigger other form elements.
However, in chrome if the password is saved, form.$invalid returns true and the digest doesn't re-run when the saved information gets added. Is there any way to require fields being saved and set by the browser and have angular re-check form.$valid?
Surprisingly, I was facing a similar problem some time back. The trick is to get the browser to fire input events for things that may have been filled in by chrome autofill (but haven't updated).
If you have a submit or click handler for the form submission, you can trigger the input event on all your inputs so that angular will pick up the changes by autofill.
You may do something like this
var app = angular.module('app',[]);
app.run(function() {
// Trigger input event on change to fix auto-complete
$('input, select').on('change',function() { $(this).trigger('input'); });
});
to fire input event on all inputs.
Here's the original github issue related to your problem.
I have a form where my intent is for required fields to not always be enforced. For example if the user is saving the document as a draft they can enter as little information as they like, if they try and publish the document then they have to enter all the required fields. I'm using a boolean on the controller which changes according to which button has been pressed e.g.
<input type="text" ng-model="field2" ng-required="enforceRequired" />
The problem is that the fields are not re-evaluated when the boolean changes so the form is submitted and then it becomes invalid. Please see this JSFiddle to see what I mean. If you fill in field1 and then click publish it will succeed on the first click and THEN become invalid.
How can I force the validation to run before the form is submitted?
Yarons is right, you are changing the value too late, by late I mean after the form validations has been run. What you can do as a workaround is, after changing the required value, let angular do another cycle and then show your alert. This can be done via $timeout service, although I must mention that it is usually not a good practise to change the flow of your digest actions. It gets pretty messy pretty soon.
Change your publish function like this (and don't forget to inject $timeout)
$scope.publish = function () {
$scope.enforceRequired = true;
$timeout(function () {
if ($scope.form.$valid) {
alert("Published!");
}
});
};
Working fiddle: http://jsfiddle.net/bh9q00Le/14/
The problem is that you are changing the value of enforceRequired in the middle of the digest loop, so the watchers are not re-rendered before you check the input fields' validity (read about digest here).
If you want to get around it, I suggest one of the following methods:
change the value of enforceRequired before you call saveDraft or publish. see example.
call $scope.$apply() after you change the value of enforceRequired. see another example.
I understand one of the key principals of Angular is:
Thou shalt not reference thy DOM from withinst thou's controllers.
I'm trying to process a credit card payment, which requires the following steps:
User fills out a form, and clicks a submit button
A portion of that form is sent to our servers, which starts a transaction with the payment gateway
The response from our servers updates values in the form, which must then be submitted directly to the payment gateway, via a form POST.
Other stuff happens.
In this scenario, how do I:
Update the data in the form (without referencing the form from the controller)
Get the form to submit?
The form binds to a model on my controller, so I've tried something like the following:
<form action="{{paymentModel.urlFromTheResponse}}">
<input type="hidden" name="accessCode" value="{{paymentModelaccessCodeFromResponse}}" />
<button ng-click="startTransaction(paymentModel)"></button>
</form>
// in my success handler
.success(function(data) {
paymentModel.urlFromTheResponse = data.url;
paymentModel.accessCode = data.accessCode;
$scope.apply();
}
the theory being here that if I can immediately get the form into the correct state via databinding, I can then do something to submit the form. However, this throws an error:
Digest already in progress
What's the Angular way to support this type of flow? It seems I'm required to interact directly with the DOM, which goes against the nature of controllers.
As others have stated, you shouldn't need to call $scope.$apply() because the form should already be tied to angular by setting ng-model attributes on each of the fields.
However, occasionally it is necessary to call $scope.$apply() to update display when data is pulled in from some other source outside of angular...
In those cases, I've had great luck with this:
// This method will be inherited by all other controllers
// It should be used any time that $scope.$apply() would
// otherwise be used.
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
I place that in my outermost controller, so all other controllers on the page inherit the function from it.. Any time I find I need a call to apply, I instead call $scope.safeApply() which will call apply if there is not already an apply or digest in progress, otherwise, those changes will already be picked up by the currently running apply/digest.
In your code I would change this:
<input type="hidden" name="accessCode" value="{{paymentModelaccessCodeFromResponse}}" />
To this:
<input type="hidden" name="accessCode" ng-model="paymentModel.accessCode" />
I would probably also remove the form action, and instead add something like this in the controller:
$scope.$watch('paymentModel.accessCode', function() {
// Fire off additional form submission here.
})
The error is generated because your success callback is already "inside Angular", so $scope.apply() will be called automatically for you.
If you use ng-model (instead of value) on your form elements, then you can modify the model/$scope properties in your success callback and the form will automatically update (due to two-way databinding via ng-model). However, instead of trying to submit the form, why not just use the $http or $resource service inside your controller to call the web service? (That's why I asked if the user needed to be involved in my comment.)
Assuming you are using something like $http, you are already inside of the angular scope and should not need to manually call $scope.apply(); as you are inside of the angular execution already.
You should be able to ditch the $scope.apply() and simply have an
.success(function(data) {
paymentModel.urlFromTheResponse = data.url;
paymentModel.accessCode = data.accessCode;
$http.post("/finalstep",paymentModel).success(function(data)
{
// other stuff
});
}