How many people are from each city ? (Javascript Object) - javascript

I'm trying to list an object in the following format but I can't figure out how to enumarade the li or put them inside their own ol any help??
It looks like your post is mostly code; please add some more details.
It looks like your post is mostly code; please add some more details.
let myObj = [
{
name:"Pablo",
age:"39",
job:"retired",
city:"LA",
},
{
name:"Ernesto",
age:"20",
job:"student",
city:"LA",
},
{
name:"Katrina",
age:"25",
job:"lawyer",
city:"LA",
},
{
name:"Mario",
age:"55",
job:"doctor",
city:"Lancaster",
},
{
name:"Luigi",
age:"50",
job:"Server",
city:"Lancaster",
},
{
name:"Peach",
age:"10",
job:"street",
city:"Labrea",
}
];
let target = document.getElementById('target');
let cityName = null;
for(i=0;i<myObj.length;i++){
if (cityName == null && myObj[i].city){
target.innerHTML += `<h3 class="cityTitle">${myObj[i].city}</h3>`;
}
if (cityName && cityName != myObj[i].city){
if (cityName) {
target.innerHTML += `<h3 class="cityTitle">${myObj[i].city}</h3>`;
}
target.innerHTML += `<li>${myObj[i].name}</li>`;
} else {
target.innerHTML += `<li>${myObj[i].name}</li>`;
}
cityName = myObj[i].city;
}
.cityTitle{
border: 1px solid black;
}
h3{
margin: 0;
padding: 0px 10px;
background-color: rgb(245, 185, 185);
}
<div id="target"></div>
Expected:
LA
Pablo
Ernesto
Katrina
Lancaster
Mario
Luigi
Labrea
Peach

get unduplicated cities first, then do the loop to render.
// get unduplicated cities
const cities = [...new Set(data.map(person => person.city))];
//render html
cities.forEach(city => {
//get persons in city
const persons = data.filter(person => person.city === city);
target.innerHTML += `<h3 class="cityTitle">${city}</h3>`;
target.innerHTML += persons.map(p => `<li>${p.name}</li>`).join('');
});

Related

Retrieve array of objects from local storage

Trying to make to-do list but I have difficulties with local storage. First i don't understand why does local storage returns [object Object] instead of actual text. Secondly at some point local storage becomes empty and then begins to fill in from the beginning. That's so confusing for me
function addTask() {
let addTaskButton = document.getElementById('add-task-button')
let list = document.getElementById('task-list');
let li = document.createElement('li');
let checkbox = document.createElement('input');
let taskText = document.createElement('span');
let delButton = document.createElement('button');
let btnText = document.createTextNode('Delete task');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
taskText.innerText = document.getElementById('input-task').value;
taskText.className = 'task';
delButton.className = 'delete-btn';
delButton.addEventListener('click', deleteTask)
delButton.addEventListener('click', updateStorage)
addTaskButton.addEventListener('click', updateStorage);
delButton.appendChild(btnText);
li.appendChild(checkbox);
li.appendChild(taskText);
li.appendChild(delButton);
list.appendChild(li);
document.getElementById('input-task').value = '';
taskList.push({
text: taskText.innerText,
checked: false
});
}
let taskList = [];
function updateStorage() {
localStorage.setItem('tasks', JSON.stringify(taskList));
console.log(taskList)
}
function deleteTask () {
this.parentNode.remove();
}
document.getElementById('add-task-button').addEventListener('click', addTask);
function loadList() {
document.querySelector('ul').innerHTML = JSON.parse(localStorage.getItem('tasks')) || [];
}
window.addEventListener('load', loadList);
this way:
const
inputTask = document.querySelector('#input-task')
, addTaskBt = document.querySelector('#add-task-button')
, taskList = document.querySelector('#task-list')
, tasks = JSON.parse(localStorage.getItem('tasks') || '[]')
, savTasks =_=> localStorage.setItem('tasks',JSON.stringify(tasks))
;
tasks.forEach( newLItask )
addTaskBt.onclick =_=>
{
if (inputTask.value.trim()==='') return
let taskElm = { txt: inputTask.value.trim(), checking:false }
tasks.push( taskElm )
newLItask( taskElm )
savTasks()
inputTask.value = ''
inputTask.focus()
}
taskList.onclick = ({target}) => // event delegayion for all buttons & checkboxes
{
if (!target.matches('button.delete-btn, input[type=checkbox]')) return
let taskIndex = tasks.findIndex(task => task===target.closest('li').ref )
if (target.matches('input[type=checkbox]'))
tasks[taskIndex].checking = target.checked
else // delete
{
tasks.splice(taskIndex,1)
target.closest('li').remove()
}
savTasks()
}
function newLItask( taskElm )
{
taskList
.appendChild(Object.assign(document.createElement('li'), {ref:taskElm} ))
.innerHTML = `
<input type="checkbox" class="checkbox" ${taskElm.checking ? 'checked': ''}>
<span class="task"> ${taskElm.txt} </span>
<button class="delete-btn">Delete task</button>`
}
for testing:
#task-list {
padding : 0;
list-style-type : none;
}
#task-list li {
margin : .4em 0;
}
#task-list li > span {
display : inline-block;
width : 20em;
border-bottom : 1px solid lightsteelblue;
margin : 0 .6em 0 0;
}
#task-list input[type=checkbox]:checked + span {
text-decoration : line-through ;
text-decoration-style : wavy;
text-decoration-color : orangered;
}
<input type="text" id="input-task" placeholder="input task" size="26">
<button id="add-task-button" >add task</button>
<ul id="task-list"></ul>
I made this a comment on the original post, but I think this might qualify as the answer...
The JSON.parse gets you an object, and when you try to use that object as a string (setting the innerHTML of an element), you'll get the "[object Object]" text. What's stored in localStorage is a string already that represents your JSON. Just set the innerHTML to what comes back from your localStorage.getItem('tasks') call.

Display slider when you hover over array elements and give value to the array elements

I have done the part where you have to generate the array elements when you enter them from textbox, what I struggle with now is to display a slider on hover over each array element and give the array element a value, also what I struggle with is to delete each generated array element individually, my delete function deletes the entire array on click not just the single element I click.
Here is how it should look like:
enter image description here
Here is my code so far:
let names = [];
let nameInput = document.getElementById("name");
let messageBox = document.getElementById("display");
function insert ( ) {
names.push( nameInput.value );
clearAndShow();
}
function remove()
{
var element = document.getElementById("display");
element.parentNode.removeChild(element);
}
function clearAndShow () {
let printd=""
nameInput.value = "";
messageBox.innerHTML = "";
names.forEach(function(element){
if(element != ''){
var _span = document.createElement('span');
_span.style.borderStyle = "solid"
_span.style.borderColor = "blue"
_span.style.width = '50px'
_span.style.marginLeft = "5px"
_span.appendChild(document.createTextNode(element))
messageBox.appendChild(_span)
printd +="''" + element + "''" + "," + " ";
document.getElementById("labelprint").innerHTML=(printd)
}
})
}
h3 {
color: rgb(0, 174, 255);
}
.container {
border: solid 2px;
display: block;
margin-left: 200px;
margin-right: 200px;
margin-top: 50px;
}
<div class="container">
<form>
<h1>Enter Search</h1>
<input id="name" type="text" />
<input type="button" value="Search" onclick="insert()" />
</form>
<br/>
<div onclick="remove(this)" id="display"></div>
<br/>
<label >You have Selected: </label>
<h3 id="labelprint"></h3>
</div>
I am not being rude I just got confused on how you stated your message but what I think you are saying is to do this:
var names = [];
var nameInput = document.getElementById("name");
var messageBox = document.getElementById("display");
function insert ( ) {
names.push( nameInput.value );
// add value to array val: names[names.length - 1] = PutValueHere
clearAndShow();
}
function remove(this){
document.getElementById("display").parentNode.firstChild.remove(); // If you want it to remove the last child with the id 'display' then do .parentNode.lastChild.remove()
//if you are trying to remove the last val in the array do this: names.splice(names.length-1,1) for the first do this names.splice(0,1)
}
function clearAndShow () {
var printd=""
nameInput.value = "";
messageBox.innerHTML = "";
names.forEach(function(element){
if(element != ''){
var _span = document.createElement('span');
_span.id = '_spanId'
$('_spanId').css('border-style',solid');
$('_spanId').css('border-color',blue');
$('_spanId').css('width',50+'px');
$('_spanId').css('margin-left',5+'px');
_span[0].appendChild(document.createTextNode(element))
messageBox[0].appendChild(_span)
printd += "''" + element + "'', ";
document.getElementById("labelprint").innerHTML = printd
}
})
}
I have tried to implement something that i hope it's close to what are you looking for:
HTML:
<div class="container">
<form>
<h1>Add new slider</h1>
<input id="sliderName" type="text" />
<input type="button" value="Add" onclick="insertSlider()" />
</form>
<div id="display"></div>
</div>
CSS:
h3 {
color: rgb(0, 174, 255);
}
.container {
border: solid 2px;
display: block;
margin-left: 200px;
margin-right: 200px;
margin-top: 50px;
}
JS:
let messageBox = document.getElementById("display");
function deleteFn(id) {
const element = document.getElementById(id)
if(element) element.outerHTML="";
}
function onChangeSlideId(id){
const elementSlide = document.getElementById('slider-'+id+'')
if(elementSlide){
const value = elementSlide.value
const elementSlideText = document.getElementById('slider-value-'+id+'')
elementSlideText.innerText = '('+value+')'
}
}
function insertSlider(){
const name = document.getElementById("sliderName")
const nameValue = name.value
const newLabel = document.createElement('label')
newLabel.setAttribute('for',nameValue)
newLabel.innerText = nameValue
const newSlider = document.createElement('input')
newSlider.setAttribute('id','slider-'+nameValue+'')
newSlider.setAttribute('type','range')
newSlider.setAttribute('name',nameValue)
newSlider.setAttribute('onchange','onChangeSlideId("'+nameValue+'")')
const sliderValue = document.createElement('span')
sliderValue.setAttribute('id','slider-value-'+nameValue+'')
sliderValue.innerText = '('+newSlider.value+')'
const newContainer = document.createElement('div')
newContainer.setAttribute('id',nameValue)
newContainer.setAttribute('style','display: grid')
newContainer.appendChild(newSlider)
newContainer.appendChild(newLabel)
newContainer.appendChild(sliderValue)
const newDeleteButton = document.createElement('input')
newDeleteButton.setAttribute('type', 'button')
newDeleteButton.setAttribute('value', 'Delete ' + nameValue + '')
newDeleteButton.setAttribute('onclick', 'deleteFn("'+nameValue+'")')
newContainer.appendChild(newDeleteButton)
messageBox.appendChild(newContainer)
}
You can try it by yourself in this codepen

Accessing multiple classes and ids in an ES6 array

How would I go about accessing a specific id or class that's inside querySelectorAll but in es6? I need to target specific elements for specific animations.
HTML
<div id="title">...</div>
<div class="text">...</div>
<div id="image">...</div>
What I'd like to do something like this
let elems = document.querySelectorAll("#title, .text, #image");
elemsArray = [...elems];
elemsArray.forEach(element => {
elemsArray[0].classList.add("title-animation");
elemsArray[1].classList.add("text-animation");
elemsArray[2].classList.add("image-animation");
});
Instead of what I currently have
let titleAnim = document.querySelectorAll("#title"),
textAnim = document.querySelectorAll(".text"),
imageAnim = document.querySelectorAll("#image");
for (const title of titleAnim) {
title.classList.add("title-animation");
}
for (const text of textAnim) {
text.classList.add("text-animation");
}
for (const image of imageAnim) {
image.classList.add("image-animation");
}
What is the ES6 equivalent to the code above? Also, here's the classic version
let elements = document.querySelectorAll("#title, .text, #image");
for (let i = 0; i < elements.length; i++){
elements[i, 0].classList.add("title-animation");
elements[i, 1].classList.add("text-animation");
elements[i, 2].classList.add("text-animation");
}
Update:
Here's what works thanks to Darth
const elems = [...document.querySelectorAll("#title, .text, #image")];
elems.forEach(element => {
let clas = "";
if(element.id === "title") clas = "title-animation";
if(element.id === "image") clas = "image-animation";
if(element.classList.contains ("text")) clas = "text-animation";
element.classList.add(clas)
})
const elems = [...document.querySelectorAll("#title, .text, #image")];
elems.forEach((element, i) =>
element.classList.add(["title-animation", "text-animation","image-animation"][i%3]))
// code above will work only if elements are ordered.
// if not, you need to check each element for choose class:
elems.forEach(element => {
let clas = "";
if(element.id === "title") clas = "title-animation";
if(element.id === "image") clas = "image-animation";
if(element.classList.contains ("text")) clas = "text-animation";
element.classList.add(clas)
});
.title-animation{ color: green }
.text-animation{ color: red }
.image-animation{ color: blue }
div{ font-size: 50px; }
<div id="title">...</div>
<div class="text">...</div>
<div id="image">...</div>
No ifs:
[
["#title", "title-animation"],
[".text", "text-animation"],
["#image", "image-animation"]
].forEach(([selector, className]) =>
[...document.querySelectorAll(selector)]
.forEach(el => el.classList.add(className))
)
.title-animation{ color: green }
.text-animation{ color: red }
.image-animation{ color: blue }
div{ font-size: 50px; }
<div id="title">...</div>
<div class="text">...</div>
<div id="image">...</div>

Validating a form

IM working on a simple form, and Im trying to validate the fields,
with below code I able to validate the field and add a message if the field is empty.
}
First you need to scan the page for labels:
var labels = document.getElementsByTagName('LABEL');
for (var i = 0; i < labels.length; i++) {
if (labels[i].htmlFor != '') {
var elem = document.getElementById(labels[i].htmlFor);
if (elem)
elem.label = labels[i];
}
}
Then you can simply use following in your IF-ELSE condition,
document.getElementById(id).label.classList.add('red-text');
and
document.getElementById(id).label.classList.remove('red-text');
I also added CSS class for the text to be red.
.red-text {
color: #ff0000;
}
Final code:
function validation(id) {
var labels = document.getElementsByTagName('LABEL');
for (var i = 0; i < labels.length; i++) {
if (labels[i].htmlFor != '') {
var elem = document.getElementById(labels[i].htmlFor);
if (elem)
elem.label = labels[i];
}
}
var value = document.getElementById(id).value;
if (value === "" || value == null) {
document.getElementById('Err' + id).innerHTML = "- Field Required";
document.getElementById(id).classList.add('class');
document.getElementById(id).label.classList.add('red-text');
} else {
document.getElementById('Err' + id).innerHTML = "";
document.getElementById(id).classList.remove('class');
document.getElementById(id).label.classList.remove('red-text');
}
}
.class {
background: #f97d7d;
color: #ff0000;
border: 1px solid #ff0000 !important;
}
.red-text {
color: #ff0000;
}
<label for="Name">* Name <span class="error" id="ErrName"></span></label>
<input type="text" name="Name" id="Name" onblur="validation('Name')">
Change your javascript code to following:
function validation(id) {
var value = document.getElementById(id).value;
if (value === "" || value == null) {
document.getElementById('Err' + id).innerHTML = "- Field Required";
document.getElementById(id).classList.add('class');
var label = findLabel(document.getElementById('Name'));
label.classList.add('class');
} else {
document.getElementById('Err' + id).innerHTML = "";
document.getElementById(id).classList.remove('class');
var label = findLabel(document.getElementById('Name'));
label.classList.remove('class');
}
}
function findLabel(el) {
var idVal = el.id;
labels = document.getElementsByTagName('label');
for (var i = 0; i < labels.length; i++) {
if (labels[i].htmlFor == idVal)
return labels[i];
}
}
.class
{
background: #f97d7d;
color: #ff0000;
border: 1px solid #ff0000 !important;
}
<label class="" for="Name">* Name <span class="error" id="ErrName"></span></label>
<input type="text" name="Name" id="Name" onblur="validation('Name')">
I've added a function findLable to get the label for that input, and using that, added error class to that label.
The span is defined as class "error" but you haven't defined that class.
I think it is better to bind blur and input events
the code:
Name.addEventListener('blur', function(){
if (!Name.value){
ErrName.innerHTML="Field Required";
this.classList.add('class');
ErrName.parentNode.style.color="red";
}
});
Name.addEventListener('input',function(){
if (Name.value.length && ErrName.innerHTML=="Field Required" ){
ErrName.innerHTML="";
this.classList.remove('class');
ErrName.parentNode.style.color="black";
}
});
a liddle fiddle

How to compare numerical values of two innerHTML elements? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am trying to compare the numerical values of elements in Javascript (Still learning, so I am grateful for any help).
Currently I have the code:
if (parseInt(document.getElementById("player1").innerHTML) > parseInt(document.getElementById("player2").innerHTML)) {
document.getElementById("gametitle").innerHTML = "Player 1 wins!"
} else if (parseInt(document.getElementById("player2").innerHTML) > parseInt(document.getElementById("player1").innerHTML)) {
document.getElementById("gametitle").innerHTML = "Player 2 wins!"
} else if (parseInt(document.getElementById("player1").innerHTML) > parseInt(document.getElementById("computer1").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You win!"
} else if (parseInt(document.getElementById("player1").innerHTML) > parseInt(document.getElementById("computer2").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You win!"
} else if (parseInt(document.getElementById("player1").innerHTML) > parseInt(document.getElementById("computer3").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You win!"
} else if (parseInt(document.getElementById("computer1").innerHTML) > parseInt(document.getElementById("player1").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You lose!"
} else if (parseInt(document.getElementById("computer2").innerHTML) > parseInt(document.getElementById("player1").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You lose!"
} else if (parseInt(document.getElementById("computer3").innerHTML) > parseInt(document.getElementById("player1").innerHTML)) {
document.getElementById("gametitle").innerHTML = "You lose!"
} else {
document.getElementById("gametitle").innerHTML = "There's an error!"
}
Any help would be greatly appreciated.
The issue here is that you are using the innerHTML when you should be using innerText. See Difference between innerText and innerHTML in javascript
Also, since you mentioned you are new to programming, here are some best practices for you.
If you are going to be comparing the values multiple times you should save the value in a variable instead of constantly using the resources to retrieve the same value.
var player1 = parseInt(document.getElementById("player1").innerText)
var player2 = parseInt(document.getElementById("player2").innerText)
var player3 = parseInt(document.getElementById("player3").innerText)
var computer1 = parseInt(document.getElementById("computer1").innerText)
var computer2 = parseInt(document.getElementById("computer2").innerText)
var computer3 = parseInt(document.getElementById("computer3").innerText)
You are also comparing multiple scores using the same logic so instead of repeating this code you should write a function. A function is a block of code that you can name and call later, see here for more information: http://www.w3schools.com/js/js_functions.asp
function compareScores(playerScore,computerScore){
if (playerScore > computerScore){
document.getElementById("gametitle").innerText = "You win!"
} else if (computerScore > playerScore){
document.getElementById("gametitle").innerText = "You lose!"
} else {
document.getElementById("gametitle").innerText = "You Tied!"
}
}
Now you just need to call this function with the values for each set.
compareScores(player1,computer1)
compareScores(player2,computer2)
compareScores(player3,computer3)
Don't use innerHTLM, as it returns... HTML. parseInt won't work on that. Use innerText instead:
if (parseInt(document.getElementById("computer3").innerText) > parseInt(document.getElementById("player1").innerText)) {
// Do something
}
Also, it will help you a lot if you first extract the values, then compare them:
var computer3Score = parseInt(document.getElementById("computer3").innerText);
var player1Score = parseInt(document.getElementById("player1").innerText);
if (computer3Score > player1Score) {
// do something
}
Relying on the DOM to store the data is a bad practice. What if you want to use the same logic and data with a different view ? You would have to refactor the entire code. Rather do the opposite, generate the DOM based on a data structure that is the unique source of data for all your application. Thus, you don't need the DOM to manage the data anymore.
In the example below, the data source is an array called "players". Try to add a new player to the array and see how easier it is to manage. Moreover, if you want to change the HTML of the score board, you just have to edit the template once for all players. This template is located in the function called "dataToHtml".
var players, tbody, button, indexOf;
players = [
{ name: "John", score: 2 },
{ name: "Mary", score: 1 },
{ name: "Bot 1", score: 4 },
{ name: "Bot 2", score: 3 }
];
indexOf = Array.prototype.indexOf;
button = document.getElementsByTagName("button")[0];
tbody = document.getElementsByTagName("tbody")[0];
tbody.innerHTML = dataToHtml();
button.onclick = function () {
var i, best, trs;
best = bestScore();
trs = tbody.childNodes;
for (i = 0; i < trs.length; i++) {
trs[i].style.backgroundColor = (
players[i].score == best ? "yellow" : "white"
);
}
};
tbody.onclick = function (ev) {
var i, tr, score, name;
tr = ev.target.parentNode;
i = indexOf.call(this.childNodes, tr);
name = players[i].name;
score = prompt("New score for " + name + " :");
if (!isNaN(score = parseInt(score, 10))) {
tr.childNodes[1].textContent = score;
players[i].score = score;
}
};
function bestScore () {
var i, best;
for (i = 0; i < players.length; i++) {
if (i == 0 || players[i].score > best) {
best = players[i].score;
}
}
return best;
}
function dataToHtml () {
var i, html = "";
for (i = 0; i < players.length; i++) {
html += ""
+ "<tr>"
+ "<td>" + players[i].name + "</td>"
+ "<td class=\"score\">" + players[i].score + "</td>"
+ "</tr>";
}
return html;
}
body, button {
font: normal 12px Arial;
}
div {
display: inline-block;
vertical-align: middle;
text-align: center;
}
table {
margin-right: 1em;
}
table, th, td {
border-collapse: collapse;
border: 1px solid #999;
padding: .25em;
}
td.score {
text-align: right;
}
<div>
<table>
<thead>
<tr>
<th>player</th>
<th>score</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div><div>
<p><button type="button">Who wins ?</button></p>
<p>click a row<br />to change<br />the score</p>
</div>

Categories

Resources