I get from the server dates, sometimes null, and my filter parse /Date(-62135596800000)/ to 0001-01-01 but I would like to have empty string.
How can I do this?
Here's my filter:
filter('myDateFormat', function() {
return function (data) {
return moment(data).format("YYYY-MM-DD");
};
})
Well your server is returning you null or a date string.
null can be handled by simple null check but for your other input "Date(-62135596800000)" which is a valid date, you can't return empty string, without explicitly checking for it.
moment(Date(-62135596800000)).isValid() // return 'true'
you may try below code.
// if inputDate not defined or null
if (!inputDate || inputDate == null) {
return '';
} else if (moment(inputDate).isValid()){
return moment(inputDate).format("DD MM YYYY");
} else {
return '';
}
but if your server is returning this specific date occasionally 'Date(-62135596800000)' and you want to avoid this, you can put explicit check for it.
if (!inputDate || inputDate == null) {
return '';
}
if (inputDate == 'Date(-62135596800000)') {
return '';
} else if (moment(inputDate).isValid()) {
return moment(inputDate).format("DD MM YYYY");
} else {
return '';
}
The filter could be improved like this:
filter('myDateFormat', function() {
return function (data) {
return data > 0 ? moment(data).format("YYYY-MM-DD") : "";
};
})
First of all decide what should be your minimum date.
For example SQL's minimum date is 1753-01-01
After that compare your date with this minimum date like:
filter('myDateFormat', function() {
return function (data) {
var minDate = moment('1753-01-01');// decide your minimum date
return moment(data).diff(minDate) > 0 ? moment(data).format("YYYY-MM-DD") : "";
};
})
Related
I have a requirement to not render a currency value if it is zero.
i.e.:
v=1 render $1
v=0 render nothing
[ EDIT ]
:egg on face:
Once I looked deeper into the core code, I found there is a custom filter.
angular
.module('com.td.tdct.bbpcCore')
.filter('currencyFilter', ['$rootScope', 'tdBbpcUserService', '$filter', function ($rootScope, tdBbpcUserService, $filter) {
return function (input, decimal, symbol) {
var languageCd;
if (input) {
if (!$rootScope.languageChange) {
languageCd = tdBbpcUserService.getLanguageCd();
} else {
languageCd = $rootScope.languageChange;
}
var value = input.toString().replace(/[^\d|\-+|\.+]/g, '');
value = (angular.isNumber(decimal)) ? $filter('number')(value, decimal) : $filter('number')(value);
if (angular.isString(languageCd) && (languageCd.toUpperCase() === "FR" || languageCd.toUpperCase() === "FR_CA")) {
value = (angular.isDefined(symbol) && symbol === "N") ? value.toString() : value.toString() + " $";
} else {
value = (angular.isDefined(symbol) && symbol === "N") ? value.toString() : "$ " + value.toString();
}
return value;
}
};
}]);
It's implemented thus:
{{asset.prevMarginalRate | currencyFilter:0}}
I'd like to either
add an optional flag to this existing filter - to return empty if set (it's got to be optional, since existing methods that use this shouldn't be affected)
or
layer another filter on top.
whichever is best practice.
In the first case, I'm trying to figure out how to pass that flag in, sort of thus:
{{asset.prevMarginalRate | currencyFilter:0, true}}
You need to create your own filter for achieve this.
I would do something like this:
app.filter('currencyWithoutZero', function() {
return function(x) {
if(x !== 0) return '$' + x;
else return '';
};
});
Working demo
0 is falsy. So you can do an OR operation to remove if like any false / null / empty values.
function foo(x) {
return x || "nothing";
}
v = 1;
console.log(foo(v));
v = 0;
console.log(foo(v));
I have an array of events and I have a search() function (below) that filters through it. Currently it only filters for name or date. Within my payload I have an array of tags, and I'm trying to figure out how to include it in the filtering of this. My current work-around is buttons that re-run the /event endpoint with search params which I don't like.
search(array: any[], query: string, excludeProps?: string|string[], dateFormat?: string) {
if (!query || !this._objArrayCheck(array)) {
return array;
}
const lQuery = query.toLowerCase();
const isoDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/; // ISO UTC
const dateF = dateFormat ? dateFormat : 'medium';
const filteredArray = array.filter(item => {
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (!excludeProps || excludeProps.indexOf(key) === -1) {
const thisVal = item[key];
if (
// Value is a string and NOT a UTC date
typeof thisVal === 'string' &&
!thisVal.match(isoDateRegex) &&
thisVal.toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
// Value is a Date object or UTC string
(thisVal instanceof Date || thisVal.toString().match(isoDateRegex)) &&
// https://angular.io/api/common/DatePipe
// Matching date format string passed in as param (or default to 'medium')
this.datePipe.transform(thisVal, dateF).toLowerCase().indexOf(lQuery) !== -1
) {
return true;
}
}
}
}
});
return filteredArray;
}
I tried adding an addition else after the date finder and leverage a for() loop on item.tags but it seems typescript doesn't really let you do a traditional for loop.
What is the actual method of handling this within Ang/Typescript?
Update
search(array: any[], query: string, excludeProps?: string|string[], dateFormat?: string) {
if (!query || !this._objArrayCheck(array)) {
return array;
}
const lQuery = query.toLowerCase();
const isoDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/; // ISO UTC
const dateF = dateFormat ? dateFormat : 'medium';
const filteredArray = array.filter(item => {
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (!excludeProps || excludeProps.indexOf(key) === -1) {
const thisVal = item[key];
if (
// Value is a string and NOT a UTC date
typeof thisVal === 'string' &&
!thisVal.match(isoDateRegex) &&
thisVal.toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
// Value is a Date object or UTC string
(thisVal instanceof Date || thisVal.toString().match(isoDateRegex)) &&
// https://angular.io/api/common/DatePipe
// Matching date format string passed in as param (or default to 'medium')
this.datePipe.transform(thisVal, dateF).toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
typeof thisVal === 'string'
) {
for (var i=0; i < item.tags.length; i++) {
if (thisVal === item.tags[i]){
return true;
}
}
}
}
}
}
});
return filteredArray;
}
I was thinking something similar to this but it doesn't seem to be returning anything.
sample Payload
// collection: events
{
"_id" : ObjectId("59dda4b702ac8332bcb90921"),
"title" : "Gantt Chart Example222dsda",
"location" : "Home",
"startDatetime" : ISODate("2018-01-01T12:30:00.000-05:00"),
"endDatetime" : ISODate("2018-01-02T12:30:00.000-05:00"),
"description" : "dsad",
"viewPublic" : true,
"tags" : [
"Gaming",
"Social",
"home",
"misc"
],
"__v" : NumberInt("0")
}
My function should be able to match 'gantt' to the title and still show the row. It should also be able to match 'gaming', 'social' 'home' etc and pull this same record due to the tags. It should be able to pull from the start or end date time.
I'm using $filter to iterate through an array and fetch a specific value
Below is my code:
var selected = $filter('filter')($scope.folders, {url: el.selected[0] });
This code is working, but I got a problem when the url contain an accent and space like so :
/Users/Me/project/products/Poste à souder
In that case the string comparaison isn't working anymore.
What is the cleaner way to solve this situation ?
That true. As a francophone, I've often encounter encoding/decoding issues with angularjs.
The source code of the default filter is as follow
function filterFilter()
{
return function(array, expression, comparator)
{
if (!isArrayLike(array))
{
if (array == null)
{
return array;
}
else
{
throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
}
}
var expressionType = getTypeForFilter(expression);
var predicateFn;
var matchAgainstAnyProp;
switch (expressionType)
{
case 'function':
predicateFn = expression;
break;
case 'boolean':
case 'null':
case 'number':
case 'string':
matchAgainstAnyProp = true;
//jshint -W086
case 'object':
//jshint +W086
predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
break;
default:
return array;
}
return Array.prototype.filter.call(array, predicateFn);
};
}
and the predicate generator stand as follow: it generate the default comparator if the provided one is not a function
function createPredicateFn(expression, comparator, matchAgainstAnyProp)
{
var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
var predicateFn;
if (comparator === true)
{
comparator = equals;
}
else if (!isFunction(comparator))
{
comparator = function(actual, expected)
{
if (isUndefined(actual))
{
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null))
{
// No substring matching against `null`; only match against `null`
return actual === expected;
}
if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual)))
{
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
actual = lowercase('' + actual);
expected = lowercase('' + expected);
return actual.indexOf(expected) !== -1;
};
}
predicateFn = function(item)
{
if (shouldMatchPrimitives && !isObject(item))
{
return deepCompare(item, expression.$, comparator, false);
}
return deepCompare(item, expression, comparator, matchAgainstAnyProp);
};
return predicateFn;
}
Too much speech. You have the choice:
Provide a comparator to your filter see the doc
but remember that you can't define inline function in angular template
you can define a function in that scope, but it will only be available in that scope
You can write your own filter
.filter('myCustomFilter', function()
{
return function(input, criteria)
{
... // your logic here
return ...// the filtered values
};
})
Maybe it's best to write your own filter:
app.filter("customFilter", function () {
//the filter will accept an input array, the key you want to look for and the value that the key should have
return function (array, key, value) {
return array.filter(function(x){
return (x.hasOwnProperty(key) && (x[key] === value));
});
};
});
And use it in your controller like:
$scope.filtered = $filter("customFilter")($scope.folders, "url", "/Users/Me/project/products/Poste à souder");
Check out a working demo here.
im using ag-Grid, but there is a issue when it filters my data, when i filter my data in the price column, it only works with numbers dot and not with commas.
Link: https://plnkr.co/edit/LDdrRbANSalvb4Iwh5mp?p=preview
Practical Example:
In the Price column select box equal and above insert "1.5" and than try inserting "1,5"
This is because this filter is a native one.
If you want to handle custom behaviour, define your own filter.
Documentation : https://www.ag-grid.com/angular-grid-filtering/index.php
A quick and dirty solution would be to monkey patch the NumberFilter like this :
NumberFilter.prototype.doesFilterPass = function (node) {
if (this.filterNumber === null) {
return true;
}
var value = this.valueGetter(node);
if (!value && value !== 0) {
return false;
}
var valueAsNumber;
if (typeof value === 'number') {
valueAsNumber = value;
}
else {
valueAsNumber = parseFloat(value.replace(',','.'));
}
switch (this.filterType) {
case EQUALS:
return valueAsNumber === this.filterNumber;
case LESS_THAN:
return valueAsNumber < this.filterNumber;
case GREATER_THAN:
return valueAsNumber > this.filterNumber;
default:
// should never happen
console.warn('invalid filter type ' + this.filterType);
return false;
}
};
Then changed line is here :
valueAsNumber = parseFloat(value.replace(',','.'));
So i found the problem, first i had to convert the value has a string than i needed to replace the dot by the comma, the problem with the answer above was first because of the data type and than the order of the properties of the replace function, but the problem now is that is not filtering correctly, if i search using equal option if gives me 2 values, instead a fixed one, code looks something like this:
Code:
NumberFilter.prototype.doesFilterPass = function (node) {
if (this.filterNumber === null) {
return true;
}
var value = this.valueGetter(node);
if (!value && value !== 0) {
return false;
}
var valueAsNumber;
if (typeof value === 'number') {
value = value.toString()
valueAsNumber = parseFloat(value.replace('.',','));
}
else {
valueAsNumber = parseFloat(value.replace('.',','));
}
switch (this.filterType) {
case EQUALS:
return valueAsNumber === this.filterNumber;
case LESS_THAN:
return valueAsNumber < this.filterNumber;
case GREATER_THAN:
return valueAsNumber > this.filterNumber;
default:
// should never happen
console.warn('invalid filter type ' + this.filterType);
return false;
}
};
Possible Solution:
NumberFilter.prototype.onFilterChanged = function () {
var filterText = utils_1.default.makeNull(this.eFilterTextField.value);
if (filterText && filterText.trim() === '') {
filterText = null;
}
var newFilter;
if (filterText !== null && filterText !== undefined) {
console.log(filterText);
// replace comma by dot
newFilter = parseFloat(filterText.replace(/,/g, '.'));
console.log(newFilter);
}
else {
newFilter = null;
}
if (this.filterNumber !== newFilter) {
this.filterNumber = newFilter;
this.filterChanged();
}
};
The date field doesn't get validated for a format like 2013-02-13, but it works for 2013-12-12. Leading zero seems to be creating problem in any node form. I have "clientside validation" module on. I couldn't find anything related to this bug/issue anywhere, so I am posting here.
Can anyone help me?
There is issue in clientside validation js due to using of parseInt for validating a month & day value of a date. just replace with it
jQuery.validator.addMethod("dateFormat", function(value, element, param) {
var parts = value.split(param.splitter);
var expectedpartscount = 0;
var day = parseInt(parts[param.daypos], 10);
var month = parseInt(parts[param.monthpos], 10);
month = month - 1;
var year = parseInt(parts[param.yearpos], 10);
var date = new Date();
var result = true;
/* if (day.toString().length !== parts[param.daypos].length){
result = false;
}
if (month.toString().length !== parts[param.monthpos].length){
result = false;
}*/
if (year.toString().length !== parts[param.yearpos].length){
result = false;
}
if (param.yearpos !== false){
expectedpartscount++;
date.setFullYear(year);
if (year !== date.getFullYear()) {
result = false;
}
}
if (param.monthpos !== false) {
expectedpartscount++;
date.setMonth(month);
if (month !== date.getMonth()) {
result = false;
}
}
if (param.daypos !== false) {
expectedpartscount++;
date.setDate(day);
if (day !== date.getDate()) {
result = false;
}
}
if (expectedpartscount !== parts.length) {
result = false;
}
return this.optional(element) || result;
}, jQuery.format('The date is not in a valid format'));