Why is this array not empty? - javascript

I trying to show a message in an array is empty in a filter method in Vue.
However, it seems my computed function still returns an array of empty object (If I search for something not there)
What I wish is that it only returns the object that actually has a value - the empty ones should be filtered out?
So if I search for "fjhdsfjsdfjsd" ex, it still return about 200 items, just empty objects, which it shouldnt?
The computed function looks like:
filteredAlarms: function () {
let filter = {};
let searchString = this.search_string.toLowerCase();
Object.keys(this.eventLog).forEach(key => {
filter[key] = this.eventLog[key].filter(item => {
let systemName = item.system_name.toLowerCase();
if(item.type.includes("alarm") && systemName.includes(searchString)) {
return item;
}
});
});
return filter
},

Array.prototype.filter must return a boolean. Just remove the if and the return item part and just return your if condition:
filteredAlarms: function () {
let searchString = this.search_string.toLowerCase();
let eventKeys = Object.keys(this.eventLog);
return eventKeys.reduce((filter, key) => {
let items = this.eventLog[key].filter(item => {
let systemName = item.system_name.toLowerCase();
return item.type.includes("alarm") && systemName.includes(searchString);
});
return Object.assign(filter, { [key]: items });
}, {});
}

Try this one. I hope this will work.
filteredAlarms: function () {
let filter = {};
let searchString = this.search_string.toLowerCase();
Object.keys(this.eventLog).forEach(key => {
filter[key] = this.eventLog[key].filter(function(item){
return item.type.includes("alarm") && item.system_name.toLowerCase().includes(searchString);
});
});
return filter
},

Related

Lodash : _Filter, but returns an array of objects with specific keys

Im making a function which compares two arrays of objects and returns two subset arrays of objects. The first returned array being a set of objects which were not included within the array passed within the second prop, and the second returned array being a set of objects which were not included within the first array but are now included within the second.
This works, however, i want to add an extra functionality to return the second array with specific keys. Is there anyway to utilise lodash "pickBy" functionality within the filter function, or will i have to create an extra recursive section?
function extract_removed_new (before, after, matching, pickBy = []) {
let before_ = cloneDeep(before)
let new_ = _.filter(after, (item) => {
let index_ = _.findIndex(before_, function (i) {
return _.get(i, matching) == _.get(item, matching)
})
if(index_ !== -1) {
before_.splice(index_, 1)
return false
}
if(pickBy.length > 0) {
return _.pickBy(item, function(value, key) {
if(key in pickBy) {
return true
}
});
}
return true
})
return [before_, new_]
}
Using lodash compact, with map I was able to get exactly what I needed.
function extract_removed_new (before, after, matching, pickBy = []) {
let before_ = cloneDeep(before)
let new_ = _.compact(_.map(after, (item) => {
let index_ = _.findIndex(before_, function (i) {
return _.get(i, matching) == _.get(item, matching)
})
if(index_ !== -1) {
before_.splice(index_, 1)
return false
}
if(pickBy.length > 0) {
return _.pickBy(item, function(value, key) {
if(pickBy.includes(key)) {
return true
}
});
}
return item
}))
return [before_, new_]
}

My filter is returning the whole object and not just the property

I want to return an array of ids, but the whole object is being returned.
Do I have the correct syntax?
const docIds = this.claim.claimDocuments.filter(doc => {
if (doc.status !== 'Submitted') {
return doc.id;
}
});
filter doesn't change the array, it just selects the entries which pass the logical test. You then need to map the output of filter to return only the id values:
const docIds = this.claim.claimDocuments
.filter(doc => doc.status !== 'Submitted')
.map(doc => doc.id);
If you want to create an array from a portion of items in another while also transforming each passing item into something else, you'll have to use a different method, perhaps by initializing the array, then pushing inside the if while iterating:
const docIds = [];
for (const doc of this.claim.claimDocuments) {
if (doc.status !== 'Submitted') {
docIds.push(doc.id);
}
}
Or with .reduce:
const docIds = this.claim.claimDocuments.reduce((a, doc) => {
if (doc.status !== 'Submitted') {
a.push(doc.id);
}
return a;
}, []);
Or with .filter followed by .map, though this requires iterating over some items twice.

Delete object from array of arrays

I just want to delete the specTplItemDropped() function parameter item from this data structure:
this.areas:
items:
item:
code:
public specTplItemDropped(index, item, external, type, area1) {
let newArray = this.areas.map(areaV => {
let a = areaV.items.filter(itemV => {
let b = itemV.id !== item.id;
return b;
});
return a;
});
console.log(newArray);
The new array should be the same as the old array, minus one item. But it is very different:
What am I doing wrong?
The input is an array of objects, but you're returning an array rather than an object from the .map() call. You need to return a copy of the original object, with the new array of items.
function specTplItemDropped(index, item, external, type, area1) {
let newArray = this.areas.map(areaV => {
let a = areaV.items.filter(itemV => {
let b = itemV.id !== item.id;
return b;
});
return Object.assign({items: a, itemCount: a.length}, areaV);
});
console.log(newArray);
}

How do I allow an empty result in my filter?

I filter the elements of an array using this function:
function filter(arr, criteria) {
return arr.filter(function(obj) {
return Object.keys(criteria).every(function(c) {
return obj[c] == criteria[c];
});
});
}
var newarr = filter(arr, { desc: dv, aasc: av, rev: cv, flo: acv });
However, if the user doesn't input anything, then the results will return nothing. I am trying to code it so that if they choose nothing for that specific criteria, then it won't filter it.
Maybe I'm not getting it, but wouldn't you just check for empty values
function filter(arr, criteria) {
return arr.filter(function(obj) {
return Object.keys(criteria).every(function(c) {
return !(criteria[c]) || obj[c] == criteria[c];
});
});
}
You could just check the criteria for any value ?
function filter(arr, criteria) {
if(criteria)
{
return arr.filter(function(obj) {
return Object.keys(criteria).every(function(c) {
return obj[c] == criteria[c];
});
});
}
else
{
return error of some kind.
}
}
Or you could add a check for null input on the filter input...
I am trying to code it so that if they choose nothing for that specific criteria, then it won't filter it.
Then do that. Get the filters as an object from user inputs, or null if no filters are provided then just do something, like this:
var userFilters = ... // get filters
var newarr = userFilters ? filter(arr, userFilters) : arr;
If for some reason this doesn't work for you, you could always rewrite your filter method like this:
function filter(arr, criteria) {
if (criteria)
return arr.filter(function(obj) {
return Object.keys(criteria).every(function(c) {
return obj[c] == criteria[c];
});
});
else
return arr;
}
However, from your comments, it seems like what you mean is simply that if a value is not provided, you'd like to not apply that filter, but that other filters would still apply. In that case your current code works, just change how you're generating the filters object:
var userFilters = {};
if (dv) userFilters[desc] = dv;
if (av) userFilters[aasc] = av;
if (cv) userFilters[rev] = cv;
if (acv) userFilters[flo] = acv;
var newarr = filter(arr, userFilters);
This works because it only adds elements to the filter collection when they're specified. If no items are added, the then arr is returned unmodified.

How to refer Knockout.js objects and array of objects in right context

I canĀ“t seem to get this right: http://jsfiddle.net/dPyQy/4/
I want to collect the tags I am entering in the input field for saving. I need to reference the Textbatches as a SelectedText as in RL I need to be able to choose among Textbatches.
var Textbatch = function (data,tags) {
var self = this;
self.TextbatchId = data.TextbatchId;
self.Title = ko.observable(data.Title);
self.Text = ko.observable(data.Text);
self.TextTags = ko.observableArray(tags);
function createTypeComputed(tagType) {
return ko.computed(function () {
return ko.utils.arrayFilter(self.TextTags(), function (item) {
return item.Type() == tagType;
});
});
}
self.managerTags = createTypeComputed(0);
self.removeTag = function (tagToRemove) {
self.TextTags.remove(function (item) {
return item.Id == tagToRemove.Id;
});
}
}
Struggling with the contexts and the objects and everything. I want the chosen tags listed beneath the input-field, and then the debug to show the updated object.
Any help highly appreciated. Thanx.
managerTags evaluates to an array, but you're using it in a text binding which is expecting it to evaluate to a string.
How do you want to display it? As an HTML list (use a foreach binding to loop over the tags), or as a comma (or something)-separated string (use join on it)?
To get a comma-separated string, change createTypeComputed to
function createTypeComputed(tagType) {
return ko.computed(function () {
return ko.utils.arrayMap(
ko.utils.arrayFilter(self.TextTags(), function (item) {
return item.Type() == tagType;
}),
function (item) {
return item.Name();
}).join(',');
});
}
Note that if you can count on using an ES5 browser (anything but IE<9) you can simplify the function for the computed to
return self.TextTags().filter(function (item) {
return item.Type() == tagType;
})
.map(function (item) {
return item.Name();
})
.join(',');

Categories

Resources