I think what I want to achieve is quite simple. Let's have a form with a required field, a select for instance (I've also tried it with an input and it's exactly the same situation anyway).
I want to display the ng-messages only when a button is clicked. If the form field was touched before clicking the button, it works fine. But I cannot do it if the form field is $untouched.
I've solved it setting programatically $touched to the form field, but I'm wondering if there is any way to solve it without this uggly 'hack'.
// Any way to avoid this line??
$scope.myForm.favoriteColor.$setTouched();
//
Code for reference:
HTML:
<md-input-container>
<label>Favorite Color</label>
<md-select name="favoriteColor" ng-model="favoriteColor" required>
<md-option value="red">Red</md-option>
<md-option value="blue">Blue</md-option>
</md-select>
<div class="errors" ng-messages="myForm.favoriteColor.$error" ng-show="validateWithHack">
<div ng-message="required">Required</div>
</div>
</md-input-container>
JS:
$scope.validateWithHack = function() {
if ($scope.myForm.$valid) {
alert('Form is valid.');
} else {
// Any way to avoid this line??
$scope.myForm.favoriteColor.$setTouched();
//
$scope.validateWithHack = true;
}
};
I'm pretty sure that this was working with previous versions of angular-material. Now I'm using the latest 1.1.1.
Here is a plunker where the
problem can be easily reproduced.
Thanks in advance.
Check the CodePen
I have added novalidate to your form and added type="submit" to your md-button
Edit 2:
The type="submit" button actually triggers a form submit and so the angular form validates itself first, What we need to do is to prevent the submit and just do the validation.
novalidate(Just to supress the HTML5 validation) to your form and added type="submit" to your md-button : This Will Validate the form and submit the form, To validate and prevent form submit add ng-click="submitMethod(<yourForm>, $event)" to the <md-button> and define method as
$scope.submitMethod(form,ev){
ev.preventDefault();
//rest of your form work say if you want to do ajax or anything you like
//check if form valid using form.$invalid
}
Related
I have a form with a URL action set. When form.$invalid is true (or form.$valid is false) I want to make the form NOT submit to the URL and show the invalid form errors in the UI.
In my particular case here, I'm using a framework that provides an Angular Controller for me, where I do not have the ability to add/modify functions on it! I need to be able to do this only by making changes to the template.
Here's what I have so far (simplified)
<form novalidate
name="form"
method="post"
ng-attr-action="{{model.loginUrl}}"
ng-submit="return form.$valid">
<div class="form-group" ng-class="{'has-danger' : form.$submitted && form.username.$invalid}">
<input type="text"
name="username"
required
class="form-control"
ng-model="model.username">
<div class="form-control-feedback" ng-if="form.$submitted && form.username.$invalid">
A username is required!
</div>
</div>
<button type="submit">Sign In</button>
</form>
A lot of what I've seen online says to do something like
ng-submit="form.$valid && model.myCustomSubmitFn()"
but that doesn't use a URL form action, and I do not have the ability to add a custom function with this framework
Angular passes the $event in the context of ng-submit. So you call $event.preventDefault(). Your ng-submit would change to
<form novalidate
name="form"
ng-attr-action="{{model.loginUrl}}"
ng-submit="form.$invalid && $event.preventDefault();form.$submitted=true;"
>
See plunker.
THE BELOW IS AN ANSWER THAT WILL NOT WORK FOR THIS QUESTION-- I AM ONLY LEAVING IT HERE SO NO ONE ELSE TRIES THIS AS THE SOLUTION
Might ngDisabled work for you in this case?
<button type="submit" ng-disabled="form.$invalid">Sign In</button>
This is certainly a tricky situation since you only have access to edit the template. I'm not seeing an "angular" way to solve your problem with being able to edit the controller. Luckily though, this can be solved in the template alone with some vanilla JavaScript.
Try adding an onclick event handler to your button that prevents form submission if your form's input(s) do not match your validation criteria.
<button type="submit" onclick="if(form.username.value.length < 1) { event.preventDefault(); }">Sign In</button>
I'm not incredibly proud of this solution and it will certainly get dirty if you have more than one input in your form, however it looks like the only work-around for your unfortunate situation.
Reactive Forms
If you wanted to declair this in the HTML of your reactive form you can simply do something like this:...
<form [formGroup]="formGroupVar" (ngSubmit)="formGroupVar.valid ?
submitFunc() : null" novalidate>...</form>
So what you are doing is making your (ngSubmit) a ternary operator, the comparison would be your formGroupVar.valid, when true, you would execute your submitFunc() else null.
NOTE: There is no reason why you wouldn't just do this in your TypeScript file, it would make sense to keep your HTML as 'clean' as possible, but that doesn't mean it is not possible!
I'm working in AngularJS with a very simple form that only has a textarea input and a submit button. The textarea is a required field. Everything works... until I've submitted the form. When I remove the value from the model after submitting the form, this triggers my validation errors. If I don't set the value to null or an empty string, the textarea retains the entered value, which is not what I want.
<form name="notesForm" class="form-horizontal" ng-submit="vm.addNotesForm(notesForm)" novalidate>
<div control-validator="" validator-condition="vm.hasTriedToSubmit">
<div class="col-sm-10">
<!-- hidden field workaround for validation for textarea -->
<input type="hidden" id="hiddenNewNote" name="hiddenNewNote" required ng-model="vm.newNote.note" />
<textarea id="newNote"
name="newNote"
class="form-control"
placeholder="Note"
ng-disabled="vm.isWorking"
ng-model="vm.newNote.note"
rows="3"></textarea>
<control-validator-message>Note is required.</control-validator-message>
</div>
<div class="col-sm-2">
<button class="btn btn-success" type="submit" ng-disabled="vm.isWorking">
<i class="fa fa-save"></i>
Add Note
<i class="fa fa-circle-o-notch fa-spin" ng-show="vm.isWorking"></i>
</button>
</div>
</div>
Since validation only works for input fields, the hidden field is necessary.
this.notesService.addNote(this.newNote).then(() => {
this.notificationService.success('Successfully added new AR Note');
this.isWorking = false;
this.newNote.note = null; // <- This is where it goes sideways.
this.refreshDataTable();
}, errorMessage => {
this.notificationService.error(errorMessage);
this.isWorking = false;
});
I've tried all sorts of solutions. I used the FormController to set the form to pristine and untouched - no luck. I saw a proposed solution where the controls on the form were programmatically set to 'undefined'. Still no luck. Either the form submits and my value stays there in my textarea, or I set the note to null/empty string, and the validation errors get set off as if I've tried to post without a value in the textarea. As a total hack I even tried using jQuery to set the value of the textarea to an empty string, while keeping the model state undisturbed. While this did appear to work, since the value is still stored in the model, if a user clicks the add button again, it reposts. Not what I need. I'd think this would be a cinch, but after an hour of looking for an answer online, I've come up with nothing that works.
I need to disable the submit button after clicking on the button to prevent multiple submissions but before the it has to ensure that the required fields are filled.
I tried
<body ng-app="ngToggle">
<div ng-controller="AppCtrl">
<form name="newUserForm">
<input type="text" required>
<input type="text" required>
<input type="text">
<button ng-click="disableClick()" ng-disabled="isDisabled"
ng-model="isDisabled">Disable ng-click</button>
</form>
</div>
</body>
angular.module('ngToggle', [])
.controller('AppCtrl',['$scope', function($scope){
$scope.isDisabled = false;
$scope.disableClick = function() {
alert("Clicked!");
$scope.isDisabled = true;
return false;
}
}]);
but this will only disable the button without any validation
Ok, I get what you mean/want so I'll try to help and come up with some code - which is obviously missing but if it wasn't missing the necessary code, you'd have the solution :)
First, you'll have to properly write your form:
<form name="newUserForm" ng-submit="disableClick(newUserForm.$valid)" novalidate>
<input type="text" name="input1" ng-model="form.input1" required>
<input type="text" name="input2" ng-model="form.input2" required>
<input type="text" name="input3" ng-model="form.input3"> //not required
<button type="submit" ng-disabled="isDisabled">Disable ng-click</button>
</form>
so what we've got here, which you're missing:
You did name your form, but you're missing a submit, in the form as ng-submit or the button with type="submit", which will submit the form and that's when the validation happens
In order for Angular to validate your inputs, they need to have ng-model, otherwise it will not validate (HTML5 validation would, but read on)
I've added novalidate so we tell the browser "Hey, we need this validated but not by you, so do nothing", and Angular takes over
And last but not least, Angular adds a couple of properties to the form (see more here: Angular form Docs), $valid being one of them, which is set to true when all validated inputs are valid.
So this sums up the changes you needed to do to your form.
As for the Javascript part, there is just one small change:
$scope.disableClick = function(valid) {
if(valid && !$scope.isDisabled) {
$scope.isDisabled = true;
}
return false;
}
I guess the change is obvious, but I'll explain anyway - check that newUserForm.$valid (boolean) and if it's true (meaning form has passed validation) disable this button.
Of course, you'll have to add checks not to run the code on any type of submits and not just disabling the button (which can easily be re-enabled via Dev Tools), so that's why I added !$scope.isDisabled to the if statement.
Hope this answers your question :)
P.S. Here's a running demo in Plunker
I am dynamically creating form fields using ng-repeat. I have a div with several inputs/selects and when I click an "add" button, they gets duplicated. No problems so far. However, I also want to perform form validation when the submit button is clicked. Right now, I am doing the following to alert users a field is invalid when the submit button is pressed:
.ng-submitted select.ng-invalid, .ng-submitted input.ng-invalid {
background-color: red;
}
This works as expected provided I have not dynamically added inputs to the form. If I add new inputs to the form, .ng-submitted gets added to my form element (without submit being pressed) and all the required and invalid inputs turn red. You can see an example of this here: https://plnkr.co/edit/hDe40mBDjw9aDSDoAhe6?p=preview
Not only do I not want the inputs turning red when simply adding elements, I also don't want the form submitting unless someone has hit the submit button. There must be something I don't understand about submit with angular forms and help would be appreciated.
EDIT: further testing shows that the button element is the problem.
<button ng-click="addRow()">add</button>
This works fine however:
<input type="button" ng-click="addRow()" value="add"/>
Not sure why this is though.
The default value of the type of a button is "submit". So clicking it submits the form. Putting type="button" explicitly prevents the form being submitted when the button is clicked.
If you want to use form submit you need to use ng-submit on form and change button type to submit.
<form name="form" ng-submit="addRow()">
<div>
<div ng-repeat="row in rows track by row.id">
<input type="number" min="0" ng-model="row.id" required/>
</div>
<button type="submit">add</button>
</div>
</form>
There were multiple changes needed in your code. I have fixed them in this plunker: https://plnkr.co/edit/GEWdCo1cQPPEFJcZxT58?p=preview
The main issue I'm trying to solve is closing soft keyboards when a user clicks their keyboard's "go" and submits a search form (see below). If the user clicks the form's submit button, there's no problem because the text field is no longer in focus and the keyboard closes.
I've dug through stackoverflow for answers. I've seen answers that involve creating directives, controllers, and factories to handle this problem. Or say 'wait until 1.1' or whatever when angular has built in focus() and blur() directives (which do not address my problem).
I'm currently using a jquery selector (see below) in the Controller method that is triggered on form submission. Simple, but I feel 'dirty' using it and want a better way that doesn't involve 30 lines of code, which is even more ugly IMO than using a jquery selector.
ng-focus handles attaching behavior to focus events. I'm trying to either blur() away from the text box or set focus somewhere.
<form class="navbar-form navbar-left ng-valid ng-dirty">
<div class="input-group">
<span class="input-group-btn">
<button type="submit" data-ng-click="triggerBigO()" class="btn btn-default btn-primary">Invoke Orgasm</button>
</span>
<input type="text" placeholder="Search" data-ng-model="search.search_term" class="form-control ng-valid ng-dirty">
</div>
</form>
<div id="somewhereElse" grass="greener"></div>
my ugly solution:
PleasureApp.controller("FunTimes", function($scope) {
$scope.triggerBigO = function() {
... do unsavory stuff ...
$("input").blur();
}
}
I think angularish way is to create a directive like this and attach it to the form :
app.directive('blurOnSubmit', function() {
return function(scope, form) {
form.submit(function() {
form.find(":focus").blur();
});
}
});
and in html
<form ... blur-on-submit> ... </form>
It may look a bit overcompilcated but now it is easy to reuse it for other forms as well.
Here is jsfiddle you may try - http://jsfiddle.net/GRaAL/qTWgP/1/