Get Length of nested JavaScript object - javascript

I want to fill a list with elements from a database. The data comes from a PHP file in JSON format. The JSON looks like this:
{"Venues" : [{"name":"McManus Galleries","id":"1"},{"name":"Dundee Law","id":"2"},{"name":"University of Abertay","id":"3"},{"name":"Baxter Park","id":"4"},{"name":"Overgate Shopping Centre","id":"5"}]}
Now I am handling this text with the following code:
obj = JSON.parse(this.responseText);
document.getElementById("list").innerHTML = "<a onclick='getVenue("+obj.Venues[0].id + ")'>" + obj.Venues[0].name + "</a><br>";
document.getElementById("list").innerHTML += "<a onclick='getVenue("+obj.Venues[1].id + ")'>" + obj.Venues[1].name + "</a><br>";
...and it works, but now I want to do it with a for-loop so no matter how many items "Venues" contains it is showing them all in the list. I got this code right now:
for(i = 0; i < obj.length; i++){
document.getElementById("list").innerHTML += obj.Venues[i].name;
}
The problem here is, that obj.length returns 1. Does anybody know how to solve this?

obj is the main object that has child Venues (that is an array to be used for iteration as below)
for(i = 0; i < obj.Venues.length; i++){
document.getElementById("list").innerHTML += obj.Venues[i].name;
}

Related

JavaScript create appropriate number of rows and columns based off of list length

I've been struggling with converting the following C# code into something I can use in JavaScript:
var g = Model.List.GroupBy(r => Model.List.IndexOf(r) / 3).ToList();
It's use was to create the appropriate number of rows, with the appropriate number of columns within them. So for example if the list had 6 elements it would allow me to create 3 rows with 2 columns in it, this was all done in razor pages using the above GroupBy and the below code:
foreach (var parent in g)
{
#Html.Raw("<div class='row'>");
foreach (var item in parent)
{
// populate contents of row
}
#Html.Raw("</div>");
}
However for certain reasons I can't do this in Razor and need to create an alternative in JavaScript but I'm struggling to figure out a way to do this.
Primarily because I don't understand entirely how 'GroupBy' creates the list of groups and what would be a suitable alternative.
Any help, or pointing in the right direction would be great. I've tried a few solutions I found online for creating 'GroupBys' but I couldn't get them to work the way I was expecting. I also thought maybe I could split the original list into a list of dictionaries, but again had little success. I'm possibly missing something obvious.
In the end it turns out I was just missing the obvious answer, I found this excellent SO answer. I had looked at slice but couldn't quite visualise how to use it for my problem (obviously been a long day).
The post showed this snippet:
var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
// do whatever
}
In the end my JavaScript code looked something like this:
var listdata = await octokit.repos.listForUser({ "username": "", "type": "owner" });
var chunk = 2;
var loop = 0;
var tempArray = [];
for (var s = 0; s < listdata.data.length; s += chunk) {
tempArray[loop] = listdata.data.slice(s, s + chunk);
loop++;
}
var htmlString = "";
for (var t = 0; t < tempArray.length; t++) {
htmlString += "<div class='row'>";
var innerArray = tempArray[t];
for (var r = 0; r < innerArray.length; r++) {
var repo = innerArray[r];
htmlString +=
"<div class=\"col-md-6 col-sm-6 col-xs-12\">" +
"<div>" + repocontent + "</div>" +
"</div>"
}
htmlString += "</div>";
}
So with a list that's 6 items long, it gets split into an array that contains 3 lists of 2 items. Then I just create the html string using two for loops to create the outer bootstrap rows and the inner column classes. There's probably a more efficient way to do this but this worked a treat.

Javascript TypeError states a list is undefined

I created a function which receives a list as input and then operates on that list:
function selected_items(list) {
for (i=0;i<=list.length;i++){
item = list[i].split("-");
item_id = item[0] + '-' + item[1] + '-' + item[2]
user_id = item[4]
$('#shift_data_' + user_id).children('#' + item_id).toggleClass('selected')
}
}
The list is composed by some strings like this : ["a-b-c", "a1-b1-c1", etc.]
I want to process the strings one by one, split them after the operator "-" and then do some work on that to help me select some items in the DOM.
The funny part is that the code works as expected however in the console I get
the following error:
TypeError: list[i] is undefined
--> item = list[i].split("-");
Any ideas on why I'm getting this error even though the code is working?
You are looping the list out of range. Try changing this:
for (i=0; i<=list.length; i++){
by this:
for (i=0; i<=list.length - 1; i++){
or this:
for (i=0; i < list.length; i++){

Different values from different arrays and append together beside one another in a table

So, am currently trying to pull out two different array values from arrays chanArrId & chanArrName via express(socket.io) & node.js.
Then once I have those display them in a table on the same row E:G
<tr class="exe">
<td>SIP/487-00000060</td>
<td>0000000001</td>
</tr>
<tr class="exe">
<td>SIP/488-00000060</td>
<td>0000000002</td>
</tr>
Then for the next set take a new row, do the same for the following channel values.
When I add another pull the next two out without repeating itself. I have had some kind of success but always fall just short, with wrong positioning or duplicated values.
I have it working fine with one value but not both so:
Call extension 488: Add Channel name and value to the page from array etc.
Works for the first one it works fine as seen at the top it works grand then I get the following when I add a second pair of values:
<tr class="exe" id="exe">
<td>SIP/487-00000060</td>
<td>1445964898.228</td>
<td>1445964898.2281445964900.229</td>
</tr>
It skips the SIP name and then just adds two channel ids in the next row.
Below is the latest code have been tweaking, to see what ave been trying to accomplish.
Client side
socket.on('sipname', function (data,datad) {
var sipname = '';
var sipid = '';
$(".exe").remove();
for (i = 0; i < data.length; i++) {
sipname += data[i];
if (sipname) {
$sipname.append('<tr class="exe" id="exe">\
<td id="siptd">' + sipname + '</td>');
}
for (i = 0; i < datad.length; i++) {
sipid += datad[i];
if (sipid) {
$('#sipTable td:last').after('<td>' + sipid + '</td></tr>');
}
}
sipid = '';
}
});
Server side function
function updateSip() {
io.sockets.emit('sipname', chanArrName,chanArrId);
chandump();
}
Stasis: Where am pushing values into array
bridge.addChannel({
channel : channel.id
}, function (err) {
var name = chanArrName.push(channel.name)
var id = chanArrId.push(channel.id)
updateSip();
if (err) {
throw err;
}
Hope you guys can give me a little bit of guidance.
In the client code you have a nested for-loop with the same index variable as the outer loop, which means the outer one will not run as many times as expected.
Also, the += operator will concatenate new values to previous values, explaining the concatenated channel ids you notice. You are already expanding the DOM with nodes incrementally, so there is no need to use +=. Just assign. The same holds for the outer loop: just assign to sipname with =.
Indenting your code correctly may also help debugging it.
Finally, declare your index variable(s) with var.
With these corrections, you get this:
socket.on('sipname', function (data, datad) {
var sipname, sipid, dataHtml;
$(".exe").remove();
for (var i = 0; i < data.length; i++) {
sipname = data[i];
if (sipname) {
dataHtml = '<td id="siptd">' + sipname + '</td>';
for (var j = 0; j < datad.length; j++) {
sipid = datad[j];
if (sipid) {
dataHtml += '<td>' + sipid + '</td>';
}
}
$sipname.append('<tr class="exe" id="exe">' + dataHtml + '</tr>');
}
}
});
EDIT:
Above code was updated after comments. This version concatenates the HTML for each TD in a variable, to then finally wrap it in a TR tag and append it to $sipname. I have no view on the variable $sipname, so I assume it is set correctly.
There is one thing you certainly need to fix:
The code sets values for the id properties of the generated nodes, but always the same ones. This is not acceptable in HTML: an id should be unique in the document.
This is how I managed to tackle it in the end:
socket.on('sipname', function (data, datad) {
var sipname = '';
var sipid = '';
$('.exe').remove();
for (var i = 0; i < data.length; i++) {
sipname = data[i];
sipid = datad[i];
if (sipname) {
$sip.html('<tr class="exe">\
<td class="sipid">' + sipid + '</td>\
<td class="sipname">' + sipname + '</td>\
<td><button class="btn btn-default mute" id="mute" type="submit"><span>Mute</span></button></td>\
<td><button class="btn btn-default kick" id="kick" type="submit">Kick</button></td>\
</tr>');
}
}
});
Because am handling the two arrays at the same time on the server side and how there are both directly related every time I pull them out into the web page I simply E.G Channel.name & Channel.id
I just started calling out the value along with sipname as they will both have the same set of values every time and also get added or removed at the same time.
Hope this makes sense.
This is how I got it to work in the end for those who want an alternate solution.

Selector syntax for not inside a container

I made this helper function to assist me with stuff
function formToObject(form) {
var items = form.querySelectorAll("[name]");
var json = "{";
for (var i = 0; i < items.length; i++) {
json += '"' + items[i].name + '":"' + items[i].value + '",';
}
json = json.substring(0, json.length-1) + "}";
return JSON.parse(json);
}
There is a problem with it though, it doesn't exclude forms that are inside the form element thats passed to it. Didn't come up before but now it seems to be necessary. Is there a way to write the selector string in a way that it would exclude any children of other forms inside it?
Like "[name]:not(form *)" (which obviously doesn't work)
EDIT: got a little closer with "[name] :not(fieldset) *" but that also ignores the immediate fieldset children

Print every record of an array on the same page with Javascript

I have an array with a variable amount of records. And I want to print every record of the array in the same html page. I prefer it to display in a list.
I have the following code. However this does only print the last record of the array because it overwrites the previous record in my html ul-element.
for (var i = 0; i < feedbackGeenLid.length; i++)
{
document.getElementById("feedback").innerHTML= ("<li>"+feedbackGeenLid[i] + "</li>");
}
Does anyone have an idea on how to realize this?
Your code keeps replacing the innerHTML you need to add to it.
document.getElementById("feedback").innerHTML += ("<li>"+feedbackGeenLid[i] + "</li>");
^
|
Added + here
For better performance build one string and set it to innerHTML at the end of the loop.
var out = "";
for (var i = 0; i < feedbackGeenLid.length; i++)
{
out += "<li>"+feedbackGeenLid[i] + "</li>";
}
document.getElementById("feedback").innerHTML= out;
Another option, use appendChild()
you are rewriting the content in each loop. use a variable to concatenate the content and then put it in the element:
var html = '';
for (var i = 0; i < feedbackGeenLid.length; i++)
{
html += "<li>"+feedbackGeenLid[i] + "</li>";
}
document.getElementById("feedback").innerHTML= html;

Categories