I have JSON data and I was wondering if there was a way to determine the parent object of a nested object. For example, take this structure:
Vehicles[]
ForSaleCars[]
Car{}
Make
Model
Year
SoldCars[]
Car{}
Make
Model
Year
Assume that this is in var json = ; and has been filled with some data. It is easy to access the second car in the ForSaleCars array like this:
var secondCar = json.Vehicles.ForSaleCars[1];
At this point, solely from the secondCar variable, is it possible to tell it came from ForSaleCars and not SoldCars?
The reason I ask is that I am traversing a json object graph recursively and it would be nice to see which parent the object had without tracking.
At this point, solely from the secondCar variable, is it possible to tell it came from ForSaleCars and not SoldCars?
No. JavaScript doesn't automatically track where a reference was copied from.
It is not possible. You can maintain hash instead.
No, you are copying from the parent, and JavaScript won't track what the parent reference used to be. If you want to be able to track it, you will need to add a reference:
var secondCar = json.Vehicles.ForSaleCars[1];
secondCar.parent = json.Vehicles;
Related
I have a selectedItem object in Angular, it contains other objects and arrays. I create a deep copy using a JSON trick:
$scope.editableItem = JSON.parse(JSON.stringify($scope.selectedItem))
Then I use editableItem model in inputs, change some values inside. selectedItem doesn't change. Then I want to send via PATCH all the changes made, but not the fields which were not changed. So I need to strip the editableItem from all fields that are the same in unchanged selectedItem.
How to do this efficiently? I was thinking about traversing object recursively using Underscore, but I'd really like to know if it's a good way of thinking before I tackle it.
Alternatively I could probably create third object which would only contain touched fields from the second one, added dynamically, but I'm not sure how to approach this.
EDITED:
To be clear, I expect the answer to be generic and assume the most complicated object structure possible. For example no answers from this question are applicable here as they either assume the object has only simple fields or they need to have Angular watcher explicitly set for every field separately.
I do something similar with a function like this:
function getUpdateObject(orig, current) {
varChanges = {};
for (var prop in orig) {
if (prop.indexOf("$") != 0 && orig[prop] !== current[prop]) {
varChanges[prop] = current[prop];
}
}
return varChanges ;
};
I don't think this will get you all the way there. I'm not using it in any scenarios where the objects have member objects or arrays, but you should be able to test if "prop" is an object or array and call it recursively. The biggest caveat I see to that approach is if you have a deep, nested structure, you may not detect a change until you're down several levels. You'd probably have to keep the full potential hierarchy for a changed property in memory, then when you detect a change at a lower, level, write the whole hierarchy to the output object.
This is what I ended up with. Maybe it'll help someone. I used DeepDiff library. Code is in CoffeScript, should be easy to translate to JavaScript if anyone needs it.
$scope.getChangesObject = () ->
selected = $scope.selectedItem
editable = $scope.editableItem
changes = {}
differences = DeepDiff(selected, editable)
for diff in differences
formattedPath = ""
for pathPart, index in diff.path
if index isnt diff.path.length - 1
formattedPath += pathPart + "."
else
formattedPath += pathPart
changes[formattedPath] = editable[formattedPath]
changes
I have some code I'm struggling with. The good news is the code working as intended for a single instance; after some thought I've decided to feature multiple of these image selectors on a page. This works but the ugly approach of duplicating the code doesn't scale well (e.g. what if you want 50 of these on there?) The snag I've hit is how I can refer to a specific array. Is an array even an ideal solution for this?
The Objective
I have a series of images that a user may select from, up to X amount. The selected image ids are stored in an array and the image is added to a "selected images pool". This occurs by using an onClick for the slider, I obtain the Id from the element attributes. This is where I'm getting stuck.
var dataArray = $(this).closest("[id^=carousel]").data('array');
var slideCounter = $(this).closest("[id^=carousel]").data('counter');
slideCounter = dataArray.length;
The slideCounter returns the length of the string, not the array elements. How can I tell this code to refer to a particular array? See the fiddle for a better idea of the markup and code: jsFiddle
I have no doubt that there is a better approach. I'm relatively new to front end work, I'd appreciate any insights, I've burnt some brain cells on this, thanks!
From looking at your HTML, it looks like when you do this:
var dataArray = $(this).closest("[id^=carousel]").data('array');
what you're trying to do is to read the name of an array with .data() and then somehow turn that name (which is a string) into the array that's in your variable. My guess is that there's probably a better way to structure your code rather than putting javascript variable names in your HTML. I'd probably put a key name in the HTML and then store the arrays in an object where you can access them by that key name at any time.
Without trying to refactor your code, here's an idea for what you were trying to accomplish:
If selectedSlidesIdArray1 is a global variable, then you can do this:
var dataArray = window[$(this).closest("[id^=carousel]").data('array')];
Using the [stringVariable] notation on an object, lets you access a property by a literal string or a variable that contains a string. Since all global variables are also properties on the window object, you can do it this way for global variables.
If selectedSlidesIdArray1 is not a global variable, then you should probably put it in an object and then you can do this:
var dataArray = yourObj[$(this).closest("[id^=carousel]").data('array')];
Instead of trying to translate an arbitrary string into a JavaScript variable of the same name, why not just use another array? You can have nested arrays, which is to say an array of arrays.
Thus, instead of selectedSlidesIdArray1, selectedSlidesIdArray2, etc., you would have one selectedSlidesIdArray with sub-arrays, which you could then pull the index for using a data attribute.
I couldn't really word the question less vaguely, but I think you will understand...
I am developing a game engine in Javascript, and the Scene object, which is a container of many things, has a method that is supposed to change one array in it, specifically the one holding all the things that can be drawn.
This array is accessed like this:
scene.internals.draw
The problem is, it is referenced many times in the method, and I think that the name/path might change. Naturally, I don't want to change every reference to it in the method each time I change the the array's path, so I did this:
var location = scene.internals.draw;
Now, the actual method code and the algorithm can stay intact, and if the name/path of the array in the scene changes, I only need to change that one line.
And it works pretty well for the most part. I can .push(obj) to it, etc, but at one point, I need to "disect" the array, ie, split it in half, add something, and then put it back together, like this:
buff1 = location.slice(0, i); //First slice of the array.
buff2 = location.slice(i, location.length); //Second slice of the array.
//Add something in between those slices.
buff1.push(ob);
location = buff1.concat(buff2); //Problems here!
This worked well while location was just scene.internals.draw, as it changed the array directly. But now, I assign the new value to the local location variable, not the desired scene.internals.draw one!
Question: how can I, using the = operator, assign values to "real" objects, instead of the variables that contain references to these objects (like location)?
The obvious solution would be this, at the end of the method:
scene.internals.draw = location.slice();
This is OK, the only side effect is that I will have to write the original name twice, and edit it twice, which isn't such a big issue. But, I maybe find myself in other situations where I just might need that functionality, so I'd still like an answer.
There is no assignment by reference in javascript, so you cannot do this. What you are doing is usually mistaken for assignment by reference but it is in fact a copy of a reference value which has implications like this.
You probably have a deeper problem somewhere since you are doing this but I don't wanna get into that.
You could do this:
location.splice( 0, location.length ); //Remove all items in the array
location.push.apply( location, buff1.concat(buff2) ); //Push the buffers into the array
To use your term, there are no "real" objects in Javascript - there are only objects, and the variables that hold references to them.
When you assign to location you're just creating an additional reference to an object. The system has no knowledge of which "real" object it was, nor of any other variables that may hold references to it.
So when you reassign to location you're just overwriting that particular reference. Any other original references to the object will stay pointing just where they were.
I want to create javascript variables on the fly and append their values into a string. I actually am unable to find a method which dynamically declares variables in javascript. Once that is done I would want to do the reverse of this. So my question has two parts : one is related to creating and deleting variables on the fly as per requirement and the other is related to appending or deleting those variables value into a string at a specific point in the string.
There is the eval function.
But! you should ask yourself twice why do you need to "create variables on the fly"
eval on MDN
If I understand what you're after correctly, you should use an object for this:
var o = {};
o.name = "value"; // Creating a property
delete o.name; // Deleting a property
It sounds like you have a specific problem, could you perhaps share a bit more information about your problem?
I have a form with about 20 input fields. I capture values of these fields, then do some calculations and output several values.
Is there a preferred/recommended way of capturing form data? Currently I store every form field into a separate variable. I was wondering if storing it to an array would be a better and more effective approach.
I'm quite new to Javascript and programming in general, trying to learn the best practices.
My best practice on this depends on what I have to do with the data. If I do not need to loop through it, or send it to another page/service, then there's nothing wrong with individual scoped-variables.
If I need to loop at all, I commonly use an array or object to loop through.
If I have to pass it to another page/service, I make one object variable to encapsulate the rest of them, so I can "stringify" it to JSON and parse back to an object on the other end.
Just my opinion,
Pete
You might consider the third approach - just use the data from the form without storing it anywhere.
First check the correctness, once it is considered correct just use what you have.
You should always assign the attribute "name=..." to an input element, so you can use something like:
var form = document.forms['form'];
var email = form['email'];
email = do something
if you use javascript... if you use jquery it's simple $('input[name="email"]') = do something
I prefer this way because you can call variables by name, not by number, for example "form[0] that corresponds to input[name="email"]".
Use the associative properties of arrays in JavaScript to get the benefits of unique field names and OOP:
var formModel = new Array();
formModel['myField'] = getMyFieldValue(); // make 'myField' index to any object
Then you can do things like:
formModel['myField'] // get the value
formModel.length; // number of fields added
for (entry in formModel) { /* loop thru entries */ }
formModel.sort([compareFunction]) // custom sort
formModel = []; // clear the model
Convert array to JSON
Any of these ArrayMDN conveniences.
Just one approach, but arrays in JS are extremely versatile and IMO underused objects in JS.