AngularJs and HTML5 required fields setting fields to empty fires validation - html

I'm trying to write a small Angular app with the following functionality:
Form starts empty with placeholder text.
User enters item in required textbox.
Angular pushes item to collection.
Reset form inputs to default.
I've got code that looks like this (jsfiddle: http://jsfiddle.net/Nn37v/1/) :
HTML:
<div ng-controller="MyCtrl">
<form name="talkForm">
<input ng-model="newVoice" placeholder="Say something" required />
<button ng-click="saySomething()">Say</button>
</form>
<ul>
<li ng-repeat="c in conversation">{{c}}</li>
</ul>
</div>
Javascript:
function MyCtrl($scope) {
$scope.conversation =[];
$scope.saySomething = function(){
if ($scope.talkForm.$valid){
//push to list
$scope.conversation.push($scope.newVoice);
$scope.newVoice='';
}
}
}
The problem I'm facing is when $scope.newVoice='' executes, the form is rendered invalid and I get the helpful HTML5 validation pop up to encourage me to fill in the form properly. Obviously this is not the behaviour I want - what is the correct way to do this with Angular?

To remove the HTML5 validation (since it will only work on compliant browsers) why not add the novalidate attribute to the form?
The validity of the form will still be invalid due to the 'required' attributed.

Seems that the following pull request in 1.1.x branch of Angular will add a $setPristine method to allow this to happen
https://github.com/angular/angular.js/pull/1127

Related

React build own components

Sometimes I need some special UI component e.g multiple range slider, but I don't like using third party libraries, so usually I create component on my own. Over time I absolute stop using form tag, instead of that, I use just div and instead of onSubmit use just onClick, which call function, which return data from redux (also use my own redux form implementation). For example:
<div>
<div className="form-title">Some random Form</div>
<div className="form-body">
<Input
type="text"
label="Name: *"
form="random_form"
name="name"
/>
</div>
<div className="form-footer">
<Button onClick={()=> handleSubmit()}>Save</Button>
</div>
</div>
const handleSubmit = () => {
const form = getForm("random_form")
}
In this case I use component Input, which return normal html input (). But now I thinking that i will create some other pseudo form component, which will be build from some span and div. And my question - Is okay, when I don't use form tag and create own form component, which haven't default html equivalent.
Because of accessibility issues, it's generally preferable to have a form tag if you're making a form, but as other people mentioned, it's not required.
You do lose some functionality if you don't have a form tag. For example, if you had an input with required, it would get validated when the form is submitted, but since there is no form, it's not validated automatically. One of the more subtle issues I've encountered is that browsers might not save your input for autocompletion if no submit event happens.

How does angularjs detect $dirty when no form tag is used?

I am using $window.addEventListener('beforeunload'... to detect whether changes have been made to a page, and it is working mostly as expected. I'm also using $transitions.onStart... to detect when the back/forward browser buttons are used. What I don't understand is how this is working, because my HTML template does not have any form tags in it, just inputs inside divs.
I have done research on this and cannot seem to find an answer, other than it is not necessary to use form tags in order to check the dirtiness of inputs. I'm just not sure how this is actually working in the background.
<div class="modal-header bg-primary">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title pull-left">New Note</h4>
<div class="clearfix"></div>
</div>
<div class="modal-body">
<input type="textfield" ng-model="detailVM.newNoteContent">
<button ng-click="detailVM.addNewNote()">
Save New Note <span class="fa fa-check"></span>
</button>
</div>
Here is my HTML code.
// For page reloads and attempts to leave the site
$window.addEventListener('beforeunload', function (e) {
// Cancel the event
e.preventDefault();
// Chrome requires returnValue to be set
e.returnValue = '';
});
// For when a user hits the back button
$transitions.onStart({}, function ($transition)
{
var answer = confirm("Are you sure you want to leave this page? Changes you made may not be saved.")
if (!answer) {
$transition.abort();
return false;
}
return true;
});
And here is what I have in the controller.
When I enter data into the inputs and then attempt to reload, close, or click the back button, these show the message, "Are you sure you want to leave this page?" But how is it detecting that the inputs are dirty?
ng-model doesn't need to be in a form for it's validators to work.
From the AngularJS docs:
The ngModel directive binds an input,select, textarea (or custom form
control) to a property on the scope using NgModelController, which is
created and exposed by this directive.
ngModel is responsible for:
Binding the view into the model, which other directives such as input,
textarea or select require.
Providing validation behavior (i.e.
required, number, email, url).
Keeping the state of the control
(valid/invalid, dirty/pristine, touched/untouched, validation errors).
Setting related css classes on the element (ng-valid, ng-invalid,
ng-dirty, ng-pristine, ng-touched, ng-untouched, ng-empty,
ng-not-empty) including animations.
Registering the control with its
parent form.
— AngularJS ng-model Directive API Reference
If the form is present, ngModelController will register it's controls to the form. This gives you a nice container for tracking the state of an entire set of inputs/controls.

Form Validation in Bootstrap Tabs (AngularJS)

Some context:
AngularJS 1.4
Bootstrap 3.3.7
I'm using Bootstrap tabs navigation and panels inside a form.
Inside each panel I have an input that is required.
The default validation is not able to focus (change the active tab) and show the error message after the validation.
(console.log):
An invalid form control with name='' is not focusable.
A lot of "solutions" mention to remove the required attribute (from the hidden inputs) but that is not what I want because I need to have all inputs validated.
I tried to use ngModel validators but I'm not sure if it's a valid path for what I need.
What I'm trying to achieve is to be able to check the input's value and if invalid show it's tab, upon form submit.
Thank you.
[Solution found!]
Controller:
$scope.tabsValidation = form => {
let first = jQuery(`form[name="${form.$name}"] input.ng-invalid`).closest('.tab-pane');
let firstID = first.attr('id');
jQuery('.nav a[data-target="#' + firstID + '"]').tab('show');
};
View (form):
<button class="btn" type="submit" ng-click="tabsValidation(formName)">
Submit
</button>
From what I understand, the ng-click its executed before the actual form submit/validation.

Angularjs and populating fields/placeholder blinking

I do know that Angularjs populates fields via their model.
Html loads first:
<input type="text" data-ng-model="values.myValue" placeholder="trololol">
Then the JavaScript:
$scope.values = {};
$scope.values.myValue = 'herro my value';
This works, but there is a blink second where the placeholder displays then updates with the value 'herro my value'.
I'm wondering if there is a way I can put the value straight into the html without screwing up the angularjs model? For example.
<input type="text" value="herro my value" data-ng-model="values.myValue" placeholder="trololol">
Then when the JavaScript loads, the model takes over. Is this a safe way of getting rid of this blink on page load?
The ng-cloak attribute should prevent this:
https://docs.angularjs.org/api/ng/directive/ngCloak
You could add a display: none; on your body tag and adding a run block to angular:
angular.module('myApp', ['ngRoute'])
.run(function() {
document.body.style.display = "block"
});
The difference is now that the user is getting a blank screen now until angular is loaded.
Run block example: https://www.ng-book.com/p/Angular-Module-Loading/#run-blocks

How to programmatically display HTML5 client-side validation error bubbles?

I'm trying to use HTML5 client-side validation outside a form/submit context, but cannot see how to display the validation error bubbles. Consider the following:
<input type="text" id="input" pattern="[0-9]" required oninvalid="alert('yes, invalid')">
<button onclick="alert(document.getElementById('input').checkValidity())">Check</button>
Everything works as expected, with the correct value being returned from checkValidity, and the invalid event being sent and displayed, but how do I programmatically display the validation error bubble?
If you're talking about this bubble:
See ScottR's comment to this answer instead.
...then my testing shows that both Firefox and Chrome display it when calling checkValidity on an element wrapped in a <form> (testcase), but not on a standalone element (testcase).
There doesn't seem to be a mechanism to display it when there's no form, and the spec doesn't even say it has to be displayed in response to programmatic checkValidity calls (on the element or the form) -- only when submitting a form.
So for now, wrap your elements in a form, even if you will not actually submit it.
Better yet, use your own validation UI, this will shield you from future changes in the browsers in this underspecified area.
Try using required="required" and getting rid of the oninvalid handler unless you really need it.
http://blog.mozilla.com/webdev/2011/03/14/html5-form-validation-on-sumo/
Example of this working: https://support.mozilla.com/en-US/users/register
Just set manually "invalid" attribute to incorrect fields.
Small example:
var form = $('#myForm').get(0);
if(typeof formItem.checkValidity != 'undefined' && !formItem.checkValidity()) {
$('input:required').each(function(cnt, item) {
if(!$(item).val()) {
$(item).attr('invalid', 'invalid');
}
});
return false;
}