using angularjs $filter() inside directives - javascript

i want to hide some part of the input text value using some filter.
app.directive('limtToDate', ['$filter', function ($filter) {
var dateFormat = "DD/MM/YYYY HH:mm"
return {
restrict: 'A',
link: function (scope, ielem, attrs) {
scope.$watch(attrs.ngModel, function (v) {
console.log('value changed, new value is: ' + v);
$filter('limitTo')(ielem.val(), -5);
});
}
}}]);
http://jsfiddle.net/PqAhk/2/
well, my input text should just show 12:12 instead of 01/01/1970 12:12. and after editing the time, for example, if user change the time to 12:40 my ng-model has to be like following 1970/01/01 12:40

First, thank you all, this solution was created by #guru and many thanks to him.
http://plnkr.co/edit/VhsleIWMq8A4rJcVQDaw?p=preview
the solution takes advantage from $formatter and $parser related to the angularjs pipeline rendering.
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
ps : this solution is not compatible with angularjs.2-rc.x

If you don't want your model to change then don't use two way binding:
<div ng-app = "fiddle">
<div ng-controller="MyCtrl">
<table class="table">
<input type="text" ng-value="fromDate | limitTo:-5" />
</table>
</div>
</div>
Better yet why not make from date a real date object:
$scope.fromDate = new Date(); // current date for demonstration, set to real value
And use the date filter:
<input type="text" ng-value="fromDate | date:'HH:mm'" />

The filter in the link function -> $filter('limitTo')(ielem.val(), -5); filters the array and returns a new array with the filtered values. It has to be assigned back to the scope variable for the changes to get reflected.
Something like below.
$scope.filteredValue= $filter('limitTo')(ielem.val(), -5);
Thats intersting. Though formatting can be easy by using $formatter in the ngModelCtl syncing the input data change back to the model can be tricky.
You can use the ngModelCtl.$parsers and ngModelCtl.$formatters to set up the format and view value.
Here is a working Solution: http://plnkr.co/edit/1KqLsIwGJjwUIbs0fwmQ?p=preview

Related

Angular js getting error while updating date

I have a form to submit data. I have one Date field in that form. All is working fine. But when i try to retrieve data to update including date. i get error "ngModel:datefmt".
I have tried converting date formats in database YY-mm-dd and dd-mm-yy.
I have tried converting date formats in JavaScript to yy-mm-dd and dd-mm-yy.
I am using input type ="date".
You have the date as string hence you are getting the error you need to convert it to date object ,
$scope.dateField = new Date(date_string);
I would recommend to use a directive for this to use it in the input element.
<input convert-date type="date" ng-model="dateField">
app.directive('convertDate', function(){
return {
restrict : 'A',
scope : {ngModel : '='},
link: function (scope) {
if (scope.ngModel)
{
scope.ngModel = new Date(scope.ngModel);
}
}
}
});

how to filter input value in AngularJS

I'm trying to implement filtering on my input element.
I want to make filtering for input with type="text" field.
For instance, if the model contain more than available characters than I want to change my input value.
I've created jsfiddle
I have directive that generate html template dynamically and it contains input field.
var app = angular.module('app', [])
.controller('ctrlr', function($scope){
$scope.myModel = "test";
$scope.availableCharacters = 5;
$scope.$watch('myModel', function(newValue, oldValue){
if(!newValue){
return;
}
if(newValue.length > 5){
$scope.cutString();
}
});
$scope.cutString = function(){
var length = $scope.myModel.length;
var string = $scope.myModel.slice(0, $scope.availableCharacters);
var countStars = length - string.length;
$scope.myModel = $scope.createStars(string, countStars);
}
$scope.createStars = function(string, countStars){
for(var i = 1; i <= countStars; i++){
string = string+'*';
}
return string;
}
})
.directive('awesome' , function(){
return {
restrict:'E',
template:'<input type="text" ng-model="myModel" ng-value="myModel | filter:my" />'
}
})
Could it possibly to move my code into the filter function? I have a lot of business logic and I don't want to keep my code in the controller, because it will be reusable directive.
I think that implementing this part of functionality as a filter is not the best idea.
It would be much more dynamic if you will implement it as directive on your input element like:
<input type="text" ng-model="myModel" ng-value="myModel" max-length="20" />
In this case it would be more flexible. You will be able to pass an argument into directive (for example length of acceptable value).
Also it is not really readable for another developers to make your input as a template of your directive because of you are using model as attribute of input field and not binding it from directive.
Is there any reason why you use directive to render simple input?
If not, then just live it as input in your view and add directive instead of filter to work with data checks limitations.
Another approach is to implement custom form controls. That will allows you to control incoming and out-coming data.
Here is a example from documentation - Implementing custom form controls (using ngModel)

Dynamically change an input field's placeholder?

I am working with Javascript and the d3 library, and AngularJS.
Is there a way to dynamically change an input box's placeholder? I am working with a calendar widget and multiple views and wanted to see if there was a way to have the placeholder always be the value that was last inputted into the field.
I wrote a small function that always returns the last thing that was entered into the input field...but then when I tried setting placeholder=functionIwrote() it literally makes the placeholder "fucntionIwrote()" instead of running the function.
I can't comment but... If you're using angularJs, you just have to bind the model of your input to the placeholder!
<input type="date" placeholder="myModel" ng-model="myModel" />
This way, your input would always be the latest filled value.
If you want to change your view, and then retrieve datas, then you have to store them outside of the controller scope - which is "cleaned" every time if you're using the ngIf directive -.
A good way to do this is to use a service as persistance layer.
Since you want the placeholder to be changed or updated both automatically and dynamically, you may use the jQuery code below:
$(function() {
$('input').on('change blur', function() {
!this.value || $(this).attr('placeholder', this.value);
});
});
WORKING JS FIDDLE DEMO
Yes you can do it in this way ,
<input
placeholder="Select Date"
onfocus="(this.type='date')"
onblur="if (!this.value) this.type = 'text'">
here's a fiddle: http://jsfiddle.net/bBh3L/
'placeholder' is an element attribute, so you can use $('#myInput').attr(attributeName, attributeValue) to set it.
In this case, I mapped the button click to change the placeholder using:
$('#myInput').attr('placeholder', 'new one');
I guess that you're trying to wrap your calendar widget into an angular directive, if so, here's what I did for a similar use case (I display the accepted/valid format as placeholder):
module.directive('yourDirective', [function() {
return {
link: function($scope, $element, $attrs, $controller) {
// bind 'yourValue' (the one you want to show as placeholder) in the scope
$scope.$watch('yourValue', function(value) {
$attrs.$set('placeholder', value);
});
}
};
}]);
There exists a conditional attribute property in AngularJS ng-attr-{property_name}
For example, I'm using different placeholders for different search options using
ng-attr-placeholder="{{isAdvanceSearch ? setPlaceholder(searchOption) : 'John Smith, 08/23/1970, 123'}}"
Here on the basis of isAdvanceSearch variable, I'm setting different placeholders in setPlaceholder method.
setPlaceholder method returns the placeholder to set in the input field.
$scope.setPlaceholder = function(searchOption) {
if (searchOption === "foo") {
return "Search by foo… e.g. foo1";
} else if (searchOption === "bar") {
return "Search by bar… e.g. bar123";
} else {
return "John Smith, 08/23/1970, 123";
}
};
Note: John Smith, 08/23/1970, 123 is the default placeholder.
Don't forget to wrap the expression in the {{}} brackets.

Angular.js and HTML5 date input value -- how to get Firefox to show a readable date value in a date input?

I have an HTML5 date input and I would like its value to be set to the value of the date property in my model by default. I'm not too fussy about formatting since Chrome seems to decide that for me anyway based on my locale, but ideally the format would be consistently dd/MM/yyyy.
Fiddle
This is how I set up my input:
<input type="date"
ng-model="date"
value="{{ date | date: 'yyyy-MM-dd' }}" />
This works fine on Chrome, and I see the following by default:
(I still don't quite understand why the value had to be given in yyyy-MM-dd, if Chrome still formats it based on my locale, but that's a different question.)
My issue is with Firefox not showing the date's value in the way I've specified. I think this has to do with binding the input to the date model, because I can specify pretty much any string in the value attribute, and I will still see the long date string in the input by default:
If I remove ng-model="date" from the input tag, Firefox nicely displays any value I give it. I didn't think the model that an input was bound to actually had any effect on its default value?
I understand the date input isn't supported universally, but seeing as it's supposed to fall back on a simple text input, I don't see why its value won't simply be 2013-08-05, as specified by angular's date filter.
So, how do I get Firefox to accept my formatted value in the date input?
NOTE After the edits have been done by the user, I will of course perform validation and convert each date input value into a proper Date object. Not sure if this is relevant to the question, but putting it out there just in case, because the input formats would obviously need to be consistent for the date conversion to work the same in all browsers. Problematic, of course, with Chrome deciding the input format for me...
The problem is that value is ignored when ng-model is present.
Firefox, which doesn't currently support type="date", will convert all the values to string. Since you (rightly) want date to be a real Date object and not a string, I think the best choice is to create another variable, for instance dateString, and then link the two variables:
<input type="date" ng-model="dateString" />
function MainCtrl($scope, dateFilter) {
$scope.date = new Date();
$scope.$watch('date', function (date)
{
$scope.dateString = dateFilter(date, 'yyyy-MM-dd');
});
$scope.$watch('dateString', function (dateString)
{
$scope.date = new Date(dateString);
});
}
Fiddle
The actual structure is for demonstration purposes only. You'd be better off creating your own directive, especially in order to:
allow formats other than yyyy-MM-dd,
be able to use NgModelController#$formatters and NgModelController#$parsers rather than the artifical dateString variable (see the documentation on this subject).
Please notice that I've used yyyy-MM-dd, because it's a format directly supported by the JavaScript Date object. In case you want to use another one, you must make the conversion yourself.
EDIT
Here is a way to make a clean directive:
myModule.directive(
'dateInput',
function(dateFilter) {
return {
require: 'ngModel',
template: '<input type="date"></input>',
replace: true,
link: function(scope, elm, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.unshift(function (modelValue) {
return dateFilter(modelValue, 'yyyy-MM-dd');
});
ngModelCtrl.$parsers.unshift(function(viewValue) {
return new Date(viewValue);
});
},
};
});
Fiddle
That's a basic directive, there's still a lot of room for improvement, for example:
allow the use of a custom format instead of yyyy-MM-dd,
check that the date typed by the user is correct.
Why the value had to be given in yyyy-MM-dd?
According to the input type = date spec of HTML 5, the value has to be in the format yyyy-MM-dd since it takes the format of a valid full-date which is specified in RFC3339 as
full-date = date-fullyear "-" date-month "-" date-mday
There is nothing to do with Angularjs since the directive input doesn't support date type.
How do I get Firefox to accept my formatted value in the date input?
FF doesn't support date type of input for at least up to the version 24.0. You can get this info from here. So for right now, if you use input with type being date in FF, the text box takes whatever value you pass in.
My suggestion is you can use Angular-ui's Timepicker and don't use the HTML5 support for the date input.
You can use this, it works fine:
<input type="date" class="form1"
value="{{date | date:MM/dd/yyyy}}"
ng-model="date"
name="id"
validatedateformat
data-date-format="mm/dd/yyyy"
maxlength="10"
id="id"
calendar
maxdate="todays"
ng-click="openCalendar('id')">
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar" ng-click="openCalendar('id')"></span>
</span>
</input>
In my case, I have solved this way:
$scope.MyObject = // get from database or other sources;
$scope.MyObject.Date = new Date($scope.MyObject.Date);
and input type date is ok
I've used ng-change:
Date.prototype.addDays = function(days) {
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
}
var app = angular.module('myApp', []);
app.controller('DateController', ['$rootScope', '$scope',
function($rootScope, $scope) {
function init() {
$scope.startDate = new Date();
$scope.endDate = $scope.startDate.addDays(14);
}
function load() {
alert($scope.startDate);
alert($scope.endDate);
}
init();
// public methods
$scope.load = load;
$scope.setStart = function(date) {
$scope.startDate = date;
};
$scope.setEnd = function(date) {
$scope.endDate = date;
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-controller="DateController">
<label class="item-input"> <span class="input-label">Start</span>
<input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
</label>
<label class="item-input"> <span class="input-label">End</span>
<input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
</label>
<button button="button" ng-disabled="planningForm.$invalid" ng-click="load()" class="button button-positive">
Run
</button>
</div <label class="item-input"> <span class="input-label">Start</span>
<input type="date" data-ng-model="startDate" ng-change="setStart(startDate)" required validatedateformat calendar>
</label>
<label class="item-input"> <span class="input-label">End</span>
<input type="date" data-ng-model="endDate" ng-change="setEnd(endDate)" required validatedateformat calendar>
</label>
Check this fully functional directive for MEAN.JS (Angular.js, bootstrap, Express.js and MongoDb)
Based on #Blackhole ´s response, we just finished it to be used with mongodb and express.
It will allow you to save and load dates from a mongoose connector
Hope it Helps!!
angular.module('myApp')
.directive(
'dateInput',
function(dateFilter) {
return {
require: 'ngModel',
template: '<input type="date" class="form-control"></input>',
replace: true,
link: function(scope, elm, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.unshift(function (modelValue) {
return dateFilter(modelValue, 'yyyy-MM-dd');
});
ngModelCtrl.$parsers.push(function(modelValue){
return angular.toJson(modelValue,true)
.substring(1,angular.toJson(modelValue).length-1);
})
}
};
});
The JADE/HTML:
div(date-input, ng-model="modelDate")
If using Angular Material Design, you can use the datepicker component there and this will work in Firefox, IE etc.
https://material.angularjs.org/latest/demo/datepicker
Fair warning though - personal experience is that there are problems with this, and seemingly it is being re-worked at present. See here:
https://github.com/angular/material/issues/4856

AngularJS - Input change outside directive value passed in to directive

I am a beginner to AngularJs and I cannot figure out how to retrieve data from outside a directive. I have various input being updated and I need the directive to take this data and work with it.
For example, in the code below, the first input field is hooked up to the directive and works fine, but without putting the directive attribute on the second input field, how can the data typed in that field be updated in the directive?
HTML:
<div ng-app="myDirective">
<input type="text" ng-model="test1" my-directive>
<input type="text" ng-model="test2">
</div>
Directive:
angular.module('myDirective', [])
.directive('myDirective', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(attrs.ngModel, function (v) {
console.log('New Value from field 1: ' + v);
//console.log('New Value from field 2: ' + ???);
});
}
};
});
I could have explained that in text, but I think it would be much better if you watch these 3 videos by john lindquist:
Isolate Scope "#"
Isolate Scope "="
Isolate Scope "&"
And summary.
They are really short (~4min each) but very simple and useful.
PS: by the way, i recommend you to watch others as well. They are all short and precise, loved them.
Since your directive does not create a new scope, the scope variable inside the directive's link method points to the outer scope containing the two inputs. So you can replace:
//console.log('New Value from field 2: ' + ???);
with
console.log('New Value from field 2: ' + scope.test2);
Make sure to enter some data in the second input when testing or it will print undefined.
Here is a working fiddle
EDIT: If you did need to use isolate scope in your directive, you could do the following in your HTML:
<input type="text" ng-model="test1" my-directive="test2">
<input type="text" ng-model="test2">
The difference here is now passing in the test2 model into the directive, and setting up a binding to it in your directive by adding the scope property:
scope: {
otherInput: '=myDirective'
// this tells the directive to bind the local variable `otherInput`
// to whatever the `my-directive` attribute value is. In this case, `test2`
},
This allows you to access passed values in your directive. You would then change your $watches as follows:
scope.$watch(attrs.ngModel, function (v) {
console.log('New Value from field 1: ' + v);
console.log('New Value from field 2: ' + scope.otherInput);
});
// notice the syntax for watching a scope variable
scope.$watch('otherInput', function (v) {
console.log('New Value from field 1: ' + scope.test1);
console.log('New Value from field 2: ' + v);
});
I've included this in my fiddle as another example, test3 and test4.
AngularJs directive lets you to use scope with different ways and do many cool things you need.You can use your scope as not inherit, inherit and isolated.If you use scope as isolated,you can pass variables and bind it wherever you want.
here are 2 cool articles with examples, which can help you
http://www.w3docs.com/snippets/angularjs/change-variable-from-outside-of-directive.html
http://www.w3docs.com/snippets/angularjs/bind-variable-inside-angularjs-directive-isolated-scope.html

Categories

Resources