Filter events by date using AngularJS - angularjs

I'd like to filter my events by date using AngularJS and jQuery Datepicker. But it seems not working using the input text...
My code below works with the title of the event...
Main issue : when I choose a date in the jQuery Datepicker, I get no events...
$scope.onChange = function(){
$scope.search.start = new Date(moment($scope.search.start, 'DD/MM/YYYY').format("YYYY-MM-DD 00:00:00"));
$scope.search = _.reduce($scope.search, function(result, n, key) {
if (n !== '') {
result[key] = n;
}
return result;
}, {});
$scope.events = data.events;
$scope.filteredEvents = $filter('filter')($scope.events, $scope.search);
};
<input class="form-control datepicker" id="start" type="text" ng-model="search.start" ng-change="onChange()" autocomplete="off">
<input class="form-control" id="title" type="text" ng-model="search.title" ng-change="onChange()" autocomplete="off">
<div class="col-12" ng-repeat="event in events | filter:search | limitTo:limit">
<div class="event">
<div class="event-body">
{{event.title}}
<p ng-if="event.end" class="event-date">{{event.start | date:"dd/MM/yyyy"}}</p>
</div>
</div>
<div class="space10"></div>
</div>

Out of the Box the JQueryUI datepicker will not work with angular because the angular model is not being updated when Jquery sets the input value. You need to tell JQueryUI datepicker to update the model.
The best way to do that is create a directive that sets up the datepicker and adds an onSelect method that sets the view value model controllers view value ngModelCtrl.$setViewValue and applies it to the scope scope.$apply()
HTML:
<input type="text" ng-model="date" datepicker />
JS
app.directive('datepicker', function() {
return {
restrict: 'A',
require : 'ngModel',
link : function (scope, element, attrs, ngModelCtrl) {
$(function(){
element.datepicker({
dateFormat:'dd/mm/y',
onSelect:function (date) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(date);
});
}
});
});
}
}
});
If you also want to use a date in a different format than available using the Date Picker you will need to format using the ng-change directive.
<input class="form-control " datepicker type="text"
ng-model="search.start" ng-change="onChange()"/>
$scope.onChange = function(){
$scope.search.start = moment($scope.search.start, 'DD/MM/YYYY')
.format("YYYY-MM-DDT00:00:00.000[Z]");
};
Working Example

Related

Attribute directive accessing element and adding a listner

I need to write an attribute directive using Angular 1.5.5 which is basically restricting inputs on keypress event of the text box. So it should look like this
<input type="number" name="age" id="age" restrict-char="['e','-']" />
How can we write an attribute directive without using link function. I dont want to use link function since i will be porting my code base to Angular 2.0 and link functions are not supported there.
Not sure if that is what you want but you can use $parsers on ngModelController and set ng-model-options to update on any event.
angular.module('app', []);
angular.module('app').directive('restrictChar', () => {
return {
restrict: 'A',
require: 'ngModel',
scope: {
restricted: '=restrictChar'
},
controller: function ($scope, $element) {
const ngModel = $element.controller('ngModel');
ngModel.$parsers.unshift((value) => {
const newVal = value
.split('')
.filter((char) => $scope.restricted.indexOf(char) === -1)
.join('');
$element.val(newVal);
return newVal;
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<div ng-app="app">
<input type="text" ng-model="x" name="age" id="age" restrict-char="['e','-']" ng-model-options="{updateOn: 'keyup'}" /><br>
{{x}}
</div>

How do I get my dual binding to work properly with bootstrap datetime picker? [duplicate]

Here is the html for the date field :
<div class='form-group'>
<label>Check out</label>
<input type='text' ng-model='checkOut' class='form-control' data-date-format="yyyy-mm-dd" placeholder="Check out" required id="check-out">
</div>
<script>
$('#check-out').datepicker();
</script>
The datepicker shows up in the input field. However if I do this in my controller :
console.log($scope.checkOut);
I get undefined in the javascript console.
How to solve this ?
Is there a better way to use bootstrap-datepicker with angularjs ?
I don't want to use angular-ui/angular-strap since my project is bloated with javascript libraries.
As #lort suggests, you cannot access the datepicker model from your controller because the datepicker has its own private scope.
If you set: ng-model="parent.checkOut"
and define in the controller: $scope.parent = {checkOut:''};
you can access the datepicker using: $scope.parent.checkOut
I am using bootstrap 3 datepicker https://eonasdan.github.io/bootstrap-datetimepicker/ and angularjs, I had the same problem with ng-model, so I am getting input date value using bootstrap jquery function, below is the code in my controller, it's worked for me.
Html
<input class="form-control" name="date" id="datetimepicker" placeholder="select date">
Controller
$(function() {
//for displaying datepicker
$('#datetimepicker').datetimepicker({
viewMode: 'years',
format: 'DD/MM/YYYY',
});
//for getting input value
$("#datetimepicker").on("dp.change", function() {
$scope.selecteddate = $("#datetimepicker").val();
alert("selected date is " + $scope.selecteddate);
});
});
I just found a solution to this myself. I just pass in the model name to the directive (which I found most of online). This will set the value of the model when the date changes.
<input data-ng-model="datepickertext" type="text" date-picker="datepickertext" />{{datepickertext}}
angular.module('app').directive('datePicker', function() {
var link = function(scope, element, attrs) {
var modelName = attrs['datePicker'];
$(element).datepicker(
{
onSelect: function(dateText) {
scope[modelName] = dateText;
scope.$apply();
}
});
};
return {
require: 'ngModel',
restrict: 'A',
link: link
}
});
I am using Angular JS 1.5.0 and Bootstrap 3 Datetimepicker from https://eonasdan.github.io/bootstrap-datetimepicker/
After some time and struggling, I finally found a solution how to make it work for me :)
JSFiddle: http://jsfiddle.net/aortega/k6ke9n2c/
HTML Code:
<div class="form-group col-sm-4" >
<label for="birthdate" class="col-sm-4">Birthday</label>
<div class="col-sm-8">
<div class="input-group date" id="birthdate" ng-model="vm.Birthdate" date-picker>
<input type="text" class="form-control netto-input" ng-model="vm.Birthdate" date-picker-input>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="form-group col-sm-4">
<label for="birthdateText" class="col-sm-4">Model:</label>
<div class="col-sm-8">
<input type="text" class="form-control netto-input" ng-model="vm.Birthdate">
</div>
</div>
</body>
App.js:
Simply a controller setting the viewmodels Birtdate attribute:
var app = angular.module('exampleApp',[]);
app.controller('ExampleCtrl', ['$scope', function($scope) {
var vm = this;
vm.Birthdate = "1988-04-21T18:25:43-05:00";
}]);
The first directive is initializing the datetimepicker and listening to the dp.change event.
When changed - the ngModel is updated as well.
// DatePicker -> NgModel
app.directive('datePicker', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
$(element).datetimepicker({
locale: 'DE',
format: 'DD.MM.YYYY',
parseInputDate: function (data) {
if (data instanceof Date) {
return moment(data);
} else {
return moment(new Date(data));
}
},
maxDate: new Date()
});
$(element).on("dp.change", function (e) {
ngModel.$viewValue = e.date;
ngModel.$commitViewValue();
});
}
};
});
The second directive is watching the ngModel, and triggering the input onChange event when changed. This will also update the datetimepicker view value.
// DatePicker Input NgModel->DatePicker
app.directive('datePickerInput', function() {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
// Trigger the Input Change Event, so the Datepicker gets refreshed
scope.$watch(attr.ngModel, function (value) {
if (value) {
element.trigger("change");
}
});
}
};
});
I have the same problem and resolve like this
added in html part
<input class="someting" id="datepicker" type="text" placeholder="Dae" ng-model=""/>
and simple in Controller call
$scope.btnPost = function () {
var dateFromHTML = $('#datepicker').val();
Have you tried AngularUI bootstrap? It has all the bootstrap modules rewritten in angular(including datepicker): http://angular-ui.github.io/bootstrap/
One of ways around: set the id field to the input, then call document.getElementById('input_name').value to get the value of the input field.
Using this datepicker I had the same problem. I solved it using a little trick.
In the inputs tag I added a new attribute (dp-model):
<input class="form-control dp" type="text" dp-model="0" />
<input class="form-control dp" type="text" dp-model="1" />
...
And then in the js file I forced the binding in this way:
$scope.formData.dp = []; // arrays of yours datepicker models
$('.dp').datepicker().on('changeDate', function(ev){
$scope.formData.dp[$(ev.target).attr('dp-model')] = $(ev.target).val();
});
This worked for me:
set ng-model="date"
on your angular controller:
$scope.date = '';
$('#check-out').datepicker().on('changeDate', function (ev) {
$scope.date= $('#check-out').val();
$scope.$digest();
$scope.$watch('date', function (newValue, oldValue) {
$scope.date= newValue;
});
});
My actual trouble was that the value of the model was not reflected till another component on the scope was changed.
im using this , and my code :
this.todayNow = function () {
var rightNow = new Date();
return rightNow.toISOString().slice(0,10);
};
$scope.selecteddate = this.todayNow();
$(function() {
//for displaying datepicker
$('.date').datepicker({
format: 'yyyy-mm-dd',
language:'fa'
});
//for getting input value
$('.date').on("changeDate", function() {
$scope.selecteddate = $(".date").val();
});
});
To solve this, I have my HTML looking like this:
<div class='input-group date' id='datetimepicker1'>
<input type='text' ng-model="date.arrival" name="arrival" id="arrival"
class="form-control" required />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
My ng-model wouldn't update, so I used this to fix it:
$("#datetimepicker1").on("dp.change", function (e) {
$scope.date.arrival = $("#arrival").val(); // pure magic
$('#datetimepicker2').data("DateTimePicker").minDate(e.date); // this line is not relevant for this example
});

How to use Material Design Lite and Angular for forms

*Disclaimer: this question is not about using material design in an angular app but using material design lite inside a form. So, please, don't answer I should rather use angular material, materialize, lumx, material bootstrap, or daemonite... I know, they exist.*
With Angular a typical form field for a name would be:
<form name="myForm">
<label>
Enter your name:
<input type="text"
name="myName"
ng-model="name"
ng-minlength="5"
ng-maxlength="20"
required />
</label>
<div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
<div ng-message="required">You did not enter a field</div>
<div ng-message="minlength">Your field is too short</div>
<div ng-message="maxlength">Your field is too long</div>
</div>
</form>
With Material Design Lite, it would be something like that:
<form action="#">
<div class="mdl-textfield mdl-js-textfield">
<input class="mdl-textfield__input" type="text" id="user" pattern="[A-Z,a-z, ]*" />
<label class="mdl-textfield__label" for="user">User name</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div>
</form>
Question: how is it possible to use the angular validation functionality combined with ngMessage (for multiple error messages) with the Material Design Lite?
You can write your own angular module to validate MDL input fields, here is a working example: http://codepen.io/alisterlf/pen/ZGgJQB
JS
// create angular app
var validationApp = angular.module('validationApp', ['fieldMatch']);
//Field Match directive
angular.module('fieldMatch', [])
.directive('fieldMatch', ["$parse", function($parse) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var me = $parse(attrs.ngModel);
var matchTo = $parse(attrs.fieldMatch);
scope.$watchGroup([me, matchTo], function(newValues, oldValues) {
ctrl.$setValidity('fieldmatch', me(scope) === matchTo(scope));
}, true);
}
}
}]);
//Run material design lite
validationApp.run(function($rootScope, $timeout) {
$rootScope.$on('$viewContentLoaded', function(event) {
$timeout(function() {
componentHandler.upgradeAllRegistered();
}, 0);
});
$rootScope.render = {
header: true,
aside: true
}
});
// create angular controller
validationApp.controller('mainController', function($scope) {
$scope.formStatus = '';
// function to submit the form after all validation has occurred
$scope.submit = function() {
// check to make sure the form is completely valid
if ($scope.form.$invalid) {
angular.forEach($scope.form.$error, function(field) {
angular.forEach(field, function(errorField) {
errorField.$setTouched();
})
});
$scope.formStatus = "Form is invalid.";
console.log("Form is invalid.");
} else {
$scope.formStatus = "Form is valid.";
console.log("Form is valid.");
console.log($scope.data);
}
};
});

binding the model value of Twitter Bootstrap datepicker in controller in Angular js

I am building an application with Angular.js and Twitter Bootstrap.
HTML:
<div ng-controller="myController">
<label for="event">Event</label>
<input type="text" ng-model="event"/>
<label for="eventdate">Date</label>
<div class="input-append date" id="datepicker" data-date-format="dd-mm-yyyy">
<input class="span2" size="20" type="text" id="datepicker" ng-model="eventdate" required>
<span class="add-on"><i class="icon-th"></i></span>
<input class="btn-primary" type="submit" id="submit" value="Submit" ng-click="submit()" />
</div>
Controller:
var myApp1 = angular.module('myApp1', []);
myApp1.controller('myController', function($scope) {
$('#datepicker').datepicker();
$scope.submit = function () {
console.log($scope.event);
console.log($scope.eventdate);
};
});
When I click "Submit" button,
console.log($scope.event); prints the data entered in event text box.
But console.log($scope.eventdate); prints "undefined" when I select a date from the date picker
What may be the reason?
Please advice.
Your bootstrap datepicker is a 3rd-component outside of angular. When you change your date from the datepicker, angular is not aware of the changes.
You have to write a custom directive like this:
app.directive('datepicker', function() {
return {
restrict: 'A',
// Always use along with an ng-model
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return;
ngModel.$render = function() { //This will update the view with your model in case your model is changed by another code.
element.datepicker('update', ngModel.$viewValue || '');
};
element.datepicker().on("changeDate",function(event){
scope.$apply(function() {
ngModel.$setViewValue(event.date);//This will update the model property bound to your ng-model whenever the datepicker's date changes.
});
});
}
};
});
Apply the directive to html:
<div class="input-append date" datepicker ng-model="eventdate" data-date-format="dd-mm-yyyy">
<input class="span2" size="20" type="text" required="" />
<span class="add-on">
<i class="icon-th"></i>
</span>
</div>
DEMO

Angular JS update input field after change

I'm trying to build a simple calculator in Angular in which I can override the total if I want. I have this part working but when I then go back to enter in a number in fields one or two the total isn't updated in the field.
Here is my jsfiddle http://jsfiddle.net/YUza7/2/
The form
<div ng-app>
<h2>Calculate</h2>
<div ng-controller="TodoCtrl">
<form>
<li>Number 1: <input type="text" ng-model="one">
<li>Number 2: <input type="text" ng-model="two">
<li>Total <input type="text" value="{{total()}}">
{{total()}}
</form>
</div>
</div>
The javascript
function TodoCtrl($scope) {
$scope.total = function(){
return $scope.one * $scope.two;
};
}
You can add ng-change directive to input fields. Have a look at the docs example.
I'm guessing that when you enter a value into the totals field that value expression somehow gets overwritten.
However, you can take an alternative approach: Create a field for the total value and when either one or two changes update that field.
<li>Total <input type="text" ng-model="total">{{total}}</li>
And change the javascript:
function TodoCtrl($scope) {
$scope.$watch('one * two', function (value) {
$scope.total = value;
});
}
Example fiddle here.
I wrote a directive you can use to bind an ng-model to any expression you want. Whenever the expression changes the model is set to the new value.
module.directive('boundModel', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
var boundModel$watcher = scope.$watch(attrs.boundModel, function(newValue, oldValue) {
if(newValue != oldValue) {
ngModel.$setViewValue(newValue);
ngModel.$render();
}
});
// When $destroy is fired stop watching the change.
// If you don't, and you come back on your state
// you'll have two watcher watching the same properties
scope.$on('$destroy', function() {
boundModel$watcher();
});
}
});
You can use it in your templates like this:
<li>Total<input type="text" ng-model="total" bound-model="one * two"></li>
You just need to correct the format of your html
<form>
<li>Number 1: <input type="text" ng-model="one"/> </li>
<li>Number 2: <input type="text" ng-model="two"/> </li>
<li>Total <input type="text" value="{{total()}}"/> </li>
{{total()}}
</form>
http://jsfiddle.net/YUza7/105/
Create a directive and put a watch on it.
app.directive("myApp", function(){
link:function(scope){
function:getTotal(){
..do your maths here
}
scope.$watch('one', getTotals());
scope.$watch('two', getTotals());
}
})

Resources