angularJS global filter module - javascript

I am having trouble getting my custom filter to work.
I have a module of global filters:
angular.module('globalFilters', []).filter('dateRange', function () {
return function(item) {
console.log(item);
return true;
}
});
This is injected into my app on creation.
I am trying to apply this to an ng-repeat:
tr.pointer(ng-repeat="asset in completed | dateRange", ng-animate="'animate'", ng-click="selectAsset(asset);")
td {{asset.Name}}
However adding this filter will filter all assets out of table. To try to isolate the problem I am returning true for the function to display all assets but it is not working.
Upon logging item to the console, result appears to be an array of all assets so I guess something is wrong.
I was following this tutorial https://docs.angularjs.org/tutorial/step_09
Thanks!

You are filtering an array...so your filter function needs to return an array.
.filter('dateRange', function () {
return function(itemArray) {
if(!itemArray){
return null
}else{
return itemArray.filter(function(item){
// conditions of filter
});
}
}
});

When you define a custom filter function, the value passed into the filter is replaced by the value returned from the filter, so you are replacing item with true.
For a filter which logs the input without changing it, just return the input:
return function(item) {
console.log(item);
return item;
}

Related

Use promise with angularjs user filter

I have a user filter. You can see the mock example below (it returns the same data which it gets, i.e. users_data_contents, in reality there is the function call):
var appModule = angular.module('appModule', [])
.filter('filter_ghosts', function($rootScope){
return function(users_data_contents){ // gets data from view
return users_data_contents;
};
});
I need to use it in async mode, but not quite understand how. I tried something like this:
var appModule = angular.module('appModule', [])
.filter('filter_ghosts', function($rootScope){
function getPromised(){
var cnt = 0, intrv = setInterval(function() {
++cnt;
if (cnt>10) {
return function(users_data_contents){
clearInterval(intrv);
return users_data_contents;
}
}
if (cnt > 50) {
clearInterval(intrv);
}
}, 100);
}
getPromised.$stateful = true;
return getPromised;
});
But this doesn't work.
The html where the filter is applied looks like this:
<tr ng-repeat="user_data in usersList | filter_ghosts">
....
Can anybody help?
UPD
The most close solution to my issue is here: AngularJS : Asynchronously initialize filter
However, it is turned out that the more appropriate approach is not to use filter at all but bind the repeater to array which is changed on corresponding procedures.
Create an empty array in the scope. Then bind your ng-repeat with filter to that array. Then just fill that array with the values when your async operation completes.

How to show a loading message before filter with AngularJS?

I need to show some "Loading Message" when a filter is about to happen with AngularJS. My filter is fast, so I can't just show it before return the filtered data. My code:
.filter('filterName', function () {
return function (pacotes, escopo) {
var filtered = [];
pacotes.forEach(function (pacote) {
if (condition)
filtered.push(pacote);
});
return filtered;
}
})
What can I do to show some message, div, anything, before return this data?
Somewhere in your html:
<p id="loadingMessage" ng-show="showMessage"></p>
Filter:
.filter('filterName', function () {
$scope.showMessage = true;
$timeout(return function (pacotes, escopo) {
var filtered = [];
pacotes.forEach(function (pacote) {
if (condition)
filtered.push(pacote);
});
$scope.showMessage = false;
return filtered;
}, 3000);
})
I was not able to test this since I don't have all of your code. But something like this should work assuming I have the syntax right. You would have to inject $scope and $timeout in the appropriate places for this to work though.
Edit: I just realized escopo likely means scope in another language. Assuming that is true and you are actually passing in the scope, just put escopo where I have $scope.

Translating non-existent keys with ng-translate

By default, if I try to translate a non-existent key using the $translate service or the translate filter, the key itself is returned.
e.g. $translate.instant('no.such.key') === 'no.such.key'
Is there a way to change this (per-invocation, rather than globally) so that null is returned instead?
Alternatively, does ng-translate provide a more concise way than this to show a translation only if it exists?
<div ng-if="('no.such.key' | translate) !== 'no.such.key')">
{{'no.such.key' | translate}}
</div>
There is a custom error handler where you can control the text that is displayed when the key cannot be found.
https://angular-translate.github.io/docs/#/guide/17_custom-error-handler
I copy and paste below the example from this page.
app.factory('customTranslationHandler', function () {
return function (translationID, uses) {
// return the following text as a translation 'result' - this will be
// displayed instead of the language key.
return 'NO DEFAULT KEY';
};
});
Maybe preferable for you would be to instead silently log missing keys. See https://angular-translate.github.io/docs/#/guide/16_error-handling
Best way to change this per invocation basis is to create a custom filter and translate inside of it.
$filter enables use of all filters within code so we can test the translate return and instead return null. This behavior doesn't override the default translate filter so you can use only where needed.
angular
.module('app')
.filter('translateNull', ['$filter', function($filter) {
return function(value) {
//Store translation to test and return
const tempValue = $filter("translate")(value);
//If translate returns the same key sent we return null
if (tempValue === value) {
return null;
} else {
return tempValue;
}
};
}]);
Source: https://docs.angularjs.org/tutorial/step_11

Vuejs template not updating applying filter to property

I have a simple template that iterates over some items:
<template v-for="card in filteredCards">
filteredCards are a property I am using to filter some results by clicking a simple html link. In my Vue component I have this:
data = {
cards: '',
filteredCards: ''
}
cards is the original data coming via an ajax request - and filteredCards is what I'm actually iterating over.
The problem becomes when I do any kind of update with a filter - the template is not reflecting the filtered array. Here is how I'm filtering:
this.filteredCards = this.cards.filter(function (item)
{
return item.Data.event_type.match('something_test');
});
In devtools I can see that the array has been updated to only a single item - however the template never updates and leaves all the results showing. If I call something that actually mutates the array though like reverse - the template updates just fine. Is there something I need to do in order to force an update after filtering the array?
I've updated a bit to reflect using a custom filter. I'm still running into the same problem. In devtools I see that the filterKey is being updated from an event broadcasted from the parent instance. But nothing is being updated in the template.
var $data = {
cards: [],
filterKey: '',
loading: true
};
Vue.component('cards', {
template: '#card-template',
data: function()
{
return $data;
},
events: {
'updateFilterKey': function(key)
{
this.filterKey = key;
}
}
});
Vue.filter('onlyMatching', function(cards)
{
var $this = this;
return cards.filter(function(item)
{
return item.Data.event_type.match($this.$data.filterKey);
});
});
The code that initially gets the data is just a simple ajax call:
var getFeed = function($url)
{
$.get($url, function(response)
{
$data.loading = false;
$data.cards = response;
}).fail(function()
{
$data.loading = false;
});
};
The strange thing is with this current code - when I click back and forth between sending different keys the actual array items are being duplicated in my template over and over when I click the "all items" which sets the filterKey to an empty string.
What you're doing is absolutely backwards.
You actually want to loop the original array but apply a filter on it.
<template v-for="card in cards | filterBy onlyMatching">
Then, in your code, create a custom filter:
Vue.filter('onlyMatching', function (cards) {
return infoBlocs.filter(function(item) {
return item.Data.event_type.match('something_test');
});
})
This should totally work. Now, whenever the array is changed in any way, the filter will get triggered and the list will be re-rendered.
Come to find out the filtering was working all along. There's an issue with the conditional templating. I'll ask that in another question.

meteor display first element of array in template spacebars

I want to display in my template only the first element of an array. I've seen many topics including this one but it doesn't work in my case.
I have an helper like this:
Template.home.helpers({
posts() {
return Posts.find({});
}
});
I would like to do something like this in my template:
{{posts.[0].title}}
I don't want to use a findOne in this case.
Best to do this at the helper level, for example, this would add an optional index argument to the posts helper:
Template.home.helpers({
posts(index) {
if(typeof index !== "undefined" && index !== null){
var data = Posts.find();
return data[index];
}
else{
return Posts.find();
}
}
});
Then you set the data context and call it in blaze like this:
{{#with posts 0}}
{{title}}
{{/with}}
Just limit the size of the return set:
Template.home.helpers({
posts() {
return Posts.find({}, {limit: 1})
}
});
Of course you'll probably want to sort it by something sensible as well, so that the first record is definitely the one you actually want.

Categories