AngularJS - max validation not working on time input - angularjs

I am writing an app with AngularJS 1.5.3.
I have an input form with a time input box.
I need to have validation on the box such that the user cannot pick a time in the future.
Here is a snippet:
<div ng-controller="myController as accvm">
<form name="accvm.addForm" novalidate>
<div class="item item-input" ng-class="{ 'has-error' : accvm.addForm.time.$invalid }">
<span class="input-label">'Time'</span>
<input name="time" type="time" id="timeInput" max="{{ accvm.data.maxTime | date:'HH:mm' }}" ng-model="accvm.data.time" ng-change="accvm.timeChange()" style="text-align: right" required />
</div>
</form>
</div>
For some reason, my validation always fires off and says the value is wrong. I am not sure why this is happening.
Here is my jsfiddle: http://jsfiddle.net/aubz88/j25jwtL2/

To the best of my understanding date inputs are not very good with limiting the input. You can add a min value and then when ever the user adds to the time instead of adding, it will reset to the min value.
I would recommend using something like bootstrap's datepicker that does offer you what you are looking for but in a form of an actual datepicker.
For the documentation https://angular-ui.github.io/bootstrap/#!#datepicker
Which you can use the maxDate property to set max date...
Also from the definition in w3schools max and min don't work in certain browsers "The max attribute will not work for dates and time in Internet Explorer 10+ or Firefox, since IE 10+ and Firefox does not support these input types."
https://www.w3schools.com/tags/att_input_max.asp

I got it to work by using 1970 instead of the current year, the max value worked.
var time = new Date(
1970, //today.getFullYear(),
0, //today.getMonth(),
1, //today.getDate(),
today.getHours(),
today.getMinutes(),
0,
0
);

Related

How to keep form error message blank on initial load in AngularJS

I'm trying to learn forms in AngularJS 1.x. But I have error messages that are always on when it first loads. How to develop behaviour such that they are blank on load, and only red after a submit if fields were not entered? Seems to be a few states I have to use the built-in directives for.
All the elements are similar so let's just take apart this bit. Also if different for a radio and dropdown list maybe we can discuss that too.
<p>First Name:<input type="text" id="firstName" ng-model="firstName" required/>
<span style="background-color: red" ng-if="identification.firstName.$error.required">The first name is required.</span>
</p>
Do I chain a few directives with || or && ?
Behaviour I'm aiming for
How to keep the error messages off when it loads?
when I hit submit, and a field is blank, will it then activate the css red error messages?
I'd like the error messages to clear as I fill in the form without reloading.
Yeah, so any tips greatly appreciated. Doesn't have to be particularly pretty
Thanks
UPDATE 1
gist of current code
Well I took a stab at it. Still really a hot mess at this point. Don't know how to use submit to test for each field and then display the error message if blank. Also seems like a lot of duplication on the testing of field states. Is there a better way to break up that logic? Ugggghhhhh
UPDATE 2
This one's weird, the form now has all text boxes not buttons or checkboxes!? But the HTML hasn't changed. Sigh
ng-if="identification.firstName.$error.required && !$pristine"
Go search more on $pristine and $dirty validator
You can add some other property to your ng-if and set its value to true only when form is submitted.
in your html add this new property
<p>First Name:<input type="text" id="firstName" ng-model="firstName" required/>
<span style="background-color: red" ng-if="identification.firstName.$error.required && running">The first name is required.</span>
</p>
in your controller set this property to true when form is submitted
$scope.submit = function(){
$scope.running = true;
...
}

Show the slots as Today and Tomorrow for E-commerce based on client current time

I am getting an array as from factories, service in controller.
$scope.getallslots=SlotService.getslots();
In this array i am having data as.
Now I want to compare the current time and existing time from the array. And based on the time i want to show my data.
I have converted the current time to ISO string format as per database but, i want to check only time but not date. Any help, will helpful.
Guys I got the answer.
Convert the date in time format at admin side and store only time in the
MongoDB using the timepicker or date.
Now take two different ng-model and check the condition as per need
Later get that date at client side and check with the current time format.
after checkin push those value one by one in the ng-model which is array.
Now it's done. Here is example, Its at server side,
$scope.Delivary.from=$filter("date")($scope.Delivary.from,'shortTime')
$scope.Delivary.to=$filter("date")($scope.Delivary.to,'shortTime')
The above code should be written before pushing/saving the slots at admin panel
Here is example, Its at client side
$scope.slotupdatedlist=[]-->1st ng-model
$scope.slotupdatedlist1=[]-->2nd ng-model
$scope.gettime=CartListService.getslots().$promise.then(function(data){
angular.forEach(data,function(list){
console.log(list)
var currtime=new Date();
$scope.HHmmss = $filter('date')(new Date(), 'HH:mm');
if(((list.from<$scope.HHmmss) && (list.to>$scope.HHmmss))||((list.to<$scope.HHmmss))){//checking condition
$scope.slotupdatedlist1.push(list);
}
else{
$scope.slotupdatedlist.push(list);
console.log($scope.HHmmss)
}
})
})
Now assign those ng-model in your HTML page and you can get the Slots
<h4>Available Slots</h4>
<span>Today</span><br>
<label class="checkbox-entry radio" ng-repeat="slot in slotupdatedlist">
<input type="radio" name="custom-name"><span class="check"></span>
{{slot.from}} -- {{slot.to}}<br>
</label>
<span>Tomorrow</span><br>
<label class="checkbox-entry radio" ng-repeat="slot in slotupdatedlist1">
<input type="radio" name="custom-name"><span class="check"></span>
{{slot.from}} -- {{slot.to}}<br>
</label>

AngularJS validation using ng-messages without a form control

I store time as an integer of minutes in the database/model. However, I want to display it to the user in decimal hours (and let them edit the value using a number of buttons).
At the moment I have this:
<p class="input-group">
<input type="text" readonly="readonly" value="{{vm.time.minutes|hoursMinutes}}" class="form-control" />
<span class="input-group-btn">
<ix-time-picker minutes="vm.time.minutes"></ix-time-picker>
</span>
</p>
Of the 2 elements in the p tag:
The input type="text" works fine as the display mechanism. The hoursMinutes filter returns a formatted value, e.g. for 90 mins it will return '1 hour 30 mins'.
The ix-time-picker directive pops up a modal window with buttons such as 15 mins, 30 mins, 45 mins, 1 hour, 1:15 hours, etc.
This works fine - except for validation. I'm using ng-messages and I can't work out how to display the validation for the required state:
<li class="help-block has-error"
ng-if="mainForm.$submitted"
ng-messages="mainForm.minutes.$error">
<span ng-message="required">
Minutes is required.
</span>
</li>
I don't have a control on the form called minutes (at least with an ng-model) so it won't display the message. I could add a hidden input with ng-model="vm.times.minutes" but as I need to use this repeatedly through the application, I'd prefer not to do that. Or at least I'd like to build some kind of common directive that merges the ability to have an ng-model on a control with the ability to display a value that is different to the model value, if that's possible.
Any suggestions?
Aha - one option is to make the input a label:
<p class="input-group">
<label id="minutes" name="minutes" readonly="readonly" class="form-control">{{vm.time.minutes|hoursMinutes}}</label>
<span class="input-group-btn">
<ix-time-picker minutes="vm.time.minutes"></ix-time-picker>
</span>
</p>
Then it displays correctly and it validates.

angularjs ng-show messes up form validation

I have an angularjs view with the following input field that is dependent on what organization the user is from..
<div class="form-group" ng-class="{'has-error': isDirtyAndInvalid(provisionVMForm.vmHostPrefix)}">
<label class="col-sm-2 control-label" for="vmHostPrefix">Host Prefix*</label>
<div class="col-sm-8">
<div ng-show="$root.sessionObj.org.name=='orgName1'>
<input id="vmHostPrefix" name="vmHostPrefix" class="form-control" type="text"
required="true"
ng-maxlength="12"
ng-minlength="12"
placeholder="Host Prefix"
ng-blur="setdirtyFromFocus(provisionVMForm.vmHostPrefix)"
ng-model="vmHostnamePrefix"/>
<div class="pull-left alert alert-danger form-validation-alert" role="alert"
ng-show="provisionVMForm.vmHostPrefix.$error.minlength ||
provisionVMForm.vmHostPrefix.$error.maxlength>
Host Prefix must be 12 characters long.
</div>
</div>
<div ng-show="$root.sessionObj.org.name=='orgName2'>
<input id="vmHostPrefix" name="vmHostPrefix" class="form-control" type="text"
required="true"
ng-maxlength="4"
ng-minlength="4"
placeholder="Host Prefix"
ng-blur="setdirtyFromFocus(provisionVMForm.vmHostPrefix)"
ng-model="vmHostnamePrefix"/>
<div class="pull-left alert alert-danger form-validation-alert" role="alert"
ng-show="provisionVMForm.vmHostPrefix.$error.minlength ||
provisionVMForm.vmHostPrefix.$error.maxlength>
Host Prefix must be 4 characters long.
</div>
</div>
</div>
</div>
What I need to do is identify what organization the user is currently in, and dependent the org, the hostname prefix input field can only be a certain length. Now, this works perfectly fine when I have just the first ng-show in my code. It correctly identifies the org name and the form complains if the input is less than or more than 12 characters. Whenever I add my second ng-show to identify my second organization.. my first organization form validation for org # 1 is not correct. The form only complains if the input IS 12 characters. I need it to be the opposite. Any ideas what I'm doing wrong by adding this second ng-show? I tried using ng-if when trying to identifiy the organization and that worked fine with the form validation.. but that resolves my vmHostPrefix variable to undefined in my controller. Any help is appreciated!
ng-show hides the element with display: none, while ng-if will remove the element from the DOM. I think what you have here is a bug caused by having 2 elements with ng-model pointing to the same variable.
Why not do this without repeating so much code and instead try using an expression in ng-minlength.
ng-minlength="$root.sessionObj.org.name==='orgName1' ? 12 : 4"
Or even better have ui state rules for the org
ng-minlength="$root.sessionObj.org.minlength"
ng-maxlength="$root.sessionObj.org.maxlength"
I believed they fixed expression evaluations for ng-min max in 1.3

Angular-formly custom Validation on multiple fields on a repeat section

I was trying to create a custom validator for angular-formly repeated section.
The form should be valid only if the sum of the percentage inputs is 100. So for example if repeat section has 2 fields 50 and 50 should be a valid option or 25 and 75 and so on.
While I was working on a JSbin in order to do that I found out that the repeated model is not actually updated onKeydown. Therefore iterating though all the repeat section values and calculating their sum is not possible.
I also tried with modelOptions: { updateOn: 'Keydown' } with no success. It actually makes the validator not to get called at all.
UPDATE
I came up with the following solution from the matching fields example.
Unfortunately it appears that the example its self has a problem.
Play with the following JSbin and see that there are many cases where the validator gets called and returns true but the field/fields still remain red (indicating they have a problem).
Here is the JSBin.
Apologies since I didn't had the time to get back on this one. It has an open issue on GitHub for 2 months now. I fixed it temporary by using 7.1.2 version of angular-formly and just waiting for an update. The updated version of JSBin I have on the question should be working.
UPDATE
Since I had time and fixed this with repeat section (with a hacky way of course) I tough I should post it in case someone else is looking for this.
(note: the solution doesn't depend on formly version)
Working JSBin
You made a typo while using modelOptions: { updateOn: 'Keydown' } the Keydown's k should be small case instead of uppercase, after fixing typo its working as expected. Also the ngModelOptions accept all event name in small case like keydown, keyup, blur, focus, etc.
modelOptions: { updateOn: 'keydown' }
Forked Plunkr
To create your own checks is best used reusable components, for example directive use-form-error.
Look at the example of jsfiddle.
<div ng-form="testForm" use-form-error="sumNot100" use-error-expression="input_1+input_2+input_3!=100">
<label>Sum of all input must be 100</label>
<br>
<label>Input 1</label>
<input ng-model="input_1" type="number" name="input_1">
<label>Input 2</label>
<input ng-model="input_2" type="number" name="input_2">
<label>Input 3</label>
<input ng-model="input_3" type="number" name="input_3">
<div ng-messages="testForm.$error" class="errors">
<div ng-message="sumNot100">
Sum of all input not equal 100
</div>
</div>
<button ng-disabled="testForm.$invalid">
Submit
</button>
</div>

Resources