I'm making a moviefilter website for school. Now the last part is that I need to link the imdbID from my array to the movie posters on the screen. I made the links, the filter mechanics work but when I click on a poster all the ID's of that filter are being added to the end. Not just one.
My teacher says I can forEach trough the movieArray array and write everything I need in that loop. Can someone help me or look at my code what I'm doing wrong. I wrote 2 seperate functions now to create the arguments needed.
My code:
const addMoviesToDom = function (movieArray) {
const movieList = document.querySelector("#movielist");
movieList.innerHTML = "";
const moviePoster = movieArray.map(item => {
return item.Poster;
});
const imdbId = movieArray.map(item => {
return item.imdbID;
})
moviePoster.forEach(element => {
let newLi = document.createElement("li");
let newLink = document.createElement("a");
let images = document.createElement("img");
images.src = element;
newLink.setAttribute("href", "https://www.imdb.com/title/" + imdbId);
newLink.setAttribute("target", "_blank");
newLi.append(newLink);
newLink.append(images);
movieList.appendChild(newLi);
})
};
addMoviesToDom(movies);
Thanks in advance, hopefully you guys understand what I'm trying to explain, this is all pretty new for me.
imdbId is an array of all the IDs. When you concatenate that to "https://www.imdb.com/title/" it's turned into a string, which joins all the IDs with a , delimiter. So you're not setting the href to just the ID corresponding to the current moviePoster element.
You need to index the array to get the correct ID. forEach provides the array index as the second argument to the callback function, so you can change element => to (element, i) =>, and then use imdbId[i].
But a simpler way would be to skip creating the moviePoster and imdbId arrays, and just create all the elements from movieArray.
const addMoviesToDom = function(movieArray) {
const movieList = document.querySelector("#movielist");
movieList.innerHTML = "";
movieArray.forEach(element => {
let newLi = document.createElement("li");
let newLink = document.createElement("a");
let images = document.createElement("img");
images.src = element.Poster;
newLink.setAttribute("href", "https://www.imdb.com/title/" + element.imdbId);
newLink.setAttribute("target", "_blank");
newLi.append(newLink);
newLink.append(images);
movieList.appendChild(newLi);
})
};
addMoviesToDom(movies);
Related
I am practicing blog stuff. posting and deleting posts. mini social media I can say. And I wanted to save posts on localStorge. however I could save only 1 post at a time. and then I wanted to do it with IDs.
I create id with random number generator:
let newId = Math.floor(Math.random() * (1000000 - 100000) + 100000)
let postContents = {
ID : newId,
text: value,
}
an then I upload those values in let storedPosts = [] array.
then I save it to local storage with JSON:
let toJson = () => {
localStorage.setItem('storedPosts', JSON.stringify(storedPosts));
}
and then I get it from Local Storage:
let storedJsonPosts = localStorage.getItem('storedPosts')
let storedPosts_toUpload = JSON.parse(storedJsonPosts)
and then I join these two arrays together:
let storedPostsArray = storedPosts.concat(storedPosts_toUpload)
and after this I don't know what to do. I tried this:
let uploadStoredPosts = () => {
for (let i = 0; i < storedPostsArray.length; i++) {
let post = document.createElement('div')
$post_place.appendChild(post)
let text = document.createElement('p')
post.appendChild(text)
text.textContent = storedPostsArray[i].text
}
}
but it showed this:
It couldn't reach array values. plz help
Is this something that you're after?
The code reads from localStorage, parses that information, returns an empty array if it's the first time the user posted, pushes a new value to the array, stores that array by stringifying it, and the appending the new value to the document.
If you want the page to read from localStorage on page load, you need to add a function that reads from localStorage, and then loops through all posts to add each one of them by using appendToDocument().
StackOverflow doesn't allow the use of localStorage, so I used a variable for demo purposes.
I left out id as a property. You can play around with that by yourself, but I would suggest to use a timestamp as a foreign key ("id").
var justForDemoPurpose = null;
const addPostBtn = document.getElementById("add-button");
const addPostInput = document.getElementById("add-post");
const postContainerEl = document.getElementById("post-container");
addPostBtn.addEventListener('click', addPost);
function readFromLocalStorage(key) {
let localStorageItem = JSON.parse(justForDemoPurpose);
// let localStorageItem = JSON.parse(localStorage.getItem(key));
console.log('returning items:', localStorageItem);
return localStorageItem;
}
function storeInLocalStorage(key, value) {
justForDemoPurpose = JSON.stringify(value);
// JSON.stringify(localStorage.setItem(key, value));
}
function addPost() {
let postValue = addPostInput.value;
if (postValue) {
const LOCAL_STORAGE_KEY = 'posts';
let storedPosts = readFromLocalStorage(LOCAL_STORAGE_KEY) || [];
storedPosts.push(postValue);
storeInLocalStorage(LOCAL_STORAGE_KEY, storedPosts);
appendToDocument(postValue);
}
}
function appendToDocument(postValue) {
let divEl = document.createElement('div')
divEl.textContent = postValue;
postContainerEl.appendChild(divEl);
}
<div class="addPostContainer">
<input id="add-post" placeholder="Type here"> <button id="add-button">Add Post</button>
</div>
<section id="post-container"></section>
Evening folks.
Trying to wrap up my to do list and I'm not able to remove items from localStorage without either deleting everything from using the wrong key or the contents just re-appearing on page refresh. A second smaller issue is that button text is merging into the innerText, like it's supposed to, but I can't find a way to exclude it It is currently commented out, if I don't then it breaks the previous entry. I've left my most recent, and rather poor attempt, below but otherwise, the rest appears to be working.
Not sure if it's ok to attach the whole code, but here it is below.
const todoForm = document.querySelector('#todoForm');
const todoList = document.querySelector('#todoList');
let todoItem = document.querySelector('#todoItem');
// const todo = JSON.parse(localStorage.getItem('todo'));
// Pull from storage
const savedList = JSON.parse(localStorage.getItem('todo')) || [];
for (let i = 0; i < savedList.length; i++) {
const newTodo = document.createElement('li');
newTodo.innerText = savedList[i].item;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.isCompleted = savedList[i].isCompleted ? true : false;
if(newTodo.isCompleted) {
newTodo.style.textDecoration = 'line-through';
}
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
}
// Add Item and Remove Button
todoForm.addEventListener('submit', function(e){
e.preventDefault();
const newTodo = document.createElement('li');
const newItem = document.querySelector('#todoItem').value;
const newButton = document.createElement('button');
let itemId = { id: new Date().getTime() };
// newButton.innerText = 'Remove';
newButton.setAttribute('id', itemId.id);
newTodo.innerText = newItem;
newTodo.setAttribute('id', itemId.id);
newTodo.isCompleted = false;
todoList.appendChild(newTodo);
newTodo.appendChild(newButton);
todoForm.reset();
// Save to storage
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
localStorage.setItem('todo', JSON.stringify(savedList));
});
// Strike Through Item
todoList.addEventListener('click', function(e){
let clickListItem = e.target;
if (!clickListItem.isCompleted){
clickListItem.style.textDecoration = 'line-through';
clickListItem.isCompleted = true;
} else {
clickListItem.style.textDecoration = 'none';
clickListItem.isCompleted = false;
}
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
});
// Remove from storage
todoList.addEventListener('click', function(e){
let removeItem = e.target;
const taskId = e.target.id;
if (e.target.tagName === 'BUTTON'){
e.target.parentNode.remove();
removeFunc(taskId);
}
});
function removeFunc(taskId){
for (let i = 0; i < savedList.length; i++){
const key = savedList[i].id;
if(key === taskId.id){
localStorage.removeItem(key);
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
}
Thanks for any insight.
My first guess looking at this would be the that, since the IDs are being defined by Date.getTime() being called at two different times, that those IDs are not the same. I would suggest that, when you push to savedList at the end of the function to add an item, that you set id as newItem.id, like you for the item name, rather than calling getTime() again
I do see few problems in your code. Here we go.
Remove text reappears because on adding an item, you create todo object with item value set to newTodo.innerText, if you check your saved value in the localstorage it holds extra Remove in it, that's because innerText gets the text of elements under newTodo (in our case we have a button in there). As a fix, you just need to set the actual value from the textbox and not the innerText. You already have that stored in a variable called newItem
And yes, as like #cfinn16 pointed it out, the id we save here would be in number format, when you compare the id from remove button attribute with the id from the savedList array you will see a mismatch. As a resolution, you can convert getTime().toString().
savedList.push({ item: newTodo.innerText, isCompleted: false, id: new Date().getTime() });
Deleting an item, not actually removing the item from both in-memory array i.e savedList or from the localStorage. All we want to do it, just get the taskId, filter/remove items from savedList then replace it in the localStorage with same key. But on loading each todoItems on page refresh, you set new date as the value to each todoItems but that should be the value from the localstorage itself.
let itemId = { id: new Date().getTime() };
Strikethrough an item, has a similar problem. Here you are trying to find clicked item from the array using text instead we can use the id itself.
for (let i = 0; i < savedList.length; i++) {
if (savedList[i].item === clickListItem.innerText) {
savedList[i].isCompleted = !savedList[i].isCompleted;
localStorage.setItem('todo', JSON.stringify(savedList));
}
}
Solution:
https://codepen.io/renishb10/project/editor/ANyqqo
Let me know if you've any questions.
With the help from Renish, I've modified to include the follow and posting it here so it may help anyone else.
// Save to storage
savedList.push({ item: newItem, isCompleted: false, id: new Date().getTime().toString() });
localStorage.setItem('todo', JSON.stringify(savedList));
Changed the new Date() to a string. As both Renish and cfinn pointed out I had mismatch .id. Changing newTodo to newItem go around my innerText from the button being carried over.
// Pull from Storage
newButton.innerText = 'Remove';
newButton.setAttribute('id', savedList[i].id);
Modified my pull from storage code to reflect the new button .id.
function removeFunc(taskId){
splicedList = savedList.filter(l => l.id != taskId)
localStorage.setItem('todo', JSON.stringify(splicedList));
}
Used a filter instead to find the items to remove, based on the .id.
Github of the full modified code:
https://github.com/BreadsticksN7/collections/blob/20b679fc704d05af5576faa3963f676c0bd2665e/todolist.js
Thanks to everyone and their assistance.
Below is a snippet of some of my code. Think a todo list on steriods. I am trying to create multiple Div elements that save to a page that contain a different list every time my "Save button is pressed. whats actually happening is that multiple divs are showing but the original div saved is the only one that gets updated with the list information(so like in a todo list when you click submit a new list item appears ive added a save button and an input field that the user can use to name their list and saves that list to a container but only one div gets updated). I know i'm almost there but ive been looking at this for a couple of hours now and cant quite figure it out. https://github.com/W33K5Y/TODO-PIRPLE
const saveButton = document.getElementById("submit-save");
const myLists = document.getElementById("my-lists");
const startNote = document.getElementById("start-note");
const listName = document.getElementById("new-list-name");
const myUl = document.getElementById("my-ul-lists");
// ! savebutton listener
saveButton.addEventListener("click", addNewTodo);
// ! make new html elements
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
// ! =============== function for creating new todo ================================
function addNewTodo() {
const todoDiv = document.querySelector(".todo-container");
const todos = document.querySelectorAll(".todo-item");
todos.forEach(function(todo) {
createLi(todo);
});
listName.value ? listH1.innerText = listName.value : listH1.innerText = "My List";
newTodoDivWrap.classList.add("new-todo-div");
newTodoDivWrap.appendChild(listH1);
newTodoDivWrap.appendChild(newTodoOl);
myLists.appendChild(newTodoDivWrap);
todoReset(todoDiv, startNote);
startLoginSignUpNoneLobbyFlex();
}
// todo function to go in above that removes all of whats in the tido-container
function todoReset(div, lobbyDiv) {
lobbyDiv.remove();
div.firstElementChild.innerHTML = "";
}
function createLi(todo) {
// ! Create LI
const newTodo = document.createElement('li');
newTodo.innerText = todo.innerText;
newTodo.classList.add("todo-saved-item");
newTodoOl.appendChild(newTodo);
}
I think the following is why it's not working as you intended:
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
Remember that javascript creates references, so when you do something like this—newTodoDivWrap.appendChild(listH1)—you don't add a new element, you only add a reference to said element.
It's the same as if you had two objects.
var a = {'name': 'Anette'}
var bbbb = a // creates a reference, not a new object.
bbbb.name = 'Bjorn'
console.log(a.name) // Bjorn
So create new elements inside the method, instead of creating and calling public ones.
Also, comments like this are so unnecessary:
function createLi(todo) {
// ! Create LI
You had a method name that perfectly explains what it does. You don't need to comment that. Start making it a habit of naming variables or method to explain what's going on—you're already doing that (ex. startLoginSignUpNoneLobbyFlex)—so you don't have to use comments. Comments are useless, unless it's for documentation.
You have to move
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
into the addNewTodo function. That way each iteration produces a brand new List
Rickard pointed me in the right direction :)
I have a test that provides 4 values:
fPortTotal = a number with how many ports in a firewall test.
fProtocol = an array with what protocol the port is (ex. UDP, TCP)
fPorts = an array with what port number
fStatus = an array with open or closed depending on the port
in all the arrays [0] is the first port, [1] is the 2nd, and so on.
I want to use the .map method to display each port's information in a <p>. The issue is I'm having a large amount of difficulty understanding the .map method and how to use it. I beleave the "skeleton" of the function should look like this:
function populateFw(fPorts, fStatus, fPortTotal, fProtocol) {
var output = document.getElementById('firewallRes');
var text = document.createElement ('p');
text.id = 'firewallEndResults';
text.innerHTML = arrayOfArrays.map;
}
any help would be appreciated.
You can try something like this:
function populateFw(fPorts, fStatus, fPortTotal, fProtocol) {
var output = document.getElementById('firewallRes');
fPorts.forEach((port, index) => {
const text = document.createElement('p');
text.innerText= `${port}: ${fProtocol[index]} - ${fStatus[index]}`;
output.appendChild(text);
})
}
ForEach would be better here. Map returns an object, you don't need that.
fStatus.forEach((_, index)=>{
//then using index acces all the information
const protocol = fProtocol[index];
const protNumber = fPorts[index]
....
text.innerHTML += 'Protocol is '+protocol+' and port number is '+protNumber;
});
Edit: also example of Talmacel Marian Silviu is basically the same thing.
do it like this:
for(i=0; i<fPorts; i++){
var text = document.createElement ('p');
text.id = `firewallEndResults${i}`;
text.innerHTML = `${fStatus[i]}, ${fPortTotal[i]}, ${fProtocol[i]}`;
somediv.appendChild(text); // don't forget
}
map is function for change array items and need callback
const newArray = arrayOfArrays.map(callback)
or
const newArray = arrayOfArrays.map((i)=>{ do something in cycle })
if you use React you can use map in JSX, but this is other story
I'm working with an API that returns strings with inline links like so:
This is a question I'm asking on <my_link type="externalLink" data="https://stackoverflow.com/">StackOverflow</my_link> about splitting a string and reconstructing as a HTML link.
The reason for this is apparently so the API can be used by both web and native platforms and that HTML is kept away from the data. There are also internalLink types which will allow app developers to link to content within an app rather than opening a web browser.
I need to be able to pass this string into a function and return the full string with an tag like so:
This is a question I'm asking on StackOverflow about splitting a string and reconstructing as a HTML link.
Another thing to consider is that the string could have multiple links in it.
My initial attempt is basic and does get externalLink from the first link but I'm unsure of how to get the value of the data attribute and then re-run for any other links.
export default function convertLink(string) {
let stringWithLinks = string;
if (string.includes('<my_link')) {
const typeStart = string.indexOf('"') + 1;
const typeEnd = string.indexOf('"', typeStart);
const typeText = string.substring(typeStart, typeEnd); // externalLink
}
return stringWithLinks;
}
You can set the string as .innerHTML of a dynamically created element and use .getAttribute() to get the data attribute of <my_link> element, set .innerHTML of dynamically created <a> element and use .replaceChild() to replace <my_link> with <a> element
let str = `This is a question I'm asking on <my_link type="externalLink" data="https://stackoverflow.com/">StackOverflow</my_link> about splitting a string and reconstructing as a HTML link.`;
let div = document.createElement("div");
div.innerHTML = str;
let my_links = Array.prototype.map.call(div.querySelectorAll("my_link"), link =>
link.getAttribute("data"));
console.log(my_links);
for (let link of my_links) {
let a = document.createElement("a");
a.href = link;
a.target = "_blank";
a.innerHTML = div.querySelector("my_link").innerHTML;
div.replaceChild(a, div.querySelector("my_link"))
}
console.log(div.innerHTML);
Add the string as HTML of a new element. Loop over all the my_link elements extracting the relevant data, then build a new anchor that can then replace the my_link on each iteration.
function convertAllLinks(str) {
let el = document.createElement('div');
el.innerHTML = str;
el.querySelectorAll('my_link').forEach(link => {
let anchor = document.createElement('a');
anchor.href = link.getAttribute('data');
anchor.setAttribute('target', '_blank');
anchor.textContent = link.textContent;
link.parentNode.replaceChild(anchor, link);
});
return el.innerHTML;
}
convertAllLinks(str);
DEMO
Here's another solution using DOMParser(), in case you might need to do any more DOM modifications later on.
let stringWithLinks = `This is a question I'm asking on <my_link type="externalLink" data="https://stackoverflow.com/">StackOverflow</my_link> about splitting a string and reconstructing as a HTML link.`,
tempDOM = new DOMParser().parseFromString('<doc>' + stringWithLinks + '</doc>', "text/xml"),
linkElements = tempDOM.getElementsByTagName('my_link');
for (let i=0; i<linkElements.length; i++) {
let newA = document.createElement('a');
newA.setAttribute('src', linkElements[i].getAttribute('data'));
let linkType = linkElements[i].getAttribute('type');
if (linkType == 'externalLink') {
newA.setAttribute('target', '_blank');
}
newA.innerHTML = linkElements[i].innerHTML;
tempDOM.documentElement.replaceChild(newA, linkElements[i]);
}
console.log(tempDOM.documentElement.innerHTML);