Dynamically created list items draggable JavaScript - javascript

I am dynamically populating a list of senators, separated by political affiliation. That part works. I need to make each list item draggable. I can't get that to work.
I tried this:
document.getElementById(name).setAttribute('draggable');
in my list population loop, but I really don't know if that's the right way.
senatorList.forEach(({name, party}) => {
let itemEl = document.createElement('li');
itemEl.textContent = name;
let listId = party === 'Democrat' ? '#democrats' : '#republicans';
let listEl = document.querySelector(listId);
document.getElementById(name).setAttribute('draggable');
listEl.appendChild(itemEl);
});

Your code contains a couple of errors:
setAttribute requires two arguments: attribute and value.
You called document.getElementById(name) before adding itemEl to the document.
If I understood your intentions correctly, the code should look similar to this:
const senatorList = [{
name: 'senator1',
party: 'Democrat'
},
{
name: 'senator2',
party: 'Democrat'
},
{
name: 'senator3',
party: 'Republican'
},
];
senatorList.forEach(({
name,
party
}) => {
let itemEl = document.createElement('li');
itemEl.textContent = name;
let listId = party === 'Democrat' ? '#democrats' : '#republicans';
let listEl = document.querySelector(listId);
itemEl.setAttribute('draggable', 'true');
listEl.appendChild(itemEl);
});
<div id="democrats"></div>
<div id="republicans"></div>

Related

How can I generate a list from a Javascript Array filtered based on local storage value?

I am trying to make a page which displays an HTML list that has been filtered using a value stored in localStorage. I have only been able to display the full array, or nothingat all.
Below is sample code from my project which demonstrates this problem. The code is a collection of snippets I pieced together from other code samples.
I have tried to find an answer, but my JavaScript level is basic.
const itemList =
[
'Ryan',
'Shannon',
'Sita',
'Greta',
'Zack',
'Zach',
'Alfredo',
'Joe',
'Jeff',
'Cameron',
'Kevin',
'Kyle',
'Ron',
'Merriam',
'Shane',
'Stitch',
];
const itemContainer = document.getElementById("item-list");
let searchInput = localStorage.getItem("nSearch");
searchInput.onkeyup = (event) => {
filterBySearch(event.target.value);
};
const itemHTML = (item) => `<li>${item}</li>`;
const filterBySearch = (query = "") => {
var renderHTML = ``;
itemList.forEach((item) => {
if (item.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
renderHTML += itemHTML(item);
}
});
itemContainer.innerHTML = renderHTML;
};
filterBySearch();
LocalStorage stores values as strings.
let searchInput = localStorage.getItem("nSearch");
So, at this point, searchInput is a string. So, the following line won't work:
searchInput.onkeyup = (event) => {
filterBySearch(event.target.value);
};
If nSearch represents an element already in the document, then try
let searchInput = Array.from(document.querySelectorAll('a')).find(el=>el.outerHTML == localStorage.getItem("nSearch"));
But if nSearch isn't an element in your page, you'll have to add it before you can put an onkeyup event listener on it.

How to access elements inside an array of objects in Javascript for a movieapp prototype

I've only shown the JS part of my code because the .html part only has one input box with name="my-input" inside a form.
What happens in this function is, if I enter 'Adventure' in my input box it gives me Edge of Tomorrow as the title of the movie and if I enter Romantic it gives me Lalaland likewise. Now what I want is, shown in the movieList1() function i.e. I have two objects with same genre 'Adventure' for example, then I would want both the movie title, 'Edge of Tomorrow' and 'Dark Force' to be shown in my empty list with id 'here'. I want title of all the movies to be shown if the genre is similar but I'm able to only get one movie title at a time that is shown. I'm new to JS and object and array of objects looks a little confusing. Any help would be very much appreciated.
function movieList(){
//This function is called in an 'onkeyup' event inside the input box.
var x = document.forms["my-form"]["my-input"].value; // x has what the user enters inside the
inputbox.
const objList = [{
title:'Edge of Tommorow',
Genre: 'Adventure',
},
{
title:'DarkForce',
Genre: 'Tactical',
},
{
title:'LalaLand',
Genre:'Romantic'
}];
objList.forEach((ele,index) => {
if(ele.Genre=='Adventure' && x==ele.Genre) {
var ans = ele.title;
document.getElementById('here').innerHTML = ans; // 'here' has the id of an empty <li></li> where
the title is shown.
}
else if(ele.Genre=='Tactical' && x==ele.Genre)
{
var ans = ele.title;
document.getElementById('here').innerHTML = ans;
}
else if(ele.Genre=='Romantic' && x==ele.Genre)
{
var ans = ele.title;
document.getElementById('here').innerHTML = ans;
}
else if(x=='')
{
document.getElementById('here').innerHTML='';
}
});
}
function movieList1(){
//This function is called in an 'onkeyup' event inside the input box.
var x = document.forms["my-form"]["my-input"].value; // x has what the user enters inside the input
box.
const objList = [{
title:'Edge of Tommorow',
Genre: 'Adventure',
},
{
title:'DarkForce',
Genre: 'Tactical, Adventure',
},
{
title:'LalaLand',
Genre:'Romantic,Tactical'
}];
objList.forEach((ele,index) => {
if(ele.Genre=='Adventure' && x==ele.Genre) {
var ans = ele.title;
document.getElementById('here').innerHTML = ans; // 'here' has the id of an empty <li></li> where
the title is shown.
}
else if(ele.Genre=='Tactical' && x==ele.Genre)
{
var ans = ele.title;
document.getElementById('here').innerHTML = ans;
}
else if(ele.Genre=='Romantic' && x==ele.Genre)
{
var ans = ele.title;
document.getElementById('here').innerHTML = ans;
}
else if(x=='')
{
document.getElementById('here').innerHTML='';
}
});
}
I'm guessing this is what you want to do.
const objList = [{
title: 'Edge of Tommorow',
Genre: 'Adventure',
},
{
title: 'DarkForce',
Genre: 'Tactical',
},
{
title: 'LalaLand',
Genre: 'Adventure'
}];
let Gen = "Adventure"; // suppose this is from your input
let temp = []; // create an array to store all similar genre title
objList.forEach(x => {
if (x.Genre == Gen) {
temp.push(x.title);
}
})
console.log(temp);
Output:
[ 'Edge of Tommorow', 'LalaLand' ]
you can also store objects in the temp array.
Thinking you are expecting the output like:: (Method movieList1)
for inputGenre=Tactical output will be DarkForce,LalaLand
for inputGenre=Adventure output will be Edge of Tommorow,DarkForce
document.getElementById("txtGenre").addEventListener("keyup",searchMovies)
function searchMovies(){
let inputGenre=document.getElementById("txtGenre").value;
const objList = [{
title:'Edge of Tommorow',
Genre: 'Adventure',
},
{
title:'DarkForce',
Genre: 'Tactical, Adventure',
},
{
title:'LalaLand',
Genre:'Romantic,Tactical'
}];
let filterdData =objList.filter(r=>r.Genre.includes(inputGenre));
console.log(filterdData);
document.getElementById("result").innerHTML=filterdData.map(r=>r.Genre).join(",");
}
#result{
background-color:green;
}
Genre input: <input type="text" id="txtGenre" onClick="searchMovies"/>
<br/>
Output Movies List:
<div id="result">
</div>
There reason you are getting only one movie name is, you are re-writing the HTML again with the latest movie that matched the criteria each time forEach runs. You need to adjust your variables and how you assign your result to HTML.
Lets keep ans out of the loop, so it doesn't get overwrittern. And write to html at the end, after you have filtered all per your input.
var ans = [];
objList.forEach((ele,index) => {
if(ele.Genre=='Adventure' && x==ele.Genre) {
ans.push(ele.title);
} else if(ele.Genre=='Tactical' && x==ele.Genre) {
ans.push(ele.title);
} else if(ele.Genre=='Romantic' && x==ele.Genre) {
ans.push(ele.title);
}
// We dont need this
// else if(x=='') {
// document.getElementById('here').innerHTML='';
// }
});
document.getElementById('here').innerHTML = ans.join(', ');
At last, you join the answer using the in-built array function.
Now if you notice, your if statements are pretty much the same except for the hardcoded genre. So you could further refactor it.
var ans = [];
var genre = 'Adventure'; // assign your genre from input box here.
objList.forEach((ele,index) => {
if (ele.Genre == genre && x==ele.Genre) {
ans.push(ele.title);
}
});
document.getElementById('here').innerHTML = ans.join(', ');
Now you would have a single if statement which is easy to understand and modify.

Adding inline tags within text node in javascript

Hi there this might be easy but I am new and just learning I need help with 2 problems.
First, when creating element using document.createElement() how to add class or id to that element?
---- found a solution for this problem of className = "" or id="" by adding a variable to differentiate the data originated from the array which I added and named id ----
Second, using createTextNode() to avoid using the innerHTML how to add the line breaker tag within?
Lets say I have an array of items = [{id: "item-1", name: "apple", price:1} , {id:"item-2" ,name : "mango", price:3}];
and I want to go through them with:
let data = document.getElementById("items-data");
items.forEach(item => {
let container = document.createElement("div"), //here i want to add a defined id for further use
itemData = document.createTextNode(
`item name : ${item.name} price: ${item.price}`); //here i want to add the br
container.appendChild(itemData);
container.id = item.id;
data.appendChild(container);
};
Do you mean something like this:
container.appendChild(document.createElement("br"));
let base = document.querySelector(".base");
let items = [{
id: "item-1",
name: "apple",
price: 1
}, {
id: "item-2",
name: "mango",
price: 3
}];
items.forEach(item => {
let container = document.createElement("div"), //here i want to add a defined id for further use
itemData = document.createTextNode(
`item name : ${item.name} price: ${item.price}`); //here i want to add the br
container.appendChild(itemData);
container.appendChild(document.createElement("br")); // <-- Add the line break to the node element
container.id = item.id;
base.appendChild(container);
});
<div class="base"></div>

Preventing duplicate objects from being added to array?

I am building a little shop for a client and storing the information as an array of objects. But I want to ensure that I am not creating "duplicate" objects. I have seen similar solutions, but perhaps it is my "newness" to coding preventing me from getting the gist of them to implement in my own code, so I'd like some advice specific to what I have done.
I have tried putting my code in an if look, and if no "part", my variable looking for part number, exists in the code, then add the part, and could not get it to function.
Here is the function I am working on:
function submitButton(something) {
window.scroll(0, 0);
cartData = ($(this).attr("data").split(','));
arrObj.push({
part: cartData[0],
description: cartData[1]
});
}
arrObj is defined as a global variable, and is what I am working with here, with a "part" and a "description", which is the data I am trying to save from elsewhere and output to my "#cart". I have that part working, I just want to ensure that the user cannot add the same item twice. (or more times.)
Sorry if my code is shoddy or I look ignorant; I am currently a student trying to figure these things out so most of JS and Jquery is completely new to me. Thank you.
You can create a proxy and use Map to hold and access values, something like this
let cart = new Map([{ id: 1, title: "Dog toy" }, { id: 2, title: "Best of Stackoverflow 2018" }].map(v=>[v.id,v]));
let handler = {
set: function(target,prop, value, reciver){
if(target.has(+prop)){
console.log('already available')
} else{
target.set(prop,value)
}
},
get: function(target,prop){
return target.get(prop)
}
}
let proxied = new Proxy(cart, handler)
proxied['1'] = {id:1,title:'Dog toy'}
proxied['3'] = {id:3,title:'Dog toy new value'}
console.log(proxied['3'])
Assuming the 'part' property is unique on every cartData, I did checking only based on it.
function submitButton(something) {
window.scroll(0, 0);
cartData = ($(this).attr("data").split(','));
if(!isDuplicate(cartData))
arrObj.push({
part: cartData[0],
description: cartData[1]
});
}
const isDuplicate = (arr) => {
for(obj of arrObj){
if(arr[0] === obj.part)
return true;
}
return false;
}
If you want to do the checking on both 'part' and 'description' properties, you may replace the if statement with if(arr[0] === obj.part && arr[1] === obj.description).
Thanks everyone for their suggestions. Using this and help from a friend, this is the solution that worked:
function submitButton(something) {
window.scroll(0,0);
cartData = ($(this).attr("data").split(','));
let cartObj = {
part: cartData[0],
description: cartData[1],
quantity: 1
}
match = false
arrObj.forEach(function(cartObject){
if (cartObject.part == cartData[0]) {
match = true;
}
})
console.log(arrObj);
if (!match) {
arrObj.push(cartObj);
}
Okay, you have multiple possible approaches to this. All of them need you to specify some kind of identifier on the items which the user can add. Usually, this is just an ID integer.
So, if you have that integer you can do the following check to make sure it's not in the array of objects:
let cart = [{ id: 1, title: "Dog toy" }, { id: 2, title: "Best of Stackoverflow 2018" }];
function isInCart(id) {
return cart.some(obj => obj.id === id);
}
console.log(isInCart(1));
console.log(isInCart(3));
Another approach is saving the items by their id in an object:
let cart = { 1: { title: "Dog toy" }, 2: { title: "Best of Stackoverflow 2018" } };
function isInCart(id) {
if(cart[id]) return true;
return false;
}
Try to use indexOf to check if the object exists, for example:
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('aaa'));
// expected output: -1

Render each Objects in an array in HTML from JavaScript

I have a JavaScript array of objects taken from a JSON file. Each object in the array represents a product. The following code shows the JavaScript. The console.log displays each element in the console, however the innerHTML only renders the last as this is the last value to be rendered.
/* global $ */
var output = document.getElementById('output');
var products = [];
$.getJSON('/products', function(data){
output.innerHTML = data
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
output.innerHTML = data[keys].NAME;
}
// output.innerHTML = products;
//console.log(products)
});
I want each product to be rendered in it's own output div. How would I display each element in the HTML instead of just the last?
Just append the element to your output. Actually you did it.
Change this:
output.innerHTML = data[keys].NAME;
To this:
$('#output').append(`<div>${data[keys].NAME}</div>`);
So:
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
$('#output').append(`<div>${data[keys].NAME}</div>`);
}
I would recommend you also to change the for...in with a simple forEach, so to change the loop into this:
data.forEach((el) => {
products.push(el);
$('#output').append(`<div>${el.NAME}</div>`);
});
The error in your code was just that you were overriding the HTML content of your element every time. If you change:
output.innerHTML = data[keys].NAME;
to this:
output.innerHTML += data[keys].NAME;
It should already work
You can use jQuery "append". You dont need to make product object.
Try like this:
for(var keys in data){
$(".productList").append( "<div>"+data[keys].NAME+"</div>" );
}
Basically, your output element should be a wrapper containing other elements repeated for each product. One semantic option is to use a list, such as ul + li.
You should iterate your products and append its piece of HTML to an array. When you are done processing them, you assign that chunk of HTML to the output element.
// Just to keep your code untouched:
const $ = {
getJSON(url, callback) {
callback([{
ID: 1,
NAME: 'Product 1',
PRICE: '2.50',
}, {
ID: 2,
NAME: 'Product 2',
PRICE: '1.25',
}, {
ID: 3,
NAME: 'Product 3',
PRICE: '10.00',
}]);
},
};
const output = document.getElementById('output');
let productsArray = [];
$.getJSON('/products', function(products){
productsArray = products;
output.innerHTML = products.map(product => {
return `<li data-id="${ product.ID }">
<span>${ product.NAME }</span>
<span>${ product.PRICE }</span>
</li>`;
}).join('');
});
<ul id="output"></ul>
$('#output').append(`<div>${data[keys].NAME}</div>`);
In reference to #VK321, you can also use the .map method.
data.map(element => {
$(".productList").append( `<div>${element.NAME}</div>` );
})

Categories

Resources