Duplicate value in javascript array of objects is not recognized by find() - javascript

I am making a bookmark function that looks as follows:
$scope.bookmarkPost = function(bookmark_post){
if(window.localStorage.bookmarks == null) {
user_bookmarks = [];
} else {
user_bookmarks = JSON.parse(window.localStorage.bookmarks)
}
var existing_post = find(user_bookmarks, function(post){ return post.title == bookmark_post.title; });
if(!existing_post){
user_bookmarks.push({
id: bookmark_post.pagid,
title : bookmark_post.title,
date: bookmark_post.created,
room: bookmark_post.room
});
}
console.log(JSON.stringify(user_bookmarks));
window.localStorage.bookmarks = JSON.stringify(user_bookmarks);
};
This should work and indeed adds the post to a my array of objects if it allready exists, and then puts it in localstorage. As you can see I'm trying to check if there's allready an entry with the same title like this:
var existing_post = find(user_bookmarks, function(post){ return post.title == bookmark_post.title; });
To be 100% honest I'm not even 100% sure what this does, but I couldn't find anything else on my particular subject. This check doesn't work and thus there are duplicate entries. Does anyone know how it can be fixed?

You probably meant to use the Array.find() method:
var existing_post = user_bookmarks.find(function(post){
return post.title === bookmark_post.title; //use === for strict comparison
}); //will return only first element that matches the callback criteria
Quick note: Array.find() is not supported by IE

Related

Find texbox value match in an array

I am trying to look for texbox values matching an array I have provided a code snippet below:
$('#message').on('keyup', function () {
suggest_array_sample = [
{ array_val: "#{person1}" },
{ array_val: "#{person2}" },
{ array_val: "#{person3}" }
];
found_variable_array = [];
$.each(suggest_array_sample, function (key, value) {
console.log(value);
if ($.inArray(value, textbox_value)) {
console.log('found');
found_variable_array.push(value);
} else {
console.log('not found');
}
})
console.log(found_variable_array);
});
<textarea id="message"></textarea>
The problem is it always return the whole array instead of just the matches the ouput should be when I type #{person1} on the textbox the output should be
[{array_val:"#{person1}"}] //expected output
[{array_val:"#{person1}"},{array_val:"#person2"}]// expected output when two or more matches are found on the textbox
instead of
[{array_val:"#{person1}"},]{array_val:"#{person2}",{array_val:"#{person3}"}] //current output
is this possible using the inArray() or do I need to change the code.
use filter method of Array.
yourArray.filter ( yourArrayModel => yourArrayModel.fieldValue === yourSearchValue )
In your case yourSearchValue can be “{#person1}”
For more information, look for filter method documentation, i hope this is what you want.
$.inArray return a position, if not found return -1 else return >= 0
The $.inArray() method is similar to JavaScript's native .indexOf()
method in that it returns -1 when it doesn't find a match. If the
first element within the array matches value, $.inArray() returns 0
Try this code
$('#message').on('keyup', function () {
textbox_value = $(this).val();
suggest_array_sample = ["#{person1}", "#{person2}", "#{person3}"];
console.log($.inArray(textbox_value, suggest_array_sample));
});
It's not entirely clear what you're trying to achieve. I've written something using $.inArray that tells you the array index of the found value. You need to use .map() on the array to extract the val you want.
EDIT:
From what I understood of your comment, I've now had the value be added to found_value_array each time the value is found.
Or is it that you want an array to be returned because the same value might appear multiple times?
let found_variable_array = [];
$('#message').on('keyup',function(){
suggest_array_sample = [
{array_val:"#{person1}"},
{array_val:"#{person2}"},
{array_val:"#{person3}"}
]
let index = $.inArray($(this).val(), suggest_array_sample.map(o => o.array_val));
if (index >= 0) found_variable_array.push(suggest_array_sample[index]);
console.log(found_variable_array);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="message"></textarea>
After combining ideas presented here this method work for me
match_value = suggest_array.filter(function(result){
if(textbox_value){
return textbox_value.search(result)>-1
}
else{
return false
}
})
console.log(match_value);

Filter an array of nested objects

I have an array of nested objects and I have a user, which searches for a room
Here is an array of objects.
I would like to filter an array as soon as user types something
I tried a lot of functions, but nothing worked for me, here is the last example, which failed
search(val: any) {
// if input is clear - show everything, what we have
if (val === '') {
this.roomList = this.roomList;
} else {
//choose the object (objects) where rName = val
this.roomList = this.roomList.staticData.rName.filter(function(o) {
return Object.keys(o).some(function(k) {
return o[k].toString().toLowerCase().indexOf(val) != -1;
})
});
}
}
Could you please help or give me a hint?
You need to apply Array.filter() on roomList instead of staticData propety
this.roomList = this.roomList.filter(function (r) {
return r.staticData.rName.toLowerCase().indexOf(val.toLowerCase()) != -1
});
this.roomList = this.roomList.staticData.rName
This is a wrong starting point, just look at it. Then, rName is not an array, so you can't invoke .filter on it.
Here's how to do it :
this.roomListFiltered = this.roomList.filter(o => new RegExp(val,"i").test(o.staticData.rName) )
new RegExp(val,"i") performs a case-insensitive match.
Also, store the result of the filter in a different variable, otherwise you will lose your original list as it gets filtered out.

How to check if an Object already exists in an Array before adding it?

I have this algorithme issue, I would like to check if an Object is already present in my Array before adding it.
I tried many different approaches (indexOf, filter...), and my last attempt is with an angular.foreach.
The problem is my $scope.newJoin remains always empty. I understood why, it's because the if is never read, because of the 0 size of my $scope.newJoin, but I don't know how to figure this out...
$scope.newJoinTMP is composed by : 6 Objects, within each a timePosted attribute (used for compare these different array Objects).
$scope.newJoin is an empty Array. I want to fill it with the Objects inside $scope.newJoinTMP but with the certainty to have once each Objects, and not twice the same ($scope.newJoinTMP can have duplicates Objects inside, but $scope.newJoin mustn't).
angular.forEach($scope.newJoinTMP, function(item)
{
angular.forEach($scope.newJoin, function(item2)
{
if (item.timePosted === item2.timePosted)
{
//snap.val().splice(snap.val().pop(item));
console.log("pop");
}
else
{
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
}
});
});
if(!$scope.newJoin.find(el=>item.timePosted===el.timePosted){
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
}
You dont want to push inside an forEach, as it will push multiple times...
There might be better ways to handle your particular situation but here's a fix for your particular code.
Replaced your inner for each with some which returns boolean for the presence of element and by that boolean value, deciding whether to add element or not
angular.forEach($scope.newJoinTMP, function(item)
{
var isItemPresent = $scope.newJoin.some(function(item2)
{
return item.timePosted === item2.timePosted;
//you dont need this conditional handling for each iteration.
/* if (item.timePosted === item2.timePosted)
{
//snap.val().splice(snap.val().pop(item));
console.log("pop");
}
else
{
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
} */
});
if( ! isItemPresent ) {
$scope.newJoin.push(item);
} else {
//do if it was present.
}
});
If you want to avoid the nested loop (forEach, some, indexOf, or whatever) you can use an auxiliar object. It will use more memory but you will spent less time.
let arr = [{ id: 0 }, { id:0 }, { id: 1}];
let aux = {};
const result = arr.reduce((result, el) => {
if (aux[el.id] === undefined) {
aux[el.id] = null;
return [el, ...result];
} else {
return result;
}
}, []);
console.log(result);
You can use reduce
$scope.newJoin = $scope.newJoinTMP.reduce(function(c, o, i) {
var contains = c.some(function(obj) {
return obj.timePosted == o.timePosted;
});
if (!contains) {
c.push(o);
}
return c;
}, []);
The problem with your current code is, if newJoin is empty, nothing will ever get added to it - and if it isnt empty, if the first iteration doesn't match the current item being iterated from newJoinTMP - you're pushing.

Compare Objects in Array and Remove Duplicate & Update - Javascript

I have an array of objects that presents as follows:
0: Object
ConsolidatedItem_catalogId: "080808"
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "Test Catalog Item"
ConsolidatedItem_imageFile: "27617647008728.jpg"
ConsolidatedItem_itemNumber: "1234"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "CAT"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
1: Object
ConsolidatedItem_catalogId: ""
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "ALARM,SHUTDOWN SYSTEM,AXIOM,XP3, 0-1500 PSIG, HIGH AND LOW PRES Testing"
ConsolidatedItem_imageFile: ""
ConsolidatedItem_itemNumber: "10008"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "INV"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
I'm trying to update and remove an object if it's added again, or update the object. Preferably update the object with the new value. My code is as follows:
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
console.log(result);
if (result.length == 0) {
finalObject.push(o);
shoppingCounter = finalObject.length;
$('#numberShoppedItems').text(shoppingCounter);
console.log(finalObject);
} else if (result.length == 1) {
finalObject.filter(function(x){
result = x;
console.log(result);
return x == result.ConsolidatedItem_itemNumber;
});
} else {
alert('Multiples Found');
}
}
I've tried multiple ways of getting the exact object and manipulating the data, however they've all failed. I would prefer to update the object, say if CatalogItem_itemNumber held the same value, if the CatalogItem_quantity was different - add the CatalogItem_quantity values together and update the array of objects.
I don't need an exact answer, a nudge in the right direction would do wonders though. I've looked at several of the related questions over the past couple of hours but none of them seem to address the issue. If you know of a question that has an answer, feel free to just link that as well. I may have missed it.
No Underscore.js please
When you find the matching record, you may update it by using $.extend
$.extend(result[0], o)
This will update the object in finalObject array in-place.
Alternatively, if you want to use the filter, you will need to insert the new object in the array.
finalObject = finalObject.filter(function(x) {
return x !== result[0];
});
finalObject.push(o)
Here we are allowing all the records that are not not equal to result to be returned in the resultant array that is received in finalObject. In next line, we are adding the new record.
Solved in the following manner:
1.) Verify object is not empty.
2.) Use .some() on object to iterate through it.
3.) Check if the finalObject, which is now e, has a match for the key in my temporary object I assemble, o.
4.) Update the values that need updating and return true;
Note: Originally I was going to remove the object by its index and replace it with a new object. This too can work by using .splice() and getting the index of the current object in that array you're in.
Here is the updating version:
if (o.ConsolidatedItem_quantity != '') {
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
if (result.length == 0) {...}
else {
finalObject.some(function (e) {
if(e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber){
var a;
a = +e.ConsolidatedItem_quantity + +o.ConsolidatedItem_quantity;
e.ConsolidatedItem_quantity = a.toString();
document.getElementById(o.ConsolidatedItem_itemNumber).value=a;
return true;
};
});
}
}

Filter a collection of objects to take an array of values

Actually the question is related to typeahead bootstrap
because I need to define an array of values to show in input text by using autocomplete.
Anyway, the goal is just to define a function which read an array of objects and return an array of string.
Here is my code(1).
The goal of (1) is:
1) get an array of strings from an array of objects.
2) filter this array rejecting some elements.
It does not work because the element I want to reject persists in the array.
In fact in the autocomplete I get false value, actually it brokes the code because false is not expected by typeahead.
How should fix the code and maybe improve it?
(1)
element.typeahead({
source: function ( {
var users = _.map(app.userCollection.models, function (model) {
if (model.get('id') === app.currentUser.id) {
return false;
}
return model.get('first_name') + ' ' + model.get('last_name');
});
console.log(users); // [false, 'some name'];
_.reject(users, function(name) {
return name === false;
});
console.log(users); // [false, 'some name'];
// why does the false value persist?
return users;
}
});
Underscore methods don't usually operate on the array itself, but they return a new array, but I suggest checking the underscore docs on each function individually for confirmation. In this case we can safely assume that reject returns some new array, according to this sentence in the underscore docs:
Returns the values in list without the elements that the truth test (iterator) passes.
What you are currently doing is:
_.reject(users, function(name) {
return name === false;
});
So, you don't actually save your results anywhere. To preserve a reference to the array without the unwanted elements do this:
users = _.reject(users, function(name) {
return name === false;
});
That would yield the result you want, but let me give you a refactoring hint:
Use backbone's own methods as far as you can, it'll make for more readable code
source: function() {
// filter the collection down to the users you want
var users = app.userCollection.filter(function(model) {
return model.id === app.currentUser.id;
});
// -> users is now an array of models
// use map to transform each wanted user to a string giving its full name
users = _.map(users, function(user) {
return user.get('first_name')+' '+user.get('last_name');
});
// -> users is now an array of strings
return users;
}
Hope this helps!

Categories