AngularJS validation using ng-messages without a form control - angularjs

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.

Related

AngularJS - max validation not working on time input

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
);

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

How do I get the number input to show up as a 2-digit number?

I'm trying to let users pick an hour and minute combination in my HTML form. But I would like them to always show up as 2-digit values, not 1-digit, so that (for example) 9:05 AM comes up as 09 and 05 instead of just 9 and 5.
I haven't found any attributes that deal specifically with this problem. I have found a pattern attribute, but it doesn't seem to do anything on Firefox 38 or Chromium 34, and the same goes for setting the minlength attribute to 2 (which I guess was only meant for strings, but I gave it a shot).
I do understand that the pattern I've tried in this example, [0-9]{2}, would only limit (a string) to 2 digits if it container more than 2 digits. Which is why I tried setting the value of my input field to 100 to test if the pattern attribute even works, but as I said, it made no change unfortunately. Maybe the pattern also only works for strings.
And since the type of the input element is number, Angularjs doesn't let me write 05 as a string in there. So I guess the solution should probably be through HTML5 attributes.
So, how would I get the values to show up as 2-digit numbers?
My form looks like this:
<fieldset>
<div class="row">
<div class="col-xs-6 text-center">
<h4>Hour</h4>
<input type="number"
max="23"
min="00"
step="1"
minlength="2"
pattern="[0-9]{2}"
class="form-control dialog-control"
ng-model="hour"/>
</div>
<div class="col-xs-6 text-center">
<h4>Minute</h4>
<input type="number"
max="59"
min="00"
minlength="2"
step="1"
pattern="[0-9]{2}"
class="form-control dialog-control"
ng-model="minute"/>
</div>
</div>
</fieldset>

angular ui bootstrap datepicker causes "infdig"

I'm trying to apply the datepicker from angular ui in my application but for some reason it results in the following error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.3.15/$rootScope/infdig?p0=10&p1=%5B%5D
I don't understand why this error is triggered because. In the link above the description reads:
This error occurs when the application's model becomes unstable and
each $digest cycle triggers a state change and subsequent $digest
cycle. Angular detects this situation and prevents an infinite loop
from causing the browser to become unresponsive.
I don't see how this is applicable to my situation at all.
If I'm using a regular input field like this:
<input type="text" class="form-control" id="my-date" name="myDate" data-ng-model="ctrl.myDate"
data-ng-model-options="{updateOn: 'blur'}" data-ng-change="ctrl.changeDetected()" >
There's no problem and the date is displayed just fine, but this:
<p class="input-group">
<input type="text" class="form-control" datetime-picker="'yyyy-MM-dd'" data-ng-model="ctrl.myDate" data-is-open="ctrl.isOpen" data-enable-time="false" data-show-button-bar="false" data-timepicker-options="ctrl.dateOptions" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" data-ng-click="ctrl.openCalendar($event, date)"><i class="fa fa-calendar"></i></button>
</span>
</p>
will result in the error. Can someone smarter than me give me a pointer as to what it is that I'm missing. I'm just loading the date from the backend and trying to display it as the current date in a datepicker.
/Regards Kris
Sorry, apparently I'm a dumbass. there's nothing wrong with the datepicker and the code above. I had missed that the surrounding div was using a validation directive that was bound to the name attribut of the input field and I forgot to add this name attribut to the corresponding datepicker input field.

How can I mimic the tags box behaviour from SO in AngularJS?

How can I mimic the tags box behaviour from SO in AngularJS? I'm trying to do something kind of similar where the user enters a set of space/comma-delimited words and as each one is typed I want to parse it out and put it into an array. I know there are probably 30 different ways to do this with bespoke javascript but I'm looking to leverage AngularJS in the most efficient way possible here.
At the moment I have an ng-model based on the input field and I'm doing an ng-repeat to create spans containing each tag, but angular uses commas as the delimiter and it also includes partially-formed words. So I only want to include words that have been delimited by the space/comma and I want to put them into an array so I can perform some validation on each one as it's entered, see below.
<form role="form" class="form-inline" data-ng-submit="updateScore()">
<input data-ng-list data-ng-model="labels" placeholder="Enter labels" class="form-control" type="text" >
</form>
<span data-ng-repeat="label in labels track by $index">
<span class="badge">
{{ label }} 5 <span class="glyphicon glyphicon-remove-sign"></span>
</span>
</span>
Any ideas?
Figured it out actually...
<input data-ng-list="/[,\s]/" data-ng-model="labels" placeholder="Enter labels" class="form-control" type="text" >

Resources