Call Json by index? - javascript

I want to return some errors to my jquery method. What is happening is I am doing a post(with a type of "json") and if they get errors I want to display the error back to them. I am doing client side validation but some of these are errors that are like server related(ie the database died or something and that update could not happen).
Anyways there could be a few errors and I want to return them all at one go.
So the only way I know really how is to use Json but I now I get the json object I want to get all the fields out of it. I don't want to call it by their name though since I want to use the same methods for all my methods and each one has different names.
So if I could call it by index there would be alot less typing.
Can I do this?

Since you are using jQuery, you could use $.each to iterate over object properties, for example:
var obj = { one:1, two:2, three:3, four:4, five:5 };
jQuery.each(obj, function(key, val) {
console.log(key,val);
});
For objects jQuery internally executes a for...in statement, which does not iterate over built-in properties, however you can have problems if the Object.prototype is extended since that extended members will be iterated also.
Is not a common practice to extend the Object.prototype, but to avoid problems you can use the hasOwnProperty function to ensure that the property exist directly on the object being iterated:
for ( var key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key,obj[key]);
}
}

JSON is nothing more than yet another markup-language to describe complex datastructures. JSON gets parsed into javascript data-structures and can represent objects, arrays or just a string in theoretically unlimited depth.
Without knowing if your JSON structure consists of arrays, objects, or {} constructs it's hard to tell if you can.
However, you could have a look at:
var dataObject = {
key1: "error1",
key2: "error2"
};
for (var key in dataObject) {
alert(key + " : " + dataObject[key]);
}

Related

Is it safe to rename the keys of an object while iterating them?

I'm renaming the keys of an object while iterating them:
Object.keys(object).forEach(function(oldKey) {
var newKey = someFunc(oldKey);
if (newKey !== oldKey) {
object[newKey] = object[oldKey];
delete object[oldKey];
}
}
And I would like to know if this method is safe.
In other words, can I be sure that my code will never iterate a key which has been renamed in a previous iteration?
No, you aren't safe. You're mutating the object live, based on an array that is not live. If you happen to cross a new name with an old (rename a to b, but b already exists and haven't been reached yet) you're going to have a bad time.
You will not come across keys you've already seen, but you have no way to know whether the newKey is not already found in the object.
There are workarounds, the situation is similar to .splice()ing an array (removing elements) while you iterate it, and the simple workaround is to iterate backwards, so that you always already pass the altered keys. (Or in your case, checking with the in operator)
You're much better, however, creating and returning a new object:
const newObj = Object.keys(object).reduce(function(result, oldKey) {
var newKey = someFunc(oldKey);
return { ...result, [newKey]: object[oldKey] };
}, {});
You get a lot of things for free when you treat all of your data structures as immutables (and more specifically, when the keys never change)
Object.keys, like many other methods, returns an Array that you can iterate over. This Array is not "live" but a snapshot from the time of taking it (e.g. executing Object.keys). So yes, you're save to use it as intended.
There are very little examples of methods that return "live lists" instead of an Array; I guess you're having NodeLists in mind, that you'll get when using document.querySelectorAll. This however not an Array but a NodeList.
However, there may be one pitfall I can see is: When a generated newKey already exists in the list of oldKeys (not the current one!). So you may or may not (depending on the position in the array) iterate over the already overwritten new key.
Here is a solution to change the key without creating a new Object.
for(key in obj){
Object.defineProperty(obj, `myNewName`, Object.getOwnPropertyDescriptor(obj, key));
delete obj[key];
}

Javascript How to overload a method and handle keys

I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"
EDIT AGAIN
Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
ie don't return this.prototype.propertyName when own is passedHere's what I have so far:
function Dict(){
this.prototype = {};
var _keys = this.prototype.keys;
this.keys = function(own){
if(typeof own === 'undefined') { return _keys(); }
var ownKeys = [];
for(var key in _keys()){
if(this.hasOwnProperty(key)) {
ownKeys.push(key);
}
}
return ownKeys;
}
}
Will this work as follows? Is there a better or already existent way to do it?
save the overloaded keys() method to a private var
return everything as usual, unless own is something that resolves to true.
if own == true, get the usual keys and filter out those
belonging to the superclass.
On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.
Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).
Any feedback is appreciated!
EDIT
In Python, we get this:
In[2]: d = {}
In[3]: 'has_key' in d.keys()
Out[3]: False
In[7]: 'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]: d.has_key('has_key')
Out[8]: False
In[9]: d['newKey'] = 5
In[10]: d.newKey # ERROR
Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.
I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.
There seem to be multiple issues here.
You seem to want to pass variable arguments to a function:
I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.
JS function arguments are very flexible.
You can either set up names for every one of them:
function foo(arg1, arg2, map, alphaMap)
and pass values directly. This style is preferred for functions that work on a fixed set of arguments.
Or you can set up an "options" object that collects keys and values:
function foo(options)
and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.
Or you can set up an empty function signature
function foo()
and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.
In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.
It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.
This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.
So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.
The direct equivalent to a Python Dict is a plain object in JavaScript.
var dict = {};
The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.
var keys = Object.keys(dict);
To iterate the keys you can either use an imperative approach:
var i, key;
for (i = 0; i < keys.length; i++) {
key = keys[i];
doSomething(key, dict[key]);
}
or a functional one
keys.forEach(function (key) {
doSomething(key, dict[key]);
});
The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:
if ( dict.hasOwnProperty('foo') ) ...
or, if it is a pure data object with no prototype chain, you can use in as well.
if ('foo' in dict)
Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.
var key;
for (key in dict) {
if ( dict.hasOwnProperty(key) ) ...
}
Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.
I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.

Iterate over javascript object such that key variables are used as methods to call the object

Right now I'm hard-coding new properties into my javascript application and its a horrible code smell but I just don't know any better when it comes to javascript implementation. This is what my code looks like now:
$.getJSON(url, function(data) {
$("#total_population_2013").html(data.table.total_population_2013);
$("#median_age_2013").html(data.table.median_age_2013);
//ETCETERA, FOR A VERY LONG TIME I MIGHT ADD
});
Its a ruby OpenStruct object converted into json that I'm sending to the getJSON method. Trial and error solution, but I can access its properties as shown above.
I'm about to add many more variables that I'll be writing into html id tags, and would prefer to do this is a more professional manner. Here is what I've tried so far but is not working:
$.getJSON(url, function(data) {
for(var k in data) {
var value = data[k];
var id_str = "#"+k;
$(id_str).html(value);
});
}
Thanks
I notice two things. One is that for..in iterates over all properties of an object, which can include stuff that it gets from the prototype chain. This is typically not what you want, so you want to do this instead:
for(var k in data) if (data.hasOwnProperty(k)) {
...
}
This makes sure you only get the object's own properties.
Second, your JSON seems to have its data under data.table and instead you're pulling stuff just out of data. This means, you'll just get table as a value and you probably don't have anything with the id #table. I suspect you want:
for(var name in data.table) if (data.table.hasOwnProperty(k)) {
$("#" + name).html(data.table[name]);
}

JSON.stringify() Does Not Work As Expected

I have used JSON.stringify() many times and I am aware of some issues such as (described in here):
cycles
too deep objects
too long arrays
However, I am facing incorrect stringify operation on object which is like that:
After running JSON.stringify(obj) on console, I am getting that.
"[{"$$hashKey":"object:103",
"ProductCategories": [{"Id":2,"ShopProductCategoryName":"Drink","isSelected":true}
{"Id":3,"ShopProductCategoryName":"Food","isSelected":true}]
}]"
It only stringifies ProductCategories and $$hashKey which is totally unexpected.
Solving Attempts
If I create new object from obj and stringify it, returns correct JSON.
var newObj = { // Creates new object with same properties.
AllProductCategories: obj.AllProductCategories,
Id: obj.Id,
LabelName: obj.LabelName,
Percentages: obj.Percentages,
ProductCategories: obj.ProductCategories
}
JSON.stringify(newObj); // Returns correct JSON.
I used the code to send object to web api compulsorily, but the way is not what I want, of course.
As I see,
There is no cycles.
It is not too deep. (only has depth 3)
Therefore, I cannot figure out what is wrong.
Well I suggest you create a function that clones your object without $$hashKey property that was set by angular I guess:
function cloneObj (obj) {
var cloned = JSON.parse(JSON.stringify(obj));
delete cloned.$$hashKey;
for(var key in cloned) {
if(typeof cloned[key] === 'object') {
cloned[key] = cloneObj(cloned[key]);
}
}
return cloned;
}
After you clone your object without $$hashKey, then you can stringify it without any problem.

How to access fields in JSON object by index

I know this isn't the best way to do it, but I have no other choice :(
I have to access the items in JSONObject by their index. The standard way to access objects is to just wirte this[objectName] or this.objectName. I also found a method to get all the fields inside a json object:
(for (var key in p) {
if (p.hasOwnProperty(key)) {
alert(key + " -> " + p[key]);
}
}
(Soruce : Loop through Json object).
However there is no way of accessing the JSONfields directly by a index. The only way I see right now, is to create an array, with the function above, get the fieldname by index and then get the value by fieldname.
As far as I see it, the p (in our case the JSON file must be an iteratable array to, or else the foreach loop wouldn't work. How can I access this array directly? Or is it some kind of unsorted list?
A JSON Object is more like a key-value-map; so, yes, it is unsorted. The only way to get around is the index->property name map you've already mentioned:
var keysbyindex = Object.keys(object);
for (var i=0; i<keysbyindex.length; i++)
alert(object[keysbyindex[i]]);
But why would you need these indexes? A unsorted map also has no length property, as an Array had. Why don't you use the for-in-loop
var counter = 0; // if you need it
for (var key in object) {
alert(object[key])
counter++;
}
? If you have a parsed JSON object, i.e. a plain JS Object, you won't have to worry about enumerable prototype properties.
Based on Bergis anserwer this is my solution:
var keysbyindex = Object.keys(this);
alert(this[keysbyindex[index]]);
return this[keysbyindex[index] || ""];
However, I think (not tested) it's extremly bad regaring performace and shouldn't be used! But desperate times require desperate measures.....
I don't think you can actually achieve this without creating your own parsing of JSON. You're writing that you want to go trough a JSON-object, but what you're actually trying to do is go trough a plain old Javascript object. Json is simply a string-representation used to transfer/store said object, and in here lies the main problem: the parser that transforms the string into an actual object (ie. the browser in most cases) can chose to ignore the order it finds the properties if it want to. Also, different browsers might have different approaches to parsing JSON for all you know. If they simply use a hash-map for the object that it's simple to loop through it, but the order won't be dependent on the order of the keys in the file, but rather the keys themselves.
For example, if you have the json {"b":"b","a":"a"} and do the for in loop, under some implementations you might end up with a comming first, and in others you might end up with b.
var jsn = {keyName: 'key value result come here...'};
var arr = jsn ? $.map(jsn, function (el) { return el }) : [0];
console.log(arr[0])
$('.result').text(arr[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="result"></span>

Categories