I am new to programming and I have been looking for solutions, but what I find are more complciated solutions than it should be and I am being asked.
I have this HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<h3>Pizza toppings:</h3>
<ul id="ingredients">
<li>Batsilica</li>
<li>Tomtato</li>
<li>Morezarella</li>
<li>Hams</li>
</ul>
</body>
</html>
So I have to change the ingredients with the console.
I wrote this so I get printed the list:
let toppings = document.querySelectorAll('#pizza-toppings li');
for (let i = 0; i < ingredients.length; i++) {
console.log(ingredients[i].innerText);
}
I dont know how to modify those items of the list one by one. It shouldnt be any replaceChild nor change the list completely, but selecting them and "modifying them".
maybe I get the children list of the element with qSelector but still dont know how to correct the spelling of those. It is not like I can right click in the printed list and edit it.
Help? Thanks
Infact we use # to select an id, so you need to put your list's id which is ingredients. And your array of matching items is called toppings, so you need to set your loop limit to toppings.length.
Although i would recommend using map instead of for loop
let toppings = document.querySelectorAll('#ingredients li');
for (let i = 0; i < toppings.length; i++) {
console.log(toppings[i].innerText);
}
This should display all of your items on the console. But if you want to edit item, for example you want to change "Tomtato" into "Meat" you have to do
toppings[1].innerText="Meat"
you don't have any element #pizza-toppings in document. So, toppings is empty node list. ingredients is object, not array of li elements. If you want iterate over li try this:
let ingredients = document.querySelectorAll('#ingredients li');
for (let i = 0; i < ingredients.length; i++) {
console.log(ingredients[i].innerText); }
}
One way to grab all of the list items and then modify them (provided you want to perform the same operation on all of the li's) would be to put them in an array:
let ingredients = document.getElementById("ingredients").getElementsByTagName("li");
//create empty array:
let ingredients_list = []
//create loop to iterate over every li:
for (let i = 0; i < ingredients.length; i++) {
//create variable to grab the text from each <li>:
let ingredients_text = ingredients[i].innerText;
//add the text from each li to the ingredients_list array:
ingredients_list.push(ingredients_text);
}
// you will now have all of your li's in an array where you can manipulate them as you wish using any array methods. For example, lets convert all of the text to uppercase and then log it to the console using the forEach array method:
ingredients_list.forEach(element => console.log(element.toUpperCase()))
//returns:
"HAMS"
"BATSILICA"
"TOMTATO"
"MOREZARELLA"
The above is just a basic example of how you can manipulate a list that has been converted into an array using the forEach method.
Another basic example would be to return all the items from the array in a single string using the join method:
console.log(ingredients_list.join(" "))
You can see a full list of available methods at the following link on the left navbar:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
I'm not sure what you want to do exactly with the list items (the original question is not 100% clear) but hopefully this points you in the right direction.
Related
I am trying to generate a Javascript array of objects (to later be saved as JSON file) from the html of this web page: https://remoteok.io/remote-dev+javascript-jobs
I want to extract the job descriptions for the first section (listed under "Today") - hidden beneath a dropdown until you click on each job listing. See screenshot:
The layout has been built with tables: The Job listing and Job description html containers are both sibling table rows <tr>.
On the site, the first "listing" with the text "the first health insurance for remote startups" is promotional content so doesn't have hidden job description text when you click on it below.
So in my code I start at index position 2 and then iterate by multiples of two in the for loop. This part works. But then I need to add this job description to each object in the array (called scrapedArray) already created from other data:
const first_table_row = $(first_section).find('tr');
for(var i = 2; i < first_table_row.length; i+= 2) {
let job_description = $(first_table_row[i]).find('.markdown').html().trim();
// console.log(job_description);
scrapedArray.forEach((obj) => {
obj["job_description"] = job_description;
});
}
Console logging job_description without the forEach gets each distinct job description as intended, but when I include the forEach it simply repeats the same html for the same Scalable Path job listing, see here (output of job_description truncated as html is quite long):
(2) [{…}, {…}]
0:
company_logo: "https://remoteok.io/assets/jobs/07a835281c655f47e04cd5799f27d219.png?1584688805"
job_description: "\nScalable Path is looking for a Senior Full Stack.."
__proto__: Object
1:
company_logo: "https://remoteok.io/assets/jobs/9e96332ed226d8ffd20da84b6951b66e.png?1584649206"
job_description: "\nScalable Path is looking for a Senior Full Stack.."
What am I doing wrong? Is there a better way to do this?
When you loop forEach inside your for loop, all job_description in your array will be assigned to one variable, so it will have the same value (of the last for loop). I've changed the for loop from 1 instead of 2, because you need company_logo, right?
Check the bellow code, I've checked and it works!
let scrapedArray = [];
// Get the first tbody
let first_section = $('#jobsboard tbody')[0];
const first_table_row = $(first_section).find('tr');
for (var i = 1; i < first_table_row.length; i += 2) {
let company_logo = $(first_table_row[i]).find('.logo').attr('src');
let job_description = $(first_table_row[i + 1]).find('.markdown').html().trim();
scrapedArray.push({
company_logo, job_description
});
}
console.log(scrapedArray);
Hope this helps!
I have the following scenario:
A JSON object array gets fetched with angular ajax and displayed as list with ng-repeat.
The list gets sorted by object property "index", which is set as default input value of the respective list item.
The user can change the input values.
On press of a button, the list gets redrawn, sorted by the updated input values.
Now there should be a counter, ++ whenever a list item changes position.
I so far managed to count all list items with updated values.
How do I register position changes for the other list items that change position?
For example: #3 changes position to #1, then #1 and #2 also change position.
Second, using Dragula, the list items are now draggable.
How can I resort the list after list items were dragged?
I also tired Angular Dragula without success.
here is my code on github.
Thank you for your help!
I had a similar issue. You need a way of getting the DOM indexing and updating the JavaScript object to match. I looped through the DOM elements, got their index values, found the corresponding item in the data object and then set the index value in the object to that of the DOM index value. Hope this example helps someone.
var updateIndexes = function() {
// this gets the index of any DOM element, like jQuery index()
function getIndex(el) {
for (var i = 0; el = el.previousElementSibling; i++);
return i;
}
// loop through the list DOM elements
for (var i = 0; i < dataArray.length; i++) {
var dataId = dataArray[i].id;
var domIndex = getIndex(document.getElementById(dataId));
dataArray[i].index= domIndex;
}
};
imagine I have an excel like grid that consists of two parts.
A column and a list.
The column is the columns and the list is the entire collection of the all of the rows.
I can get my columns list with a .length and a .length on the list gives me the number of rows.
So I have my x and my y now.
I want to create an object out of this that would work something like this:
var = ObjList {
row0 = [],
row1 = [],
row2 = [],
column = [],
};
The issue is that the list can be modified in length. The only way i see to approach this is to programmatically create variables. Like so ( psuedo code )
//Variables
var itemName
//Get Column Names
for (var j in columns) { //columns is an object/array
var cName =columns[j].getName(); //I have to get the name otherwise cName just returns as ListItem
columnList.push(cName); //Push cName to my own array so I have an array of strings
}
for (var i in listItems) { //Again working with an object array
item = listItems[i] //Creating an easier reference variable
for (var j = 0; j < columnList.length - 1;j++){ //now I have to use the length of the Column array to find out how wide our list is
itemName = item.getValueByName(columnList[j]); //turning the listitem into a string
row(i).push(itemName); //the is the programmatic variable.
}
}
The problem is I'm not sure where I would declare the variable. Is there some other way for me to loop through the List array and match each index of the listItems array to the index of the column which I am doing here with the getValueByName(columnList[j]).
******************************Edit********************************
An example was requested and I can see how this would be confusing. This is dealing with google sites specifically.
I added comments to the above code as well.
We have a grid.This grid is actually two parts. The column is an object which is why I am creating another array and putting the names into the array. The list is another object. ( LI = lineItem )
|Col1|Col2|Col3|Col4|<~~~ Column Object
|LI |LI |LI |LI |<~~~~~~~~~~~~~~~~~~~|
|LI |LI |LI |LI |<~~~~~~~~~~~~~~~~~~~| List Object
|LI |LI |LI |LI |<~~~~~~~~~~~~~~~~~~~|
WHat I want is to be able to iterate through a loop and break each row into its own array.
I have been able to do that successfully one at a time. But since I would like to have one array per row and the number of rows is dynamic ( because a user can add more rows ) I am confused as to how I would account for that.
I want the entire grid to exist as an object with row properties and column properties that are array. So row0 would be row0[LI1,LI2,LI3,LI4]
Columns[]~~>|Col1|Col2|Col3|Col4| ~~~~~~~|
row0[]~~~~~>|LI1 |LI2 |LI3 |LI4 | ~~~~~~~|
row1[]~~~~~>|LI1 |LI2 |LI3 |LI4 | ~~~~~~~|ObjList
row2[]~~~~~>|LI1 |LI2 |LI3 |LI4 | ~~~~~~~|
Again the width of the grid is
Column.length
and the number of rows can be defined by
itemList.length
So I guess the question is can I have an array of arrays?
So I could have
//Variables
var itemName;
var masterArray = [];
var midArray = [];
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
for (var i in listItems) {
item = listItems[i]
for (var j = 0; j < columnList.length - 1;j++){
itemName = item.getValueByName(columnList[j]);
midArray.push(itemName);
if (midArray > columnLisst.length -1) {
masterArray.push(midArray);
midArray.length = 0;
}
}
}
It feels clunky and wrong though.
Yes, you can have a 2 dimensional array in JavaScript. What you have now is an object with another level which is an array, so, in terms of dimensions, there really isn't any difference. Whether it's an object with arrays, or an object with other objects, or an array with other arrays; in all situations you have that second level.
The only issue really is; do you want to be able to access values by name rather than by index? If you want to access values by name, then use an object. Have you considered having an object inside of an object?
I don't see that you are programatically declaring variables. Maybe there is a misunderstanding of the terminology.
In this situation, where there is a second level of data, it would be normal to have nested FOR loops, so even though it's more complex, I don't think it would be considered clunky or wrong.
You'll need to run the code and look at the results to figure out what will work for you. You can use Logger.log("some text: " + aVariableName); statements to print information to the LOG, then VIEW the LOG. Also, view the EXECUTION TRANSCRIPT.
You can also step through lines of code, one line at a time, line by line and view the results.
If you have a specific problem that you can't figure out, provide the error message, and what line of code is producing the error message.
I have this array tv, when I read this array with a loop for, it just give me the last item, in this case Toshiba,
how can I do to it show me the TV brands??
for (var i=0;i<tv.length;i++){
$('#item').html(tv[i].Brand)}
<div id='item'></div>
Array tv:
var tv = [{"Name":"TV","Brand":"Samsung"},
{"Name":"TV","Brand":"Toshiba"},
{"Name":"TV","Brand":"LG"}]
html() overwrites the content on each iteration, that's why only the last one is visible, the others are overwritten. You should be using append:
$('#item').empty();
for (var i=0; i<tv.length; i++){
$('#item').append(tv[i].Brand);
}
The problem: You have only one div#item element and you are updating its value in every iteration.
Solution: Dynamically create and append an element to show each item in the array like:
for (var i=0;i<tv.length;i++){
$('<div/>').addClass('item').html(tv[i].Brand).appendTo('.container');
}
where:
item is a class - now that you have multiple elements
container - assumed to the parent element under which you want the items displayed
I have an javascript array, which looks like:
var styles = new Array();
styles[0] = { ... Position: 0, ... };
styles[1] = { ... Position: 1, ... };
styles[2] = { ... Position: 2, ... };
...
styles[N] = { ... Position: N, ... };
I use this array to display a list, where each item is a div. The end result is this:
<div id="container">
<div>... item 1...</div>
<div>... item 2...</div>
<div>... item 3...</div>
</div>
Now the "container" div is also jquery sortable. That way I can drag/drop the items and change the position. Now whenever the user drags an item to a different position I update the positions back in the array by looping through the div items, which is pretty bad. It looks more or less like that:
var items = $("#container");
for (var i = 0; i < items.length; i++)
{
....
styles[i] = { ... Position: i, ... };
}
Is there a better way to achieve this?
Update 1:
I need to save the positions in the database, which is why I need change my array after the list has been changed. The list changes depending on other criterias. So I could have a list of 10 items or I could have a list of X items. It depends on which list the users selects. Now if the user changes one list and then wants to see a second list, then I need to make sure that the first list maintains the positions.
I think Drew Wills response is on the mark, and this might also help. A div is a JavaScript object, which means you can add properties to it. So you might be able to reduce the number of lines of JavaScript code and increase the code's expressiveness by sticking your "information object" right onto each div, meaning you'd no longer need your array.
Where does your array come from in the first place? I'm going to assume it is a JSON-ified version of some data you have on the server. So I'm assuming (guessing) that you have some kind of "each" or for loop that creates the divs from the array, perhaps like this:
for (var i = 0; i < styles.length; i++)
{
var newDiv = $("<div>" + style[i].item + "</div>";
$("#container").append(newDiv);
}
Assuming you have that, then you could modify it to this:
for (var i = 0; i < styles.length; i++)
{
var newDiv = $("<div>" + style[i].item + "</div>";
// KEY NEW LINE FOLLOWS:
newDiv.myCustomObject = styles[i];
$("#container").append(newDiv);
}
Now, as the divs get sorted all over the place, this "myCustomObject" goes along with them. You don't need the array anymore. If you need the "Position" property on "myCustomObject" to be updated, use the "index" property of the div, as Drew Wills said.
So, imagine that your "styles" object has a property in it called "Color". Imagine you want to show an alert on click that tells the color associated with the div they clicked on. You can now accomplish this without needing the "styles" array, because the divs now have everything you need. So you could do this:
$("#container div").click(function() {
alert("The color is " + this.myCustomObject.Color);
});
Later, when it comes time to post or send via ajax the positions, you could do this:
$("#container div").each(function(index) {
this.myCustomObject.Position = index;
}
NOTE: Also, some people would prefer to use the JQuery data() method to associate "myCustomObject" with the div. It achieves the same result and perhaps gets garbage collected more completely in some browsers.
Why is it you need to know the position?
You won't have to track the position at all if you can rely on jQuery's $.index() method.
When you need to know the position of an element, just use something like the following...
$("#container div").index(myDiv);
UPDATE 1:
I see -- the server needs to know the positions to store them in the DB. Nevertheless, I'm not crazy about the notion of having 2 representations of this data on the page: markup (divs), and JS array. I would look at changing my code to build the array (from the divs) at the last second... just before you send it to the server. That way you can loop over the divs in order and you won't have to maintain the order in parallel in a separate data structure. Keeping 2 structures in sync in messy and can be error-prone
Little disclaimer: I don't know everything about your page. I don't know anything about your situation that would make this suggestion unworkable, but I suppose there may be something out there.
Little tip: if there are data elements int he area that aren't represented in the markup somehow, consider just tagging the markup with arbitrary info.
link text