How to display HTML local storage link within modal? - javascript

I have a modal that displays API images within a modal, and I want the "Add To Favourites" link to be shown within the modal.
So far, I can display the "title", "explanation" and "date" by using result.title etc.
However when I use result.saveText to display the "add to favourites" as a HTML link is display undefined.
How do I display the "Add To Favourites as an HTML link within the modal?
// Image
const image = document.createElement("img");
image.src = result.url;
image.alt = result.title + "<br>" + result.explanation + "<br>" + result.date;
image.loading = "lazy";
image.classList.add("card-img-top");
// Card Title
const cardTitle = document.createElement("h5");
cardTitle.classList.add("card-title");
cardTitle.textContent = result.title;
// Save Text
const saveText = document.createElement("p");
saveText.classList.add("clickable");
if (page === "results") {
saveText.textContent = "Add To Favorites";
saveText.setAttribute("onclick", `saveFavorite('${result.url}')`);
} else {
saveText.textContent = "Remove Favorite";
saveText.setAttribute("onclick", `removeFavorite('${result.url}')`);
}

There is nothing wrong with your code showing (except not appending it either to a parent element or document.body)
I check your model and I found that the saveText doesn't append to any parent element or any document.body. The element of your code doesn't even has p tag.
Your probably should use append method to append it to either a parent element or a child element. In your situation, you probably should use cardTitle.appendChild(SaveText)
Doesn't even has p tag in your whole body:
document.querySelectorAll('img')[1].onerror = function(){
let div = document.createElement('div')
div.textContent = 'Link is invalid.'
document.body.appendChild(div)
}
<img src="invalid.jpg" alt ="<a href='https://www.w3schools.com'>Visit W3Schools.com!</a>">
<img src="invalid.jpg" >

Related

I want to use vanilla JS to remove the parent element of the button I'm pressing on click

I created a meme generator that accepts text and images and puts them all together. The generator creates a unique ID for each 'meme' and also adds buttons that show up on hover to "delete" the meme. I used vanilla JS to create this and therefore had to layer a few different child divs on top of one another: image, top text, bottom text using z-index.
I am struggling, however, to get the button to delete the parent div. I want to be able to click that delete button, and have the parent div deleted so that the button goes away, along with image and text. picture below + code snippets.
I attemped to do it with vanilla javascript, by adding a closeTheMeme function on click to each button:
let deleteBtns = document.getElementsByClassName('.delete');
function closeTheMeme (){
this.parentElement.parentElement.removeChild();
};
for(let i=0;i<deleteBtns.length;i++){
deleteBtns[i].addEventListener("click",closeTheMeme);
}
No errors on console...Including the rest of the JS below so you can see how the elements are created on click of the meme generator.
'use strict';
let count=0;
// SUBMIT FORM
document.getElementById('memeInput').addEventListener('submit',function(e){
count++;
//prevent default
e.preventDefault();
//set image, top, and bottom to variables we can work with
let bottomText = document.getElementById('bottomText').value;
createMeme();
})
function createMeme(){
//create a meme section with an ID of the number of times the button was clicked, and add it to the meme section
let meme = document.createElement("DIV");
document.body.appendChild(meme);
meme.setAttribute("id", "meme"+count);
//create an image, set that image to equal the link, give it an id based on form submits, set image.src equal to the link
let img = document.createElement("IMG");
img.setAttribute("id","image"+count);
let imageLink = document.getElementById('imageLink').value;
meme.appendChild(img);
document.getElementById("image"+count).src=imageLink;
//set top text variable equal to the ID of toptext. value(form submission)
let topText = document.getElementById('topText').value;
let top = document.createElement('DIV');
top.setAttribute("id","topText"+ count);
meme.appendChild(top);
top.innerHTML = topText;
//set bottom text variable equal to the ID of toptext.value form submission
let bottomText = document.getElementById('bottomText').value;
let bottom = document.createElement('DIV');
bottom.setAttribute("id","bottomText" + count);
meme.appendChild(bottom);
bottom.innerHTML = bottomText;
//add a button that deletes the meme in the same way as above
let deleteButton = document.createElement("BUTTON");
deleteButton.classList.add("delete");
deleteButton.innerHTML = "Delete";
meme.appendChild(deleteButton);
//styling and position
meme.classList.add("meme");
top.classList.add("topWords");
bottom.classList.add("bottomWords");
};
let deleteBtns = document.getElementsByClassName('.delete');
function closeTheMeme (){
this.parentElement.parentElement.removeChild();
};
for(let i=0;i<deleteBtns.length;i++){
deleteBtns[i].addEventListener("click",closeTheMeme);
}
You select the buttons when the page loads. You created no buttons so it is not possible for it to work since there is nothing to bind an event to.
Since you are making the buttons, add the event there.
const deleteButton = document.createElement("BUTTON");
deleteButton.addEventListener("click", function () {
this.closest("div").remove();
});
Other option is event delegation
document.body.addEventListener("click", function (e) {
const btn = e.target.closest(".delete");
if (btn) btn.closest("div").remove();
});

ScrollTop doesn't work on dynamically generated elements

I am trying to create a chat system (like Facebook)'s where a user clicks the name of the online user and a chat box will appear. _chatbox is generated dynamically using javascript. It will scroll down to the last message. The chat box and messages load/display successfully but the scroll down function is not working... why?
//displays the popups. Displays based on the maximum number of popups that can be displayed on the current viewport width
function display_popups() {
//code for popup here
}
//creates markup for a new popup. Adds the id to popups array.
function register_popup(id, name) {
var element = '<div class="popup-box chat-popup" id="' + id + '">';
element = element + '<div class="popup-head">';
element = element + '<div class="popup-head-left">' + name + '</div>';
element = element + '<div class="popup-head-right">✕</div>';
element = element + '<div style="clear: both"></div></div><div class="popup-messages"></div></div>';
document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML + element;
calculate_popups();
scrollDown(id);
}
//scroll down to the last message
function scrollDown(id) {
var messages = document.getElementById(id);
messages.scrollTop = messages.scrollHeight;
}
//calculate the total number of popups suitable and then populate the toatal_popups variable.
function calculate_popups() {
//calculate popups here
}
<div class="sidebar-name">
<a href="javascript:register_popup('ind', 'Indiana Pacers');">
<img width="30" height="30" src="img/ind.png" />
<span>Indiana Pacers</span>
</a>
</div>
It works, but you seemed to select the wrong element. I adapted your code so that i can demonstrate what is going on. Your scrollable element here is the message container (class ".popup-messages"), not the popup itself.
You need to adapt this code though, as i selected directly the .popup-messages element, but you might want to select the one that is specifically inside your popup.
//displays the popups. Displays based on the maximum number of popups that can be displayed on the current viewport width
function display_popups()
{
//code for popup here
}
//creates markup for a new popup. Adds the id to popups array.
function register_popup(id, name)
{
var element = '<div class="popup-box chat-popup" id="'+ id +'">';
element = element + '<div class="popup-head">';
element = element + '<div class="popup-head-left">'+ name +'</div>';
element = element + '<div class="popup-head-right">✕</div>';
element = element + '<div style="clear: both"></div></div><div class="popup-messages"><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>message</p><p>last message</p></div></div>';
document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML + element;
calculate_popups();
scrollDown(id);
}
//scroll down to the last message
function scrollDown(id)
{
var messages = document.getElementsByClassName('popup-messages')[0];
messages.scrollTop = messages.scrollHeight;
}
//calculate the total number of popups suitable and then populate the toatal_popups variable.
function calculate_popups()
{
//calculate popups here
}
window.onload = function(){
register_popup('test', 'testName');
};
.popup-messages {
height: 100px;
overflow-y: scroll;
}
<div class="sidebar-name">
<a href="javascript:register_popup('ind', 'Indiana Pacers');">
<img width="30" height="30" src="img/ind.png" />
<span>Indiana Pacers</span>
</a>
</div>
Why do you use innerHTML instead of creating an element?
Can you try creating the element with Javascript and adding it to DOM manually like:
var popupBox = document.createElement("div");
// Set properties
var popupHead = document.createElement("div");
// Set properties
popupBox.appendChild(popupHead);
// etc. etc
// Then add it to DOM
document.getElementsByTagName("body")[0].appendChild(element)
// This should work now
calculate_popups();
scrollDown(id);
I think setting innerHtml and converting it to DOM is processed later than your function call.
Read up on creating elements with Javascript here:
https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement

How to reset error message after button has been pressed?

I'm currently learning JavaScript and I'm working on a mock pet adoption site. Super simple layout and functionality except for one issue. I have an error message that comes up when the 'submit' button is pressed and the user tries to submit a pet for adoption without clicking the 'terms and conditions' box. The error comes up, but if I click the button again (without checking the terms and conditions check box), it's like the error just appends another error message.
I am trying to get it where it won't create another error message. I have tried setting the alertMessage variable to an empty string at the end of the function in hopes of it resetting itself, but this does not work.
Thank you in advance for all of your help.
$('#add-pet').on('click', function() {
if (termsBox.checked) {
// Grab info from the form
let $name = $('#pet-name');
let $species = $('#pet-species');
let $notes = $('#pet-notes');
// Assemble the HTML of our new element with the above variables
let $newPet = $(
'<section class="six columns"><div class="card"><p><strong>Name:</strong> ' + $name.val() +
'</p><p><strong>Species:</strong> ' + $species.val() +
'</p><p><strong>Notes:</strong> ' + $notes.val() +
'</p><span class="close">×</span></div></section>'
);
// Attach the element to the page
$('#posted-pets').append($newPet);
// Make the 'x' in the corner remove the section it's contained within
$('.close').on('click', function() {
$(this).parents('section').remove();
});
// Reset form fields
$name.val('');
$species.val('Dog');
$notes.val('');
} else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.appendChild(br);
termsLabel.appendChild(span);
alertMessage = '';
}
});
The easiest way is to use innerHTML DOM element property to clean up node's content:
else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = ''; // this removes previous content of the node including all it's children
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
But I would use just:
else {
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = 'Please read the terms and conditions.';
}
And all styles for termsLabel element should be declared via CSS in a way like
#termsLabel {
margin-top: 15px;
color: red;
}
UPD Here's the fiddler satisfying new requirements: https://jsfiddle.net/yy1z75e7/2/
Clear the element before appending the alert messages
termsLabel.innerHTML = '';
termsLabel.appendChild(br);
termsLabel.appendChild(span);
Or when creating the span give it a class or id, and then check termsLabel to see if it already has the span. If it doesn't then create it, otherwise don't do anything.
//cache this so you don't keep needing to call it over and over
let termsLabel = document.getElementById('termsLabel');
//querySelector() will return null if the span isn't in termsLabel
if(!termsLabel.querySelector('.errorMessage')){
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.classList.add("errorMessage");
span.appendChild(alertMessage);
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
This also gives you the ability to remove the message as well
document.querySelector('.errorMessage').remove()
Every time you click the button, and the code in the else clause executes, you are creating new elements. What you want to do instead is to check if the element, termsLabel lets say, is created first, and if it is then change its innerHtml or text values, and if it isn't then create the element instead.

HTML elements created by the content script are not accessible by the content script

Within content script I use on.Message.addListener to add images with a class name to the currently active web page.
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
// Selecting HTML tags
var divs = document.getElementsByTagName("div");
// Creating a full URL to use icon1
var imageUrl = chrome.extension.getURL("icons/icon1.png");
// Function to create an image
function PlaceImage(source_x, source_y, imageUrl) {
var newImage = document.createElement("img");
newImage.src = imageUrl;
newImage.style.position = "absolute";
newImage.style.left = source_x + 'px';
newImage.style.top = source_y + 'px';
// Assigning a class name
newImage.className = "label-key";
// Add an element to the HTML document
document.body.appendChild(newImage);
}
// Divs
for(var j=0; j<divs.length; j++) {
// Get the position of an element with getBoundingClientRect
var position = divs[j].getBoundingClientRect();
var x = position.left;
var y = position.top;
y -=32;
// Create comment image
PlaceImage(x, y, imageUrl);
}
});
Later I try to write to console by clicking on one of just created images by:
$(".label-key").click(function () {
console.log("hello");
});
There is no reaction of the browser.
I tried to write to console by accessing some class element with a different name, which was part of the original web page(received from the server). It worked fine.
More over I created another element within content script, but this time outside of onMessage.AddListener:
var newDiv = document.createElement("div");
document.body.appendChild(newDiv);
newDiv.style.width = "100px";
newDiv.style.height = "100px";
newDiv.style.backgroundColor = "red";
newDiv.className = "label-key";
It also worked fine. jQuery was able to access this element.
Therefore, I think there is something wrong with html elements created by the onMessage.addListener part of content script.
For additional reference: when I right-click on the newly created element "Inspect element" - I can see that the element is part of the html document. However, if I click "View page source" the element is not there.
Well, you are creating a new element of the class label-key, but the click handler assignment does not automagically extend to newly-created elements.
$(".label-key").click(...) is not behaving like a CSS rule despite looking like one: it collects all elements that match at the time of invocation and binds a listener for them.
So, if you add more images later, you need to add a click handler again:
function PlaceImage(source_x, source_y, imageUrl) {
var newImage = document.createElement("img");
newImage.src = imageUrl;
newImage.style.position = "absolute";
newImage.style.left = source_x + 'px';
newImage.style.top = source_y + 'px';
// Assigning a class name
newImage.className = "label-key";
newImage.click(function () {
console.log("hello");
});
// Add an element to the HTML document
document.body.appendChild(newImage);
}

How to modify style to a link in JavaScript?

How can I make the text in the div (the content of the variable name) become a link? In other words: To change the style to "a" without using jQuery.
var newtit=document.createElement('div');
newtit.id=name; // name is a variable
newtit.innerHTML= name;
document.getElementById("w3c").appendChild(newtit);
Just do what you did with a div, but instead of creating a div, create an anchor element. Add the link you want as the href-attribute.
var newtit=document.createElement('a');
newtit.href = "http://www.google.com"
newtit.innerHTML= "linkylink";
document.getElementById("w3c").appendChild(newtit);
Based on your content, first create the div then append the anchor element to it
var tab = document.createElement("div");
tab.id = "TabX";
document.getElementById("w3c").appendChild("tab");
var link = document.createElement("a");
link.href = "#TabX";
link.innerText = "Tab XX";
document.getElementById("TabX").appendChild("tab");
or just write the anchor straight to the inner HTML
tab.innerHTML = "<a href='#TabX'>Tab XX</a>"

Categories