I need to search a large JSON file for an id and return all the attributes. However, there is a parentId attribute. This corresponds to the id of another object whose attributes I need to include, and possibly another parentId, etc.
m.getAttrs = function(o){
var a = []
// get the model based on id or object.id
if(o instanceof String)
var obj = json.models.filter(i => i.id == o)[0]
else
var obj = json.models.filter(i => i.id == o.id)[0]
////// On 2nd iteration: "TypeError: Cannot read property 'hasOwnProperty' of undefined" ///////////////
if( obj.hasOwnProperty("parentId") && obj.parentId != ""){
// get parent id
var pid = obj.parentId
// get parent attributes
a.push(m.getAttrs(pid)) // RECURSION //
}
// get attributes
var attrs = obj.attrids
// get Attribute Names
for(aid in attrs){
var aName = json.attrs.filter(i => i.id == aid)
a.push(aName)
}
return a
}
I'm seeing an error where obj is not defined after the first iteration of getAttrs. I think this is because json.models.filter... isn't finished, but it could be a lot of things.
I've tried a bunch of times to implement promises, but can't seem to get anything working, and it makes my code too messy for me to want to include it here.
How can I implement a promise to say "after you find the right model, CONTINUE (rather than execute another function)"?
Here's what I found out...
According to Jamiec, It is not possible to use a promise to continue regular operation. Although it seems like a generator may be able to accomplish this, but I'm not familiar with them.
Array.prototype.filter is synchronous, so my issue wasn't with async in the first place. It turns out that instanceof String doesn't work unless you specifically make a String variable. Here's a post I found to help with that: Why does instanceof return false for some literals?
This fixed my code:
if(typeof o === "string")
var obj = json.models.filter(i => i.id == o)[0]
else
var obj = json.models.filter(i => i.id == o.id)[0]
Related
Maybe ReSharper or visual studio is wrong, but I don't think that this returns an r-value. I also don't think it actually sets the property in the $parent controller:
function getParentItem(path) {
var obj = $scope.$parent;
var param = null;
var items = path.split(".");
for (var i = 0; i < items.length; i++) {
var item = items[i];
var split = item.split("(");
if (split.length === 2) {
param = split[1].replace(/[\)\']/g, "");
}
obj = obj[split[0]];
}
if (param == null) {
var thisObj = obj;
return thisObj;
} else {
return { obj: obj, param: param };
}
}
If I do this:
getParentItem($scope.someProperty) = "yadda"
I get error marked by probably ReSharper and I think it doesn't actually set the new value
As Amy/Volkan said your code is not valid but I think I get what you want to do. There are lots of ifs but here it goes:
if your $scope.someProperty is string property that you want to reassign on result of the function getParentItem, and your function returns object that can have that param ($scope.someProperty), first you need to figure out which path you pass in but it looks like it's some string separated by dots.
// so then assign result of the function to some variable
// you need to pass somePath to function
let parentItem = getParentItem(somePath);
// then change that property
parentItem[$scope.someProperty] = "yadda";
or another possibility what you might need would be:
parentItem.param[$scope.someProperty] = "yadda";
then do whatever you want with parentItem like put it on $scope or whatever.
If you want better help please do some jsfiddle or something.
The problem is (and I slap my head on how stupid I was) that the leaf branches of this $scope object aren't objects themselves, and in some cases in our code they don't even exist yet. You get so used to $scope being an object you fail to realize that the final elements can't possibly be objects at least in Javascript.
So the solution was to pass the value that I wanted to set as a parameter:
function getParentItem(path, optionalValue)
On the final loop of the parent search, if optionalValue is passed, I can then set the value onto the object:
obj[--last parameter name--] = optionalValue;
I have a JSON object which I get from a server. The key which I get the value from looks something like this:
var myJson = data.body.region.store.customer.name;
I am trying to get the name key here, but sometimes the JSON (which comes from a service I have no control over) will have some empty fields, like for instance name might not be defined so the object will actually look like this: data.body.region.store.customer. Sometimes too customer, or store, or region might not be defined (If the data doesn't exist the service doesn't return a null or empty string for the value).
So if I need the name what I am doing is this:
if(data.body.region.store.customer.name){
//Do something with the name
}
But say even store isn't defined, it will not get the value for name(which I would expect to be undefined since it doesn't exist) and the program crashes. So what I am doing now is checking every part of the JSON before I get the value with AND operands:
if(data && data.body && data.body.region && data.body.region.store && data.body.region.store.customer && data.body.region.store.customer.name){
//Do something with the name value then
}
This works, because it checks sequentially, so it first checks does data exist and if it does it checks next if data.body exists and so on. This is a lot of conditions to check every time, especially since I use the service a lot for many other things and they need their own conditions too. So to just check if the name exists I need to execute 6 conditions which of course doesn't seem very good performance wise (and overall coding wise). I was wondering if there is a simpler way to do this?
var myJson = null;
try {
myJson = data.body.region.store.customer.name;
}
catch(err) {
//display error message
}
You can try following
function test(obj, prop) {
var parts = prop.split('.');
for(var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
if(obj !== null && typeof obj === "object" && part in obj) {
obj = obj[part];
}
else {
return false;
}
}
return true;
}
test(myJson, 'data.body.region.store.customer.name');
I don't have much experience in JavaScript, so far I have this:
function loop() {
var authorDivs = document.getElementById('ctl00_MainContent_MCPObjectInfo_dvCreatorView').getElementsByTagName("div");
for (var i = 0; i < authorDivs.length; i++) {
var divOfDiv = authorDivs[i].getElementsByTagName("div");
if (typeof divOfDiv.item(i) === 'undefined' || divOfDiv.item(i) === null) {
console.log("This is undefined or null");
}
else {
var realDivs = divOfDiv.item(i);
realDivs.item(i).textContent = "please work plz";
}
}
}
I get the following error from the console in FireFox: TypeError: realDivs is undefined on this line: realDivs.item(i).innerHTML = "please work plz";
Essentially what I have (in my mind) is a loop that goes through authorDivs and gets all of the divs within those divs and saves them in divOfDiv. I then check to see if the divs in divOfDiv are undefined or null, if they are not then those divs get saved in a variable realDivs which I then use to edit the innerHTML. That's what I'd ideally like to see happen, what is causing the error? What am I doing wrong?
Note: I do not have access to jQuery but only JavaScript.
Edit: I've added the changes suggested below and its fixed that -- thanks! But I'm now getting the following error: TypeError: realDivs.item is not a function
What is causing that? And on another note how do I know when I'm dealing with an array and when I'm dealing with an HTMLCollection? Do you just assume? I've never used a loosely typed language before so its new to me.
Well, you'll need to move that code inside the conditional block that is supposed to prevent it! Also, || "null" is not going to work as you expect, you'll need to check for || divOfDiv.item(i) === null explicitly.
So try
for (var i = 0; i < authorDivs.length; i++) {
var divOfDiv = authorDivs[i].getElementsByTagName("div");
if (divOfDiv.item(i) == null) {
console.log("This is undefined or null");
} else {
var realDivs = divOfDiv.item(i)
realDivs.item(i).innerHTML = "please work plz";
console.log(divOfDiv.item(i));
}
}
However, that still doesn't really work for two reasons:
The i index you use to access the i-th divOfDiv comes from the iteration over authorDivs - hardly what you want. Instead, use a second loop over all divOfDivs.
Your realDivs variable does hold a single <div>, which does not have an .item method. You'd just directly access its .innerHTML property.
So you should use
var authorDivs = document.getElementById('authorView').getElementsByTagName("div");
for (var i=0; i<authorDivs.length; i++) {
var divsOfDiv = authorDivs.item(i).getElementsByTagName("div");
for (var j=0; j<divsOfDiv.length; j++) {
var realDiv = divsOfDiv.item(j);
realDiv.innerHTML = "please work plz";
console.log(realDiv);
}
}
it will happen in case when your if (typeof divOfDiv.item(i) === 'undefined' || 'null') returns true. Then you never initialize realDivs (what would happen if condition was falsy). Later you try to call item function on that unitialized object
There are two problems in the code.
comparing DOM object with 'undefined' and null. If div tag is not available in authorDivs[i], it will return empty DOM array. So, comparision of empty DOM array with undefined and null is not good approach. We can use array length property for doing validation.
divOfDiv = authorDivs[i].getElementsByTagName("div");
if(divOfDiv.length > 0) { console statement}
As item(i) is already return single DOM element, item(i) of "realDivs" variable is not proper approach. In addition to this, innerHTML method needs to be used after validating whether realDivs contains DOM element. Please update the code as below.
var realDivs = divOfDiv.item(i);
realDivs ? (realDivs.innerHTML = "please work plz"): null;
Note : item(i) will return null if DOM is not available.
I'm writing a script that adds labels to things on a page using an element from an array based on part of the link... so my array looks like this:
var componentList[9] = "Sunnyseed"
var componentList[10] = "Echoberry"
var componentList[11] = "Riverstone"
var componentList[13] = "Auraglass"
var componentList[14] = "Skypollen"
You'll notice there is no '12'... I want the label to be 'Unknown' when the array item doesn't exist. Now, I can't exactly test my solution since I can't cause the target page to throw me a 12... so I was hoping somebody would tell me whether this will do what I want or not...
var component = ""
if(typeof componentList[critterIDval] == 'undefined'){
component="Unknown"
}
else{
component=componentList[critterIDval]
}
This is obviously not the full script, but it should be the important stuff... I just want to know if that will make it say 'Unknown' when the critterIDval is 12 - since it could take years to come across the situation for testing.
You're pretty much there. You're using a single-equals sign in your comparison, so that will mess it up, and I'm not sure you can create a JS array like that, but aside from that, you're good.
Here is the test I ran for it:
var componentList = [];
componentList[9] = "Sunnyseed";
componentList[10] = "Echoberry";
componentList[11] = "Riverstone";
componentList[13] = "Auraglass";
componentList[14] = "Skypollen";
for (var critterIDval = 9; critterIDval < 15; critterIDval++) {
if (typeof componentList[critterIDval] == 'undefined') { // double equals here
component = "Unknown";
} else {
component = componentList[critterIDval];
}
console.log(component);
}
It looks fine.
Though if you are sure that the value will never be an empty string(like componentList[14] = '';) then you can try
var component = componentList[critterIDval] || 'Unknown'
I want the label to be 'Unknown' when the array item doesn't exist.
The typeof operator does not tell you if a property exists or not as it returns undefined when the property doesn't exist but also when it does exist and has been assigned a the value undefined or simply created but hasn't been assigned a value.
There are two primary ways to test for the existence of a property: the in operator, which also looks on the [[Prototype]] chain and the hasOwnProperty method of all Objects. So
if (componentList.hasOwnProperty(critterIDval)) {
component = "Unknown"
} else {
component = componentList[critterIDval]
}
which you could also write as:
component = componentList.hasOwnProperty(critterIDval)? componentList[critterIDval] : 'unknown';
PS. there are other methods, such as looking at Object.keys(componentList) and componentList.propertyIsEnumerable(critterIDval), but the above are the most common.
Edit
If your requirement is not just to test for property existence but to also test for a "truthy" value, then:
if (componentList[critterIDval])
may be sufficient and will return false where the value is '' (empty string), 0, false, NaN, undefined or null.
Maybe just testing for a non–empty string or number will do:
if (/.+/.test(componentList[critterIDval]))
but that returns true for NaN, null and so on. So you need to specify what you are actually testing for, otherwise you may get undesired results for some values.
trying to determine a decent, cross browser method for obtaining attributes with javascript? assume javascript library use (jQuery/Mootools/etc.) is not an option.
I've tried the following, but I frequently get "attributes" is null or not an object error when IE tries to use the "else" method. Can anyone assist?
<script type="text/javascript">
//...
getAttr: function(ele, attr) {
if (typeof ele.attributes[attr] == 'undefined'){
return ele.getAttribute(attr);
} else {
return ele.attributes[attr].nodeValue;
}
},
//...
</script>
<div>
Link
</div>
using the above html, in each browser, how do I getAttr(ele, 'href')? (assume selecting the ele node isn't an issue)
For the vast majority of cases you can simply use the built in getAttribute function.
e.g.
ele.getAttribute(attr)
According to QuirksMode this should work on all major browsers (IE >= 6 included), with a minor exception:
In IE5-7, accessing the style attribute gives an object, and accessing the onclick attribute gives an anonymous function wrapped around the actual content.
With regard to your question's update, you could try this.
It may be overkill, but if getAttribute() and the dot notation don't return a result, it iterates through the attributes object to try to find a match.
Example: http://jsfiddle.net/4ZwNs/
var funcs = {
getAttr: function(ele, attr) {
var result = (ele.getAttribute && ele.getAttribute(attr)) || null;
if( !result ) {
var attrs = ele.attributes;
var length = attrs.length;
for(var i = 0; i < length; i++)
if(attrs[i].nodeName === attr)
result = attrs[i].nodeValue;
}
return result;
}
};
var result = funcs.getAttr(el, 'hash');
It's up to you to do some cross-browser testing, though. :o)
Using ele.attributes, you need to access them by index, as in:
ele.attributes[0].nodeName; // "id" (for example)
ele.attributes[0].nodeValue; // "my_id" (for example)
Trying to pass attributes an attribute name appears to return a value whose typeof is object, so your else code is running even though ele.attributes[attr] doesn't give you the value you want.
You are trying to access properties of ele before you've established if those properties exist. Try this kind of evidence chain:
if (ele.attributes && ele.attributes[attr] && typeof ele.attributes[attr] == 'undefined')
etc.