Reference another field inside a javascript object - javascript

I have an object in javascript:
admins: {
articles: {
path: '/admins/articles',
template: '/views/admins/articles.html',
link: function() {
return path; // !!! how to reference the 'path'?
}
}
}
I have a lot of objects like this, and each of them has a path field and a link function. I want to use the field path in link, but I can't just use path.
What should I do?

You can use this to reference the object. Standard object.method() "dot" syntax will set this to object within method:
var someObj = {
admins: {
articles: {
path: '/admins/articles',
template: '/views/admins/articles.html',
link: function() {
return this.path; // !!! how to reference the 'path'?
}
}
}
};
var returnedPath = someObj.admins.articles.link();
Demo: http://jsfiddle.net/2Pt7n/
(There are other ways to call a function such that this will not be set to the appropriate object, but I hope they don't apply here - you don't really say how you're using the objects or calling the function, but if not in the way I showed then please update your question and I'll update my answer accordingly.)

I'll just point out that you don't want to use ES6 fat arrow here, because there will be no this pointer in that case:
var someObj = {
admins: {
articles: {
path: '/admins/articles',
template: '/views/admins/articles.html',
link: () => {
return this.path; // 'this' is undefined
}
}
}
};
someObj.admins.articles.link() === undefined

What you are showing is not JSON. It is a Javascript object, which is different than JSON. JSON is a strictly defined data serialization format that is a subset of Javascript object literals.
Javascript provides no syntax for referencing peer properties in an object literal, as you want to do. Naming them is one idea, but it won't help, because the name won't exist while the literal is being defined, so the name is not available for you to use in the literal itself.
Also, note that the syntax you define makes the object lop-sided: you can access path as obj.admins.articles.path, but link is a function you would have to invoke: obj.admins.articles.link().

I won't talk about how this is not JSON (others covered it well).
You can do this to get path:
return admins.articles.path;
Here's a fiddle to show it working: http://jsfiddle.net/UwbLt/

I'm reading the answers and even understanding the point of some users (that JSON should be used just for data) and agreeing that this is correct, I just created a proof of concept example. Take a look.
// just a regular object
var obj = {
a: "aaa",
b: "bbb",
c: function() {
return this.a;
}
};
console.log( obj.c() ); // prints "aaa"
// isn't it json just because it has a function? ExtJS will treat it like JSON, but jQuery not
var json = "{" +
"\"a\": \"aaa\", " +
"\"b\": \"bbb\", " +
"\"c\": function() {" +
" return this.a;" +
"}" +
"}";
// ok, the "json" above
console.log( json );
//var jsonObj = $.parseJSON( json ); // does not work
//var jsonObj = eval( json ); // does not work too
var jsonObj = Ext.decode( json ); // it works! shortcut for Ext.JSON.decode
console.log( jsonObj.c() ); // prints "aaa"
It is almost the same that nnnnnn posted, but I think I would post it too, just to complement the answers. jsFiddle: http://jsfiddle.net/davidbuzatto/rhKAM/
So I think, even contradicting the definition of JSON, that JSON maybe can have (or should have?) the same characteristics of a object created using the regular object initializer sintax, since its name is JavaScript Object Notation, not "Lightweight" Object Notation. I know, I know, a deserializer won't be able to deserialize a function depending on the target language, but why ExtJS supports this "behavior"? A good discussion can be found here: Is it valid to define functions in JSON results?
Just to clarify. I don't use (and I won't use too) functions inside my JSONs.

Related

Passing a param to build a JSON object

How can I pass the subCategory in as an parameter for the function? I have a working solution just passing in the param and then having a switch do the work to make the JSON.subcategory read from the right place. However I feel like there is some thing I am missing on making this more functional, or OO friendly.
So is there a way to make the passed param understand its a variable and not the object literal.
json = {
weather: ["rain", "snow","sun"],
news: ["events", "local","world"]
}
messageBuilder(weather)
function messageBuilder(passedVariable){
var object = json.passedVariable;
// object = json.weather
console.log(JSON.stringify(object));
}
Also am I using the terms correctly? I tried to search google for an answer and ended up not really finding anything.
Just pass the object property key name (sub category) in as a string and use bracket notation to pick it from the data in the function.
Note: that's an object, not JSON, so I've named it as such in the example.
const obj = {
weather: ["rain", "snow", "sun"],
news: ["events", "local", "world"]
};
messageBuilder('weather');
function messageBuilder(subCat){
var object = obj[subCat];
console.log(JSON.stringify(object));
}
Just modify your code a little bit:
json = {
weather : [
"rain", "snow","sun"
],
news : [
"events", "local","world"
]
}
messageBuilder('weather');
function messageBuilder(passedVariable){
var object = json[passedVariable];
// object = json.weather
console.log(object);
}
First of all you should pass your parameter as a string. Then just pull out the property from the object using object['property']

creating a multidimensional array javascript

I am creating a multi-dimensional associative array in javascript. I have created a variable inputs with the following structure but when I access it some where else I get undefined. I don't think there is anything wrong with the structure
inputs = {
indexe: {"input_name":$(input).val()},
};
//where indexe is indexe = indexe + 1;
secondly when I try to access inputs[0]["input_name"] I get undefined. Why is that? My main question is that whether the array structure is correct and it should give the values correctly? There is no scope problem here.
I asked you to use console.log() on the input object, because that will make it clear what you problem is:
// your (wrong) way
const indexe = 5;
const yourway = {
indexe: {
"input_name": 'value' // I used a string so I wouldn't have to import jQuery for this
},
};
console.log('Your original version: ', yourway);
// using a real array, this will have a lot of undefined elements
const arrayV = [];
arrayV[indexe] = {
"input_name": 'value'
}
console.log('Array version: ', arrayV);
// using an object correctly
const objectV1 = {
[indexe]: {
"input_name": 'value'
},
};
console.log('Object version: ', objectV1);
// you can add more to it like so:
objectV1[7] = {
"input_name": 'value'
};
console.log('After adding another entry: ', objectV1);
// you also don't need to create a new object with an already existing element. This will suffice:
const objectV2 = {};
objectV2[indexe] = {
"input_name": 'value'
};
console.log('2. Object version: ', objectV2);
// imortant note on the object versions: length is not defined for objects
console.log('Object version 1 length: ', objectV1.length);
console.log('Object version 2 length: ', objectV2.length);
Your problem simply was that it didn't use the value of indexe, but rather that as the name of a property. I have also included the array version, even though that is not an associative array (and as people in the comments have pointed out, neither are the object versions, really).
P.s. I used ES6 Syntax. It is rather widely supported, but I would still recommend going for at least ES5. (There are pre-processors for that)
If you want to make it ES5-valid, replace const with var and don't use the objectV1-version.

AngularJS Directive Not Evaluating Object Properly

I'm using objects improperly somehow. Basically, I want:
angular.module('mobileDashboardApp')
.directive('localForageModel', function ($localForage) {
return {
link: function postLink(scope, element, attrs) {
scope.$watch(attrs.ngModel, function () {
$localForage.setItem(attrs.localForageModel, scope[attrs.ngModel]);
console.log(attrs.ngModel);
console.log(scope[attrs.ngModel]);
console.log(scope.user.companyId);
console.log(scope["user.companyId"]);
});
}
};
});
to output
user.companyId
dsf
dsf
dsf
instead of the current output which is:
user.companyId
undefined
dsf
undefined
Can anyone point me in the right direction? Or suggest a better title for this?
You have incorrect notation, it must be
var props = attrs.ngModel.split(".");
scope[props[0]][props[1]]
As dot notations are not valid for dynamic properties, so object['abc.def'] must be written as object['abc']['def']
Side-note, definitely you should have some kind of object property checkings, for example, if your ngModel attribute is not abc.def - this will throw exception, so better have generic function for this
In JS, there's a difference between property name containing . (dot) and nested objects accessed by dot. So scope.user.companyId is something different than scope["user.companyId"]. You can have JS object like this:
{
user: {
companyId: 1
},
"user.companyId" : 2
}
So, if you really need to access property having string that represents path within the object (not single property name) you need to parse it. There are many ways to do this. Naive way would be something like this:
function getProperty(obj, pathString) {
var properties = pathString.split(".");
var result = obj;
for (var i in properties) {
result = result[properties[i]];
}
return result;
}
In your case can be used like this: getProperty(scope, "user.companyId").
The way you're accessing the object is incorrect in e.g.
console.log(scope["user.companyId"]);
This should be
console.log(scope["user"]["companyId"]);
I hope this helps you :-)

How to declare nested objects in JavaScript?

I'm trying to create an object that contains an object, so think of it as a dictionary:
var dictionaries = {};
dictionaries.english_to_french =
{
{english:"hello",french:"bonjour"},
{english:"i want",french:"je veux"},
{english:"bla",french:"le bla"}
};
but it gives the error Uncaught SyntaxError: Unexpected token {
what am I doing wrong?
Thanks !
Edit
I'm sorry that I did not clarify what I want to do.
Edited the code above.
You're trying to give your object a property, and that property will be a single object:
dictionaries.english_to_french =
{english:"hello",french:"bonjour"}
;
You don't need the extra { }. You could declare the whole thing at once:
var dictionaries = {
english_to_french: {
english: "hello", french: "bonjour"
}
};
I would suggest that a better format for your dictionaries might be:
var dictionaries = {
english_to_french: {
"hello": "bonjour",
"chicken": "poulet", // ? something like that
"Englishman": "rosbif"
}
};
That way you can look up words directly without having to search. You could then create the reverse dictionary from that:
dictionaries.french_to_english = function(dict) {
var rv = {};
for (var eword in dict)
rv[dict[eword]] = eword;
return rv;
}(dictionaries.english_to_french);
In order to nest two or more objects, the objects need to have an attribute assigned to them. For example,
{
"hello":{
"english":"hello",
"french":"bonjour",
"portuguese":"ola"
},
"good day":{...},
"how are you":{...}
}
"hello" at the beginning of the object would be the attribute. Then the object is its value. So that way you can access the object by accessing its attribute. Just putting an object in an object does not work. That's why you're getting your error.

JavaScript Function arguments

I am trying to create a function that deserialises a JSON object and creates some functions, but I want to be able to specify a variable set of arguments.
For example, in JSON I want to specify something like:
{
"handler" :
{
"args" : ["evt","value"],
"content" : "console.log(value);"
}
}
And when I parse the object, I will do something like:
var myFunction = new Function(handler.args,handler.content);
But the challenge is that each argument is supposed to be a n strings followed by the content of the function as the last argument. Is there any easy way of specifying n number of arguments in a new Function()?
To solve the technically issue: You can use apply [docs].
handler.args.push(handler.content);
var myFunction = Function.apply(null, handler.args);
However the question is why you are doing something like this? What is the context? Spontaneously I would say you should consider another solution for whatever problem you are trying to solve ;)
According to MDN
Parameters
arg1, arg2, ... argN
Names to be used by the function as formal argument names. Each must be
a string that corresponds to a valid
JavaScript identifier or a list of
such strings separated with a comma;
for example "x", "theValue", or "a,b".
So the arguments list can either be one or more strings seperated by commas, or just one string with each identifier in it seperated by commas.
Also since
['evt', 'value'].toString() == 'evt,value'
Simply passing your handler.args array as the first argument to the new Function constructor should work exactly as you want it to
new Function(handler.args, handler.content);
Internally, new Function casts every argument to a string if it is not already one. So conceivably something like this would also work
new Function({ toString: function() { return 'a,b,c' } }, 'return a+b+c');
Not that I'm suggesting you do anything silly like that.
This works in every browser I've tried including IE
I think the simplest route would be to combine the 2 properties. Then use apply to construct the function.
var x = {
"handler" :
{
"constructorArgs" : [
"evt",
"value",
"alert(value);"
]
}
};
var f = Function.apply(undefined, x.handler.constructorArgs);
f(1, 2);
To keep it similar you can use Array.prototype.concat.
var x = {
"handler" :
{
args: [ "evt", "value" ],
content : "alert(value);"
}
};
var f = Function.apply(undefined, x.handler.args.concat(x.handler.content));
f(1, 2);
Can;t you just make the body of your functions work with the arguments property?
http://jsfiddle.net/9XcEb/
var add = new Function(
"var total=0;"+
"for (var i=0; i < arguments.length; i++) {"+
"total+=arguments[i]"+
"};"+
" return total"
);
alert(add(3,4,5,6));

Categories