Simple angularjs date input - angularjs

I have an edit page for an event and one of my fields is a date. In some browsers it seems to act like a plain text box (IE8), however in chrome it displays "dd/mm/yyyy" and if you click on it it has some additional options for setting the date.
My issue though is on the edit page it's not populating the existing date (I imagine because it's not in the correct format?). The MVC controller returns the data in this format "2014-03-08T00:00:00" (just using basic CRUD controller actions).
<form name="form" class="form-horizontal">
<div class="control-group" ng-class="{error: form.EventDate.$invalid}">
<label class="control-label" for="EventDate">Event Date</label>
<div class="controls">
<input type="date" ng-model="item.EventDate" id="EventDate">
</div>
</div>
<div class="form-actions">
<button ng-click="save()" class="btn btn-primary">
{{action}}
</button>
Cancel
</div>
</form>
I've seen quite a few posts on using directives and watches, but that seems complicated. I would have thought there would have been a relatively simple way of formatting the model data so that it displays in the right format and works as expected. I don't mind if Chrome gives a different experience than other browsers - it's just a simple internal user website. I just don't like that it's not prepopulating the date when I edit a record.

If you want to populate the field with an initial value, then the following will work
//Controller:
$scope.myDate = new Date('2014-03-08T00:00:00');
//HTML:
<input type="date" ng-init="model=(myDate | date:'yyyy-MM-dd')" ng-model="model" />
However, I strongly recommend creating a custom date field directive.
A custom input field directive offers the following benefits:
Two-way binding between the model and the view.
For example, when you enter a valid date in the input field, it will automatically assign a javascript date to the model; and when you assign a valid javascript date as the model, it will automatically format it in the text field.
Form validation support. When you enter an invalid date, you can set an $error flag, which can be used in your view bindings (i.e. displaying an error message). Setting an error flag will also set form.$valid to false so that you can conditionally submit the form to the server.
There are three basic things to consider when implementing a custom date directive:
A parser that will parse the input text and return the model
(in this case, a javascript date).
A formatter that will format the model and display it in the text field.
Setting of an optional validation flag which can be used in the UI
for custom form validation.
Date Directive:
myApp.directive('dateField', function($filter) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) {
//View -> Model
var date = Date.parseExact(data,'yyyy-MM-dd');
// if the date field is not a valid date
// then set a 'date' error flag by calling $setValidity
ngModelController.$setValidity('date', date!=null);
return date == null ? undefined : date;
});
ngModelController.$formatters.push(function(data) {
//Model -> View
return $filter('date')(data, "yyyy-MM-dd");
});
}
}
});
Note: For parsing dates, this directive uses Date.js (an external library).
CSS:
.error {
color:red;
}
.error-border {
border: solid 2px red;
}
HTML:
<form name="myForm">
<input ng-class="{'error-border': myForm.myDate.$error.date}" type="date"
name="myDate" ng-model="myDate" date-field />
<span ng-show="myForm.myDate.$error.date" class="error">
Please enter a valid date!!!
</span>
<br /> Raw Date: {{myDate}}
<br /> Formatted Nicely: {{ myDate | date:'yyyy, MMMM dd'}}
<br /> Is Valid Date? {{ !myForm.myDate.$error.date}}
<br /> Is Form Valid? {{ myForm.$valid }}
</form>
Controller:
myApp.controller('ctrl', function($scope) {
$scope.myDate = new Date('2014-03-08T00:00:00');
});
Demo JS Fiddle with Date.js
Demo JS Fiddle with Moment.js

Related

AngularJS: How to edit parts of a datetime from different html controls

I would like to have 2 textboxes assigned to the same ng-model initialized to Date.now() and allow them to be edited by the user.
My template looks like:
<div ng-controller="MainCtrl">
<input type="text" ng-model="date | date:'yyyy-MM-dd'" />
<input type="text" ng-model="date | date:'HH:mm'" />
<button ng-click="submit()">Submit</button>
<div ng-if="show">
{{ date }}
</div>
</div>
And my controller looks like:
angular.module('app', []).controller('MainCtrl', function($scope) {
$scope.show = false;
$scope.date = new Date(Date.now());
$scope.submit = function () {
$scope.show = true;
}
});
Plunker: http://plnkr.co/edit/d2slQW6pDTLM4KTo
In my example, the textboxes are not editable, and I get a console error stating the expression is non-assignable.
How can I modify this example to allow the date parts to be modifiable?
If you're willing to use date and time inputs instead of text, this is very easy to do.
<input type="date" ng-model="date" />
<input type="time" ng-model="date" />
Because they're bound to the same Date instance, leap days daylight savings (where a day might be 23 or 25 hours) are supported.
If you don't like the native date and time inputs and want some more control over the style/functionality and consistent UI across devices, you can try Kendo UI's DatePicker and TimePicker widgets. They both have AngularJS support and are included in the free offering called Kendo UI Core.
And if you want to avoid having milliseconds in your time picker, make sure they're stripped from whatever Date instance is bound to your scope property.
$scope.date = new Date(Date.now());
$scope.date.setMilliseconds(0)
As an aside, I don't believe filters work in ng-model expressions, which is probably the source of your error message.

Deletion Error with Email Validation in Angular

So I've recently taken over an Angular Giving Form Application. I am running validation on the email field using ng-pattern and displaying the errors on blur with ngMessages. The validation works great, however once the validation passes as $valid if the user decides they need to make a change in their email and begin to delete part of the first deletion deletes the last character of the email as expected, but the second deletion deletes the entire field forcing the user to start from scratch.
The regex for ng-pattern is being set in the controller scope with the variable $scope.emailre
The files are much to large to place here but here is the link to the site I am working on for my client.
https://epiqa.moodyglobal.org/corporate/
Snippet of Angular controller:
myApp.controller('mainCtrl', function($scope, localStorageService, $http) {
$scope.emailre = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
Snippet of HTML Form:
<div class="row form-group">
<div class="col-sm-6">
<div>
<label class="label" for="txt_donorEmail">E-mail:</label>
<input ng-class="{ 'submitted-error' : givingForm.email.$invalid && submitted }" ng-model="email" type="text" id="email" name="email" class="textbox required full form-control" maxlength="50" ng-pattern="emailre" required />
</div>
<div ng-messages="givingForm.email.$error" ng-if="givingForm.email.$touched || submitted">
<div class="errorText" ng-message="required">This field is required</div>
<div class="errorText" ng-message="pattern">Enter a valid email</div>
</div>
</div>
</div>
I have tried changing the input type from type="text" to type="email" but when doing that any time the user types two (.) periods the field gets immediately deleted.
Please help any ideas are very welcome.
The behavior is caused by this section
$scope.$watch('email', function(value){
localStorageService.set('email',value);
$scope.emailValue = localStorageService.get('email');
});
By Angular documentation
The default behaviour in ngModel is that the model value is set to undefined when the validation determines that the value is invalid. By setting the allowInvalid property to true, the model will still be updated even if the value is invalid.
I'm not sure whether you want to save the invalid email into localStorage, though. Maybe you can add a check only update when the value is valid.

How to format a date from the date object in `ng-model`

I am getting date values from the ng-model from the controller. I would like to format the date as 10-22-2013 But in the output i am getting the date format as 10/22/2013
what is the correct way to format the date here?
js :
angular.module('dateInputExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.example = {
value: new Date(2013, 9, 22)
};
}]);
html :
<form name="myForm" ng-controller="DateController as dateCtrl">
<label for="exampleInput">Pick a date </label>
<input type="date" id="exampleInput" name="input" ng-model="example.value"
placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
<div role="alert">
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.date">
Not a valid date!</span>
</div>
</form>
Live Demo
Using purely HTML5 there is no answer to your question. Refer to this link.
There is no way possible to change the format
We have to differentiate between the over the wire format and the
browser's presentation format.
Wire format The HTML5 date input specification 1 refers to the
RFC3339 specification 2, which specifies a full-date format equal
to: yyyy-mm-dd. See section 5.6 of the RFC3339 specification for more
details.
Presentation format Browsers are unrestricted in how they present a
date input. At the time of writing Chrome has the most extensive date
support [3]. It displays a date picker using the user's local calendar
format. Opera (v10.6+) also displays a date picker, but shows the date
in the wire format. Other browsers, such as Firefox 44.0.2 and
Internet Explorer 9/10/11 display a text input field with the wire
format.
References http://www.w3.org/TR/html-markup/input.date.html
https://www.rfc-editor.org/rfc/rfc3339
https://plus.google.com/102860501900098846931/posts/hTcMLVNKnec
I suggest using angular-ui. It has a neat load of modules that makes everything easy for angular.
The markup in the view would look like this:
<p class="form-group">
<label>Result</label>
<input type="text" class="form-control" uib-datepicker-popup="{{format}}" ng-model="date" />
</p>
And on the controller:
angular.module('ui.bootstrap.demo').controller('DateParserDemoCtrl', function ($scope, uibDateParser) {
$scope.format = 'MM-dd-yyyy';
$scope.date = new Date();
});

Form validation with modals in Angular

I have a form inside a modal pop up. I am trying to run form validation on the inputs after the user attempts to submit the form. So far, I'm struggling to make things work.
In my view, I have the following (sorry if there are any syntax errors, I'm converting this from jade on the fly):
<script type="text/ng-template", id="modalVideoNew">
<div class="ngdialog-message">
<form class="form-horizontal" ng-submit="submitForm()" novalidate name="newVideoForm">
...
<div class="form-group">
<label> Title </label>
<div class="col-sm-8">
<input type="text" name="title", required='', ng-model="newVideoForm.title">
<span class="text-danger" ng-show="validateInput('newVideoForm.title', 'required')"> This field is required</span>
</div>
</div>
</div>
</script>
And then in my controller, where I'm calling the ng-dialog pop up, I have this:
$scope.newVideo = function() {
ngDialog.openConfirm({
template: 'modalVideoNew',
className: 'ngdialog-theme-default',
scope: $scope
}).then(function() {
$scope.validateInput = function(name, type) {
var input = $scope.newVideoForm[name];
return (input.$dirty || $scope.submitted) && input.$error[type];
};
var newVideo = $scope.newVideoForm;
...
Right now, I am still able to submit the form, but once I open it back up I see the 'This field is required' error message. Also, the input is pre-filled with [object, Object] instead of an empty text input box.
A way of cleaning your model would work with using a model var that belongs to your parent controller and cleaning it in the callback. Check out how the template has attached your parent controller's var FormData.
Check this out
So about your validation, what I would recommend you is to have your own controller in it, no matter how much code it will have. It helps you keeping concepts of modularization and a better control over your scopes. This way will also facilitate a lot when validating.

Conditional tooltip with Bootstrap 3 and angular

So I can get tooltips to appear on field focus, but I only want them to sometimes. I want to add a manual trigger, but to say the docs are lacking would be to indicate that some exist. Here's what I've found so far (in the source)
// Default hide triggers for each show trigger
var triggerMap = {
'mouseenter': 'mouseleave',
'click': 'click',
'focus': 'blur'
};
...
/**
* This allows you to extend the set of trigger mappings available. E.g.:
*
* $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
*/
this.setTriggers = function setTriggers ( triggers ) {
angular.extend( triggerMap, triggers );
};
So, how do you write one of these triggers?
if you are still searching for a solution it might be handy to know that the tooltips only show when there is a text value, otherwise they don't actually show.
I myself use the popover directive, here is a plunker where you can edit your text. When you clear the field, the tooltip won't show.
http://plnkr.co/edit/Zdkyhc90qTZFzLEwtrVL?p=preview
<body ng-controller="MainCtrl">
<br/><br/>
<input type="text" size="100" ng-model="error"/><br/><br/>
<p class="btn btn-default"
popover="{{error}}"
popover-placement="right"
popover-trigger="mouseenter">Hover my error!</p>
</body>
And in the controller you just set the error initial value. Make sure you include 'ui.bootstrap' as a dependency for your app, else it won't work.
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.error = 'Something went wrong';
});
AngularJS 1.5.7 and Bootstrap 3.3.6 support uib-tooltip-html properties on input, select and textarea elements. Unlike uib-tooltip properties, uib-tooltip-html properties support expressions. You should be able to express your conditions therein.
For example, here is a date of birth textbox with an expression that either names the field when valid OR explains the validation error:
<input id="dateOfBirth{{::vm.studentID}}"
name="dateOfBirth"
placeholder="Date of Birth"
uib-tooltip-html="myFormName.dateOfBirth.$valid ? 'Date of Birth' : myFormName.dateOfBirth.$error.required ? 'Date of Birth is required' : 'Date of Birth is not a valid date: mm/dd/yyyy'"
type="date"
class="form-control"
data-ng-model="vm.dateOfBirth"
data-ng-required="vm.editMode"
min="1920-01-01"
data-ng-max="vm.maxDateOfBirth"
tabindex="3" />
With a little more work you could explain the min and max date errors as well.
<label>
Open tooltips <span uib-tooltip="Hello!" tooltip-is-open="tooltipIsOpen" tooltip-placement="bottom">conditionally.</span>
</label>
Check the tooltip part of the API doc
we can use popover-enable property to show it conditional
This can be archived through Angular Property binding and the title property of the bootstrap element. In Bootstrap, a tooltip will only show in the DOM if some text was given for the title value. What you have to do is to bind property or method to the tooltip. Here getTooltip() should return either tooltip or empty string.
<button type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" [title]="getTooltip()">

Resources