I am developing a React Native App. In my Code i am fetching data from server. This data is used in my ListView which parameter is dataSource. This code works actually. Now i wanted to fill the array with data, only when the values doesn´t exists yet.
So: Push Value to Array, if index is bigger than -1:
if (friendsArray.indexOf(x.id) > -1) {
friendsArray.push(x);
self.setState({
dataSource: self.state.dataSource.cloneWithRows(friendsArray)
});
}
In my debugger i see that, the Line:
friendsArray.push(x);
Will be skipped everytime... Any ideas?
I believe you have two errors here.
First, if you want to execute the push when an item is not in the array, you'll want to do friendsArray.indexOf(x.id) == -1. Checking for > -1 is checking that the item already exists in the array.
Second, you're checking if x.id is in the array, but then pushing x. You probably mean to either be checking if x is in the array, or pushing x.id? If the former (you want to check if x is in the array), you'll need a different solution as objects in javascript will always fail an equality comparison. You would instead probably want to do something like check if any of the objects in friendsArray have an id that matches the id of the object you're trying to push. That could be accomplished with something like this:
if (friendsArray.filter(function(a) { return a.id == x.id; }).length == 0) {
// friendsArray does not contain an object with that id
}
Related
I have a vue application that gets a set of objects from an external REST API.
In a component, I sort and filter the object into an array of objects based on a field called rank, like this:
let myResults = _.orderBy(this.search_result, 'rank', 'desc').filter(service => (service.rank >= 5) ? service: "");
I then need to move a single element/object to the end of the list before rendering it, however, when I tried to do this:
let index = myResults.findIndex(e => e.name === 'Target Element');
myResults.push(myResults.splice(index,1));
It didn't work; It pushed an empty element back to the list. Eventually, I got it working by doing the following:
myResults.push(myResults.splice(index,1)[0]);
I noticed the splice was creating an array that looked like [object, object] with all the target object in the zero index object.
I don't really understand why this happened. Have I done something to the original object somewhere or is this a vue thing?
JavaScript Array.prototype.splice() returns an Array.
Return value
An array containing the deleted elements.
If only one element is removed, an array of one element is returned.
If no elements are removed, an empty array is returned.
Since an Array is returned, you're .push()-ing and Array into an existent array. As you noticed correctly, you need to extract that one Object using removedItems[0], making
myResults.push(myResults.splice(index,1)[0]);
or equally
// Remove from array 1 item
const removedItems = myResults.splice(index, 1); // Array of removed items
// Get the first Object from array
const item = removedItems[0]; // Object
// Append one Object
myResults.push(item);
the correct approach.
I learn Javascript and read and understand how the includes works to test if a value exists in an array.
My problem comes when I have an Array of items that look like this this:
state = { focused: null, files: [] };:
The image show this here:
When I add a new newFile and it's the same it should not add it ok but the evaluation,
if (newFile && !files.includes(newFile)) {.. always say false so how to test for this do I have to test on individual values inside newFiles?
Array.includes will not do a deep comparison between object, only a shallow one comparing references. This way even objects that have same values they would fail on test because they have different references.
In your case you could compare id, which should be unique for each object. You can use Array.every that checks if all values pass in the test. This way you want to check that every file id doesn't match newFile id:
if (newFile && files.every(({id}) => newFile.id !== id))
Array.includes does reference comparison for Array or Object, so instead you can use Array.filter
if (newFile && newFile.filter(e => { /*Comparison logic */ }).length > 0)
I am using this handy function:
function not(a, b) {
return a.filter((value) => b.indexOf(value) === -1);
}
Then I have this
let AvailableList = not(FullList, MyList);
If I were to give example of first element in MyList and FullList it is:
appName: "MyAppName*"
description: null
permissionID: MyAppID*
permissionName: "MyAppPermName*"
__proto__: Object
So initially AvailableList is full of items like above. When user makes selection and saves it I save it into MyList. So then I need to use this not function to calculate remaining parts from MyList. But even when I move the first item of AvailableList to MyList then check like if(AvailableList === MyList) console.log(true) else console.log(false) I get false. But if I console log both of the array's first items they print identical values. I tried to compare after declaring variables using Object.assign() as well but no help.
Perhaps I can tackle this easily checking a value like permissionID, but I do not want to go that route since there will be other items later on that won't have permissionID.
If you know of a different function that can do a better job, feel free to share. Please don't share library solutions like Lodash.
*entries are masked
I'm looking for an efficient way to test whether or not a JavaScript object is some kind of ordered object. Hopefully someone knows a trick that doesn't involve writing some huge type assessor function. Fortunately, I don't have to deal with IE < 9 so most of the newer methods are OK.
The fundamental problem is this: I need to figure out whether or not to run a for loop or a for...in loop on an object. However, I don't always know if the object is going to be an object literal, an array, a jQuery object, etc.
Here are some of the obstacles I'm running up against:
I clearly can't only use typeof because both arrays and objects return object.
I clearly can't only use Object.prototype.toString.call(collection) because, while arrays do return [object Array], custom ordered collections such as jQuery objects still return [object Object] and the whole reason I want this test is to determine whether I need a for loop or a for...in loop. Using a for...in loop on a jQuery object includes properties that aren't actually part of the collection and messes things up.
I did come up with one idea that looks like this:
function isOrdered(item) {
// Begin by storing a possible length property
// and defaulting to false for whether the item
// is ordered.
var len = item.length, isOrdered = false;
// Functions are an easy test.
if (typeof item === 'function') {
return false;
}
// The Arguments object is the only object I know of
// with a native length property that can be deleted
// so we account for that specifically too.
if (Object.prototype.toString.call(item) === '[object Arguments]') {
return true;
}
// Attempt to delete the item's length property.
// If the item is ordered by nature, we won't get
// an error but we also won't be able to delete
// this property.
delete item.length;
// So if the length property still exists as a
// number, the item must be an ordered collection.
if (typeof item.length === 'number') {
isOrdered = true;
}
// If we originally stored a custom length property,
// put it back.
if (len !== undefined) {
item.length = len;
}
// Return the result.
return isOrdered;
}
So far this technique has passed all of my tests but I'm worried about possible performance hits that could arise from deleting properties on custom objects and I'm not 100% confident I'm not missing something. Does anyone have any better ideas?
You can do something like this:
function isOrdered(item) {
var len = item.constructor.prototype.length;
return len === +len;
}
If 'item' is a js object this will evaluate to false but if it's an array or jQuery collection this will return true.
Note that things other than arrays can have numeric length properties (try checking the length of a function). If you might pass things like integers or functions you will need to do something more complicate, but this should catch all the cases you catch in your posted code. Also, I think deleting the length property can have unpredictable results so I would avoid that approach in favor something that does not mutate the object you are testing.
If your trick is working in Firefox, Chrome, and recent IE, I think it's probably okay....though a bit wonky.
Delete goes through and deletes the key and value from an object, rather than just clearing the reference. It will actually return false if it cannot delete the property, so you could tighten up your logic a bit further.
There's a bit of performance overhead to property deletion, and it does some weird stuff to regular objects currently in memory [see this article], but negligible depending on the browser. It really depends on how many collections you'd be doing this on at a time. For a single array/object/mystery, I think it would be fine. But for a nested collection of thousands of arrays, you might want to look into some other alternative.
Here's a JS perf if you're primarily concerned with performance:
http://jsperf.com/delete-vs-undefined-vs-null/3
update
Alternatively, if you are concerned with Jquery collections vs arrays, you could do something like the following:
if (foo.length != undefined) {
if (Array.isArray(foo)) {
// regular array. Could also do
// foo instanceof Array
}
else if(foo.constructor.toString().match(/jQuery/g)) {
// jquery collection
}
} else {
// not an ordered collection
}
I have some simple Javascript looping through an array of items (Tridion User Groups) to check if the user is a member of a specific group.
I can easily code around the issue shown below ( see && extensionGroup !== 'true') but I want to understand why the isArray = true is counted as a value in the array - any ideas?
The screenshot below demonstrates that the value extensionGroups has been set thus
var extensionGroups = ["NotEvenARealGroup", "Author", "ExampleGroupAfterOneUserIsActuallyIn"];
but returns the isArray value as a 4th value?
updated to show images a little clearer
You're using for in to iterate an array; don't do that. Use for (or forEach):
for(var i = 0; i < extensionGroups.length; i++) {
var extensionGroup = extensionGroups[i];
// ...
}
The reason this fails is because for in is used to iterate over an object's properties in JavaScript. Iterating over an array in this way means you get anything else assigned to it, such as this property or length.
And if you're able to use Array#forEach, it's probably most appropriate here:
extensionGroups.forEach(function(extensionGroup) {
// ...
});
For..in, technically speaking, doesn't iterate through values. It iterates through property names. In an array, the values ARE properties, under the hood. So when you iterate over them with for..in you get funky stuff like that happening.
Which highlights my next point: don't use for..in. Don't use it for arrays -- don't use it for anything, really. Ok -- maybe that's going a bit too far. How about this: if you feel the need to use for..in, think hard to see if it's justifiable before you do it.