Splice on copied array removes object from parent / master array - javascript

I have what you may call a parent array, a master array. On page load, a json_encoded PHP array containing information about every user on the site is assigned to a JS variable - var all_users = <?php echo $users;?>;. A console.log of this array looks like this...
[Object, Object, Object, Object, Object, Object, Object, Object, Object]
0: Object
user_id: "4"
registered: "2015-02-15 12:54:34"
...etc
1: Object
user_id: "5"
...etc
In an external .js file I have a few event handlers for various filtering options. At the moment these filters work by sending an AJAX request to the server, querying the database, and then returning the data. This is great, but it's unnecessary to query the database every single time (there will only be around 50 records) hence changing my approach to the JS array.
My solution therefore was to start by copying the contents of all_users to a new variable, display_users, every time the function below is called (so that to reset display_users to contain all users). The purpose of this new variable is to then be able to remove any records that do not match the user's filters. So for example a search for user_id = 4 would result in the second, third, fourth, ... objects being removed from display_users, leaving just those that match.
var display_users = [];
function update_users (type) {
display_users = all_users;
i = 0;
$.each(all_users, function() {
var user = this;
$.each(user, function(k, v) {
// show_admin_only is true or false
if (show_admin_only) {
// if the key is_admin has a value of 0 they are not an admin, remove them from the display users array
if (k == 'is_admin' && v == 0) display_users.splice(i,1);
}
});
i++;
});
// pass the array through to a jQuery template
}
The problem, however, is that the splice is causing an error. The first time the function is ran all is great, however on the second time Chrome reports two warnings, 'window.webkitStorageInfo' is deprecated. Please use 'navigator.webkitTemporaryStorage' or 'navigator.webkitPersistentStorage' instead. and 'webkitIndexedDB' is deprecated. Please use 'indexedDB' instead.. After these errors, any future runs of that function results in the removal of records from both arrays, the master and the copy.
Given this, I'd guess that display_users is acting as a pointer to the master array, all_users, but then that wouldn't make much sense to me, and is why I'm now at a complete loss. A console.log of both arrays after i = 0 outputs this...
Run 1
[Object, Object, Object, Object, Object, Object, Object, Object, Object]
[Object, Object, Object, Object, Object, Object, Object, Object, Object]
Run 2
[Object, Object, Object, Object, Object, Object, Object, Object]
[Object, Object, Object, Object, Object, Object, Object, Object]
// for every run, -1 Object from BOTH arrays
I added a console.log(user); within $.each(user, function(k, v) { and it is during these second, third, ... runs that it begins to output hundreds of Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…} as well as those expected, such as Object {user_id: "4", registered_date: "2015-02-15 12:54:34" ... }.
Has anyone any idea why this is happening? Sorry for the long post for what is probably a very simple fix...!

For duplication use:
display_users = all_users.slice();

Your problem is right here
display_users = all_users;
It is not copying the array but creating one more reference to the same array. If you wish to copy the array you ca use Array.slice() instead
var display_users = all_users.slice(0);

Related

Arranging array of nested objects by one of the nested variables - Angular JS

I am using Angular JS to provide output for an endpoint, the logic to achieve this output is created in the controller as follows:
myApp.controller('AnalyticsController',['$scope','$rootScope','$location','token_service','api_service',function($scope,$rootScope,$location,token_service,api_service){
var analytics = api_service.get_analytics()
analytics.then(function(response){
$scope.analytics = response;
$rootScope.spinner = false;
})
}])
Please note: get_analytics is from another script and the data comes from that service.
The output I get is a nested object, in the console it looks like as follows:
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
0:Object
Devices:Array[1]
Id:"eefd439f-1e2e-481e-815d-0a2ce9a38bbe"
KeyHolderDeviceConfiguration:null
Name:"Shaun m "
Photos:null
Type:2
__proto__:Object
1:Object
2:Object
There are more objects in the list but I figure there's no point opening them as is just repetition.
I wish to separate each nested object in the actual output, so there is one set of results for each 'Name'. Any idea how I would go about doing this?
I saw a similar problem - AS3 - Sorting an array of nested arrays - but I am unsure how to apply this to my problem. Any ideas? Many thanks in advance.
When you use .then the response contain more than property
you should assign data like this
$scope.analytics = response.data;

search for word or phrase in array element and return results using .filter

I'm trying to filter an array by a user defined word so that it acts like a search. This might not be the way to go about it but I've never created a search before and it semms logical and fast. I have a an array 'dataset' containing my data in various object. it looks like this:
dataset [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
Each object contains the following:
commenturl: "http://blogs.ft.com/businessblog/2013/12/"
definition: "To fire someone."
sourceurl: null
submisiondate: "02/11/2015"
usagesource: "HSBC"
phrase: "Transition out of the company"
wordid: "word001"
wordtype: "Verb"
I have an input form that when its changed returns its value to the variable 'lookup'. So if I type the word 'company' into the form then lookup='company'
I would then like to filter my dataset of objects on the element called 'phrase' to another array called 'results'. In the example above the element phrase='Transition out of the company' and as it contains the word 'company' which is the same as 'lookup' it should return the whole object to the results array.
In the second object of the array dataset the eleement phrase='Demise' so I would not expect this to be returned
Trying to do something like this but doesn't seem to work. Any help appreciated
var lookup=String(this.value)
console.log("search",lookup);
var results=dataset.filter(function(el){return el.word.text.indexOf(lookup) > -1)});
console.log("results",results);
There seemed to be an unmatched bracket, this now works
var lookup=String(this.value)
console.log("search",lookup);
var results=dataset.filter(function(el){
return (el.word.indexOf(lookup) > -1)
});
console.log("results",results);

Create Object in Object

I'm confuse the way how Google Chrome developer tool console is displaying if the (A) is the actual object created in the loop, why are the (B) contains 3 objects?
Does it means (A) will contain 3 objects?
Demo: https://jsfiddle.net/LygmkgLm/
var test={}
for(var i=0;i<3;i++){
test[i]={}
test[i].y="111"
console.log("test",test)
}
You're misinterpreting the console output. It correctly and and as expected shows the increasing contents of the object within the loop, hence the 1, 2 and 3 members in the output. At the end however the variable 'test' is the fully filled object, and when you expand the first line it shows the contents at the time of expansion. Being the fully filled object with 3 children.
Your confusion arises from the fact that the logging does not store the state of the object at logging time.
Chrome console shows the final object in console. It shows whatever the values have gone through the object. So in console first it will show you
test Object {0: Object}
But when you extend, it will have three object which has passed through it.
test Object {0: Object}0: Object1: Object2: Object__proto__: Object
One thing to note that, at first iteration of the loop, you may see three object in console but only one object i.e.
test Object {0: Object}
is actually accessible. If you want to check actual state of object in each iteration, you have to clone it like below
var newObject = jQuery.extend(true, {}, test);
Here is the fiddle which will give you an idea of my points https://jsfiddle.net/qtdurtzc/

JavaScript objects from Eloquent JavaScript Chapter 4

JSFiddle: http://jsfiddle.net/TkV2y/3/
var chineseBox = {}; //create an object
chineseBox.content = "chineseBox"; //put a key/value pair inside chinesebox
alert(chineseBox); // why does the alert display { Object object }?
alert("content" in chineseBox); //returns true, as expected
alert("content" in chineseBox.content); //why does this alert not show up??
My questions are:
Why, when I do alert(chineseBox), do I not get the contents of the chineseBox object? I'd expected to see this:
{content: "chineseBox"}
Instead, I got [object Object] in the alert.
Why does the third alert I have there—alert("content" in chineseBox.content);—not show up?
That is the default .toString() implementation for objects in most JavaScript engines. To see the contents of the object, try: alert(JSON.stringify(chineseBox));
If you check the browser console, you'll find a type error. You cannot use the in operator on non-objects. This doesn't work (errors out): 'foo' in 'bar', but this does work (returns false): 'foo' in new String('bar')
Is the result of invoking toString upon an object Since they are objects and there is no specific format they should use, JavaScript wouldn't know how to serialize the object. If you want to see its content you need to use JSON.stringify.
The in operator searches for content inside an object. You can not search for content inside a primitive value since it has no methods or properties; hence, it will fail. You can test this by searching in a empty object; you'll see you get false as a response.

Javascript: What datatype is this?

I am using API to build something, but it's not well documentated, so I am moving by guess.
I have a 2 variables:
g.nodes and g.edges, when I do:
console.log(g.nodes);
console.log(g.edges);
I got output for g.nodes as:
Object {hello: Object, test: Object, test1: Object, test2: Object, test3: Object…}
and for g.edges as :
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
I understood that g.edges is an array, but what datatype is g.nodes?
for the first one g.nodes are simply a javascript object, but you can consider it as something like a HashMap or a key-value pair.
and the next one is an array or an array like object which could be a javascript object which all the keys are numbers, it could also be a arguments type object.
about how to go thru:
for g.nodes you can do this:
for(var key in g.nodes){
var value = g.nodes[key];
console.log(typeof value);
}
for arrays you'd better not use the first iteration method, because other than the actual data of the array it can also iterates all other properties defined in Array.prototype, for instance if you add this:
Array.prototype.myarray_prop = 1;
if you use for(var key in obj) method, in addition to the actual array values the myarray_prop will show up as a key, as far as when we usually use arrays we want to iterate the actual values of the array, not these kinds of extra props, it is not a good idea to use for(var key in obj);
so for g.edges you'd better do this:
for(var i=0;i<g.edges.length;i++){
var edge = g.edges[i];
console.log(typeof edge);
}
This is an interesting Question. Lets discuss this one by one:
console.log(g.nodes);
The output suggests that this is an Object. The properties of this Object are:
hello
test
test1
and so on...
Secondly there is an array of an object. This is essentially a JavaScript collection of objects.
A good way not to encounter such things is by debugging your Scripts properly.
A good way to debug JavaScript:
Whenever you feel like that you are not understanding the flow of JavaScript, run that script in FireFox, FireBug and insert break points at all important locations. Then FireBug will show you the type and state of each variable.
An Example of Debugging:
function SayHello(){
debugger;
var msg = "Hello World";
console.log(msg);
}
The code will stop at debugger and you can see the steps from there. You can even see the type of variable "msg".
Hope this helps you a long way.

Categories