I have an object whose members are objects and arrays. This is what it looks like in the console:
Object {UserAccount: Object}
UserAccount: Object
UserAccountId: 2
User: Object
UserId: 2
UserRoles: Array [2]
0: Object
UserRoleId: 2
RoleId: 1
Org: Object
OrgId: 2
OrgName: "Little League"
1: Object
UserRoleId: 7
RoleId: 1
Org: Object
OrgId: 5
OrgName: "Youth Soccer"
I need a loop that will insert a child element for each OrgName. Here is the HTML so far:
<div class="sp">
<div class="tabs">
<!-- Want to insert element here -->
</div>
I am trying to write a javascript loop and it isn't working. I think the reason is that I don't know how to refer to members of objects inside other objects. This is from the .js file:
var i;
for (i in userAccount.User.UserRoles) {
$('.tabs').append('<span>' + Org.OrgName + '</span>');
}
When I run it I get this error:
Uncaught TypeError: Cannot read property 'UserRoles' of undefined
Please help!
Since you're looping through an array, use the iterative for loop.
var roles = UserAccount.User.UserRoles;
for(var i = 0; i < roles.length;i++){
var role = roles[i];
$('.tabs').append('<span>' + role.Org.OrgName + '</span>');
}
try
UserAccount.User.UserRoles.forEach(function(userRole) {
$('.tabs').append('<span>' + userRole.Org.OrgName + '</span>');
});
You can do a regular for loop as well. Or you can implement your own one as a utility function, as using a regular one is frustrating, so you DRY instead of repeating yourself :
var each = function(elements,fn) {
for (var i = 0; i < elements.length && !fn(elements[i], i++););
};
Looks good so far. But it looks like a mixture of forEach and for loops.
This is untested but adding userAccount.User.UserRoles[i] before Org.OrgName should work.
var i;
for (i in userAccount.User.UserRoles) {
$('.tabs').append('<span>' + userAccount.User.UserRoles[i].Org.OrgName + '</span>');
}
Another option. One that I find easier to read, is using a forEach loop.
userAccount.User.UserRoles.forEach(function (role) {
$('.tabs').append('<span>' + role.Org.OrgName + '</span>');
});
Note: forEach is unssupported in IE8. If this is a supported browser for your application, try using jQuery or Underscore which provide an IE8 friendly forEach option. Both of which are called each $.each() _.each()
There is this element.querySelector() for this job. You just do like
var myParentElement = document.querySelector(".sp"),
myElementToAppend = myParentElement.querySelector(".tabs");
myElementToAppend.appendChild(yourNewElement);
Related
I've been using a crossword app from this repo: https://github.com/jweisbeck/Crossword . The problem is that the program uses jquery version 1.6.2 and my whole project uses jquery-3.1.1 version. Particularly, the error arises here:
buildEntries: function() {
var puzzCells = $('#puzzle td'),
light,
$groupedLights,
hasOffset = false,
positionOffset = entryCount - puzz.data[puzz.data.length-1].position; // diff. between total ENTRIES and highest POSITIONS
for (var x=1, p = entryCount; x <= p; ++x) {
var letters = puzz.data[x-1].answer.split('');
for (var i=0; i < entries[x-1].length; ++i) {
light = $(puzzCells +'[data-coords="' + entries[x-1][i] + '"]');
if($(light).empty()){
console.log($(light));
$(light)
.addClass('entry-' + (x-1) + ' position-' + (x-1) )
.append('<input maxlength="1" val="" type="text" tabindex="-1" />');
}
}
}
// Put entry number in first 'light' of each entry, skipping it if already present
console.log(entries);
console.log(puzz.data);
for (var i = 0; i < entryCount; i++) {
$groupedLights = $('.entry-' + i);
if(!$('.entry-' + i +':eq(0) span').length){
$groupedLights.eq(0)
.append('<span>' + puzz.data[i].position + '</span>');
}
}
util.highlightEntry();
util.highlightClue();
$('.active').eq(0).focus();
$('.active').eq(0).select();
}
The error arises at line with
light = $(puzzCells +'[data-coords="' + entries[x-1][i] + '"]');
The browser shows this error:
Error: Syntax error, unrecognized expression [object Object][data-coords="1,6"]
I believe this is related to the jQuery version. Or maybe the program uses [object Object] as index. Not sure as I am new in jQuery. I tried to use jQuery Migrate, but it didn't help. Also, I tried to use that jQuery 1.6.2, but a web browser could not find jQuery at all as I am using Typescript and had to install jQuery through .d.ts file. Any tips or advises? Thanks in advance
As the title says:
Make object Object as index of array
That is not possible with standard Objects/Arrays, but you can use a Map for that:
let map = new Map(),
key = {id: '##'};
map.set(key, [1,2,3,4,5]);
console.log(map.get(key)); //[1,2,3,4,5]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
The [object Object] in the string shown in the error is because a jQuery object is being appended to a string to create a selector, which is invalid.
In your code, it's this line causing the problem:
var puzzCells = $('#puzzle td') // holds jQuery object
// later on...
light = $(puzzCells + '[data-coords="' + entries[x-1][i] + '"]');
This is nothing to do with the version of jQuery being used as it's a syntax issue.
To fix this you should use filter() on the puzzCells object, instead of appending it to a selector. Try this:
light = puzzCells.filter('[data-coords="' + entries[x-1][i] + '"]');
You are concatenating an object (puzzCells) and a string. When JavaScript detects an string concatenation tries to convert all the variables to strings before concatenating them. In plain JavaScript, if you do WHATEVEROBJECT.toString() you will receive [object Object], that's why you see an error containing that message.
This is not jQuery version problem, as this happens at the very low level (JavaScript).
puzzCells is a jQuery object, where you can call jQuery methods. In this case you need the filter method, like this:
light = puzzCells.filter('[data-coords="' + entries[x-1][i] + '"]');
Check out more info right here: http://api.jquery.com/filter/
I'm not that experienced in javascript and totally new to the whole loop idea but I know it can save a lot of code. So I have been trying to create a loop. This is my problem: I find every variable in the first line and want to add a value to the A. I know $(this) doesn't do the trick but I can't come up with something better what works.
Basically, I want for the first variable amount[0] and for the second amount[1] and so on..
This is what I have so far..
$(a).each(function() {
$(this).find("a").after( (" (" + amount[0] + ")"));
});
So I assume you want somthing like this:
$('a').each(function(index) {
if (index >= amount.length) return; // avoind IndexOutOfBounds Exception
$(this).after( " (" + amount[index] + ")"); // $(this) will refer to a link, in this each
});
After each link (a) you want to add a '(text_from_amount)' where text_from_amount is taken from amount array?
More about each, can be found here.
First of all, you're using jQuery, not native Javascript.
The $(selector).each function may take two parameters: The first one is the loop counter and the second one is the callback.
(Use the counter of the each() method, assuming that the amount array has all those entries. The better aproach would be to use a conditional to check if amount[counter] exists)
$(a).each(function(counter, value) {
//conditional to check array entry
if (amount[counter] !== undefined) {
$(value).find("a").after('(' + amount[counter] + ')');
}
});
The $.each() function (without selector) may be used to iterate over arrays or an array of objects:
// An array
var myArray = ['one', 'two', 'three'];
$.each(myArray, function (counter, value) {
console.log(counter);
console.log(value);
});
// An array of objects
var myArrayObject = [
{
one: 'foo',
two: 'bar'
},
{
one: 'another foo',
two: 'another bar'
}
];
$.each(myArrayObject, function (counter, value) {
console.log(counter);
console.log(value.one);
console.log(value.two);
});
See the docs for more information.
i want to for loop my array result as array because i use nested loop.
Here is my code
var isp = ["yahoo", "gmail"];
var yahoo = ["#yahoo.com", "#rocketmail.com", "#ymail.com"];
var gmail = ["#gmail.com"];
for(x=0;x<isp.length;x++){
//Should alert 3 Because var yahoo contains 3 element
//Should alert 1 because var gmail is contain 1 element
alert(isp[x].length);
for(y=0;y<isp[x].length;y++){
//Should alert #yahoo.com, #rocketmail.com and so on
alert(isp[x][y]);
}
}
Here is my JSFiddle https://jsfiddle.net/4v272ghL/1/
Try this:
https://jsfiddle.net/4v272ghL/2/
var isp = ["yahoo", "gmail"];
var providers = {
'yahoo': ["#yahoo.com", "#rocketmail.com", "#ymail.com"],
'gmail': ["#gmail.com"]
};
isp.forEach(function(v, i) {
console.log(v);
providers[v].forEach(function(domain, index) {
console.log(domain);
});
});
You're using a JS object to hold the arrays of domains instead. Using this, you can access each provider's data dynamically.
Maybe you don't need so many arrays? Lets use an object instead.
var isps = {
yahoo: ["#yahoo.com", "#rocketmail.com", "#ymail.com"],
gmail: ["#gmail.com"]
};
for(isp in isps) {
var providers = isps[isp];
document.write(isp + " has " + providers.length + " provider(s):<br/>");
providers.forEach(function(domain) {
document.write(domain + "<br/>");
});
};
This works because instead of looping through an array and trying to access different variables with the same name, you can instead simply loop through the keys of an object (which are the same as that first array) and use it to access the values of that object (which are the same as in the other variables you had before).
Note that I've changed your alerts to things that will be more informative in running the code snippet. Of course, once you've got access to these values isp, providers and domain, you can do whatever you like with them - you don't need to document.write them.
There are a few benefits to this method. For instance, as we're only human, what if this happened:
var isp = ["yahoo"];
var yahooo = ["#yahoo.com"];
There's a dependency on the values in isp and the variable names being exactly the same. A simple error like above ("yahooo" instead of "yahoo") would prevent the code from working, and a one letter bug like that could be quite difficult to find if you don't know what you're looking for.
If you're to come back and add or modify these values often, this could become a concern. With the object pattern, it's cleaner and more self-contained.
One potential concern with this solution, however, is if the order in which these providers are looped through is important (i.e. if you always need "yahoo" to output before "gmail"). Currently JavaScript states the following in regards to objects: "It is an unordered collection of properties". This could be subject to change in ES6 (we're currently on ES5). Read more about this particular issue here:
Does JavaScript Guarantee Object Property Order?
You will need to eval the isp[x] in order to get the array names of the other two. For example:
var isp = ["yahoo", "gmail"];
var yahoo = ["#yahoo.com", "#rocketmail.com", "#ymail.com"];
var gmail = ["#gmail.com"];
for(x=0;x<isp.length;x++){
//Should alert 3 Because var yahoo contains 3 element
//Should alert 1 because var gmail is contain 1 element
alert(isp[x].length);
for(y=0;y<eval(isp[x]).length;y++){
//Should alert #yahoo.com, #rocketmail.com and so on
alert(eval(isp[x])[y]);
}
}
This is clear i guess right ?
:D
var ispAndData = [
["yahoo", ["#yahoo.com", "#rocketmail.com", "#ymail.com"]],
["gmail", ["#gmail.com"]]
];
for (x = 0; x < ispAndData.length; x++) {
//Should alert 3 Because var yahoo contains 3 element
//Should alert 1 because var gmail is contain 1 element
document.write(ispAndData[x][0] + " -> ");
document.write(ispAndData[x][1].length + "</br>");
for (y = 0; y < ispAndData[x][1].length; y++) {
//Should alert #yahoo.com, #rocketmail.com and so on
document.write(ispAndData[x][1][y] + "</br>");
}
document.write("</br>");
}
I'm trying to dynamically find a particular value inside a multi dimensional object.
To create the object, I'm doing this:
var inViewElements = {};
$('.story-section')
.each(
function(index){
var sectionId = 'story-section-' + Math.floor(Math.random() * (1000 - 1 + 1)) + 1;
$(this).attr('id', sectionId);
var inViewHeight = $(this).height(),
inViewPosTop = $('#' + sectionId).offset().top,
inViewPosBottom = ((inViewPosTop + inViewHeight) - (inViewTolerence + inViewHeight));
inViewElements[inViewPosTop] = {
id: sectionId,
height: inViewHeight,
bottom: inViewPosBottom
};
debug('Inview', 'Object', sectionId);
debug('Inview', 'Height', inViewHeight);
debug('Inview', 'Offset Top', inViewPosTop);
debug('Inview', 'Offset Bottom', inViewPosBottom);
}
);
console.log(inViewElements);
And the output looks like:
What I'm trying to do is compare if another variable value, for example:
var currentPos = '3038';
Matches any of the objects keys. E.g. the 3038 or 2038 etc.
I'm struggling to figure this one out!
So you're trying to search for an object that contains a certain value?
There is no way to query an array/object in Javascript. As you're not using incremental indexes, I would suggest using a foreach loop, using a conditional statement to check whether the property you're trying to match is equal to the value you're looking for.
It would be quicker to use a for loop, however that would require incremental indexes.
If you r logging response variable through which ur output came then u can use this function
for(var x in response){
if( x == 3038) {
// do something
}
}
or
for(var x in response){
if(x == currentPos){
//dosomething
}
}
can u give me the proper code of how u put values to console log so i will edit the answer properly accourding to your question
I can not get around JSHint's error message. Here is the loop I am using:
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(function(item) {
return {
id: item[0],
title: item[1],
};
})
});
}
You can just move the function outside the loop and pass a reference to it to map:
function mapCallback(item) {
return {
id : item[0],
title : item[1],
};
}
for (i = 0; i < Collection.length; i += 4) {
data.push({
items: Collection.slice(i, i + 4).map(mapCallback)
});
}
Alternatively, you can use a JSHint directive to ignore function expressions inside loops. Just put this at the top of the file in question:
/*jshint loopfunc: true */
Declaring a function in a loop is messy, and potentially error prone. Instead, define the function once, and then enter the loop.
var objMaker = function(item) {
return {
id : item[0],
title : item[1],
};
};
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(objMaker)
});
}
People say "Declaring a function in a loop is messy and potentially error-prone", but functions within loops is what directly instructed in, for example, Array.prototype.forEach method. Just because the word "function" should theoretically mean defining it anew in every forEach call it does not mean it is actually defined each time by the Javascript engine.
The same goes for outer loops since engines have "lazy" processing of instructions. They are not going to redefine the whole forEach/Map/etc construct-instruction anew if nothing really changed about it, they will just feed new arguments to it.
The times of ancient JS engines which were clueless about such simple things as well as of code context are long gone. And yet we are getting this ancient warning which was conceived when functions were not yet capable of being passed as arguments as in the cases of forEach or Map.