How to Add Diff Links to JS Buttons? - javascript

I created multiple buttons with Vanilla JS and want them to link to a different page. I'm thinking of mapping over the 'links' array but need a little refresher on how to target each individual button leading to the right page?
const multipleButtons = () => {
// let i = 0;
let body = document.getElementsByTagName("body")[0];
var optionText = ["Fit Guide", "Care", "Materials"];
var links = ['fitGuide.html', 'care.html', 'materials.html'];
for (let i = 0; i < optionText.length; i++) {
let button = document.createElement("button");
// button.innerHTML = 'Button '+i;
button.innerHTML = optionText[i];
body.appendChild(button);
button.addEventListener("click", function() {
// alert(this.innerHTML);
});
}
}
multipleButtons();
Buttons work just fine, just gotta add the appropriate links. I know this can easily be done in HTML/CSS but I'm supposed to do this in plain JS.

You can change your event listener to
button.addEventListener("click", function() { window.location.href = links[i]; });

If you have to use buttons and not an a tag, something like this:
const multipleButtons = () => {
// let i = 0;
let body = document.getElementsByTagName("body")[0];
var optionText = ["Fit Guide", "Care", "Materials"];
var links = ['fitGuide.html', 'care.html', 'materials.html'];
for (let i=0; i < optionText.length; i++) {
let button = document.createElement("button");
// button.innerHTML = 'Button '+i;
button.innerHTML = optionText[i];
body.appendChild(button);
button.addEventListener ("click", function() {
window.location.href = "http://www.baseurl.com/path/to/page/"+links[i];
});
}
}
multipleButtons();
EDIT: changed to href instead of replace

for loops have been proven to be faster, but forEach loops are a bit more readable so I suggest you use those. It's also a good idea to use const for variables that won't change.
One last thing is that it's better to use <a> tags because that's what they were designed to do - like Quentin mentioned in the comments. You can style them to look like buttons if you want.
const multipleButtons = () => {
const optionText = ["Fit Guide", "Care", "Materials"];
const links = ['fitGuide.html', 'care.html', 'materials.html'];
optionText.forEach(function(text, index) {
const anchor = document.createElement("a");
anchor.innerText = text;
anchor.href = links[index];
document.body.appendChild(anchor);
anchor.addEventListener("click", function() {
alert(this.innerText);
window.location.href = this.href;
});
});
}
multipleButtons();
a {
margin-right: .5em;
}

Related

Remove repetition of javascript html tag creation

If you go through the process of creating html elements in JavaScript, you can see that this process is repeated a lot. For example I made a function to create, edit and delete comments in real time, please see the following code.
function addComment(comment, score) {
// Create a list for comments
const newComment = document.createElement('li');
newComment.setAttribute('data-commentid', comment._id);
newComment.classList.add('detail__comment');
// Creating a Comments Information
const commentInfo = document.createElement('div');
commentInfo.classList.add('detail__comment__info');
const scoreConfigWrap = document.createElement('div');
scoreConfigWrap.classList.add('detail__comment__score');
for (let i = 0; i < score; i++) {
const filledScore = document.createElement('i');
const filledScoreClass = ['fa-solid', 'fa-star', 'filled'];
filledScore.classList.add(...filledScoreClass);
scoreConfigWrap.appendChild(filledScore);
}
for (let j = score; j < 5; j++) {
const score = document.createElement('i');
const scoreClass = ['fa-solid', 'fa-star'];
score.classList.add(...scoreClass);
scoreConfigWrap.appendChild(score);
}
// Create a comment edit button and include it in its parent
const commentBtns = document.createElement('div');
commentBtns.classList.add('detail__comment__btns');
const modifyBtn = document.createElement('button');
modifyBtn.innerText = 'Update';
modifyBtn.classList.add('detail__comment__modify-btn');
const cancelModifyBtn = document.createElement('button');
cancelModifyBtn.innerText = 'Cancel';
cancelModifyBtn.classList.add('detail__comment__modify-cancel');
cancelModifyBtn.classList.add('hidden');
commentBtns.appendChild(modifyBtn);
commentBtns.appendChild(cancelModifyBtn);
commentInfo.appendChild(scoreConfigWrap);
commentInfo.appendChild(commentBtns);
// Create space for comment text, author
const commentText = document.createElement('div');
commentText.classList.add('detail__comment__text');
const span = document.createElement('span');
span.innerText = comment.text;
const commentOwner = document.createElement('a');
commentOwner.setAttribute('href', `users/${comment.owner._id}`);
commentOwner.innerText = comment.owner.uid;
commentText.appendChild(span);
commentText.appendChild(commentOwner);
// Create a delete comment button
const deleteBtn = document.createElement('button');
deleteBtn.innerText = 'X';
deleteBtn.classList.add('detail__comment__delete');
// Saving information to be used for comment editing and deletion functions
comment = {
text: comment.text,
_id: comment._id,
};
commentObj = {
comment,
commentBtns,
commentElement: commentText,
};
// Link all elements related to comments with their parent
newComment.appendChild(commentInfo);
newComment.appendChild(commentText);
newComment.appendChild(modifyForm);
newComment.appendChild(deleteBtn);
detailComments.prepend(newComment);
}
Doesn't it make you annoyed just by looking at it? The problem is I don't know how to refactor this iteration. I thought about making the process of creating html elements into a separate function.
export default function createHtmlTag(
element,
text,
attrObj,
className,
parentNode
) {
const newElement = document.createElement(element);
if (attrObj) {
newElement.setAttribute(attrObj.key, attrObj.value);
}
if (text) {
newElement.innerText = text;
}
if (className) {
newElement.classList.add(className);
}
parentNode.appendChild(newElement);
}
But even then, the code looked like it was less readable. So I'd like to get a little hint about the refactoring process.

Removing input from the DOM and local storage with vanilla JavaScript

I'm creating a ToDo app in vanilla JavaScript.
My goal is to be able to remove the input data from local storage when the corresponding "X" button has been clicked.
So far, when you click on an X button, the corresponding input field and checkbox are removed from the DOM with this function I created -
function removeToDoInput(button, input1, input2, input3) {
if (allToDoInputs.length > 2) {
button.addEventListener("click", () => {
toDoInputContainer.removeChild(input1);
toDoInputContainer.removeChild(input2);
toDoInputContainer.removeChild(input3);
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
for (let i = 0; i < localStorage.length; i++) {
localStorage.removeItem("ToDo " + toDoInput);
console.log("test");
}
}
})
}
}
This works fine. But like I mentioned I also need to remove the corresponding input data from local storage.
Here is the 'add-to-do' button functionality. You'll notice the removeToDoInput is called which I don't think is good -
function createToDoInput() {
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
toDoInputContainer.appendChild(newToDoInputCheckbox);
toDoInputContainer.appendChild(newToDoInput);
toDoInputContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
}
And here is the save button functionality -
function saveToDoInputs() {
localStorage.setItem("Title", toDoListTitle.value.trim());
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
if (createToDoInput) {
localStorage.setItem("ToDo " + toDoInput, allToDoInputs[toDoInput].value.trim());
}
}
}
Both of these last functions I mentioned are attached to buttons through click event listeners.
How can I delete the input from local storage as well as the DOM?
This is incorrect and will be called immediately you assign the event handler
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
you need
newXBtn.addEventListener("click", function() { removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn)});
or similar
I have redesigned your code and now it
wraps the elements in their own container
delegates click and change to the list container
use relative addressing (closest)
gives the todo a unique ID and stores it in an object
retrieves the object from local storage when loading
adds the object to localStorage when changed
I also added a select all and delete selected
NOTE I have commented the localStorage interaction out because stacksnippets do not allow access to localStorage. Just uncomment them on your page
let todos = {};
// const saveTodos = localStorage.getItem("ToDo");
// if (saveTodos) todos = JSON.parse(saveTodos);
const toDoInputContainer = document.getElementById("toDoInputContainer");
const toggleSelDel = () => {
document.getElementById("seldel").classList.toggle("hide",Object.keys(todos).length===0); // show if there are actual entries - we can toggle on existense of checkboxes instead
}
const saveAndToggle = (id,why) => {
// localStorage.setItem("ToDo",JSON.stringify(todos));
console.log(id, why);
toggleSelDel()
};
const saveTodo = (id, text) => {
todos[id] = text;
saveAndToggle(id,"added")
};
const removeTodo = id => {
if (todos[id]) {
delete todos[id];
}
saveAndToggle(id,"deleted"); // toggle anyway
};
function createToDoInput() {
const todoContainer = document.createElement("div");
todoContainer.id = 'todo' + new Date().getTime(); // unique ID
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
todoContainer.appendChild(newToDoInputCheckbox);
todoContainer.appendChild(newToDoInput);
todoContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
toDoInputContainer.appendChild(todoContainer);
}
toDoInputContainer.addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("X")) {
const parent = tgt.closest("div")
removeTodo(parent.id);
parent.remove();
}
});
toDoInputContainer.addEventListener("change", function(e) {
const tgt = e.target;
if (tgt.classList.contains("to-do-input")) {
const id = tgt.closest("div").id;
if (tgt.value === "") removeTodo(id);
else saveTodo(id, tgt.value);
}
});
document.getElementById("add").addEventListener("click", createToDoInput);
toggleSelDel(); // possibly show the select all button
document.getElementById("selAll").addEventListener("click", function() {
const checked = this.checked;
[...toDoInputContainer.querySelectorAll("[type=checkbox]")].forEach(chk => chk.checked = checked)
});
document.getElementById("delAll").addEventListener("click", function() {
[...toDoInputContainer.querySelectorAll("[type=checkbox]:checked")].forEach(chk => {
const parent = chk.closest("div");
removeTodo(parent.id);
parent.remove();
});
});
.hide { display: none; }
<button id="add">Add</button>
<div id="seldel" class="hide"><label>Select all<input type="checkbox" id="selAll"/></label><button type="button" id="delAll">Delete selected</button></div>
<div id="toDoInputContainer"></div>

VUEJS: passing value of javascript button

I am trying to pass the value of a button to a function when it is clicked. Because the buttons were created as a javascript element I'm not sure how to do it.
methods:{
createButtons() {
var i;
var rows =["9","8","7","6","5","4","3","2","1","0","•","="];
var elDiv = document.getElementById("myDIV");
for (i=0; i<12; i++){
var btn = document.createElement("BUTTON");
btn.value = i
btn.style.height = "40px"
btn.textContent = rows[i];
btn.onclick = buttonvalue;
elDiv.appendChild(btn);
}
var pressedbutton = document.getElementById("calculate");
pressedbutton.remove();
},
}
}
function buttonvalue(i){
alert(i);
}
This is an XY problem. Don't create DOM elements manually like this, that's what Vue is for.
But to answer your question, you can do something like this:
const captureI = i;
btn.onclick = () => buttonvalue(captureI);
I copied i into a new local variable because i changes value by the for loop.
Or you can just write the for loop like this instead:
for (let i = 0; i < 12; i++) {
// ... omitted code ...
btn.onclick = () => buttonvalue(i);
}

JavaScript - How to know which object has been clicked

I have a basic film search, now I'm trying to make it so that once you click on a film, it gets just that clicked films title property, at the moment it is bringing every film from the list of films that match the search term.
How do I go about finding out which film has been clicked and ONLY pass this objects properties through instead of every object? Do I need to use a loop?
screenshots added, e.g if I click the first film "John Wick" it creates a h1 title for every film title that has "John Wick"
function search() {
var userInput = $("#content-container-search").val().replace(/\s+/g,"%20");
var searchTerm = "".concat(standardURL, apiKey, 'query=', userInput);
var request = new XMLHttpRequest();
clear(); //runs the clear function to clear existing DOM results to make way for the new ones
request.open('GET', searchTerm , true);
request.onload = function(data) {
var data = JSON.parse(this.response);
createList(data);
}
request.send();
}
function createList(data){
var app = document.getElementById("film-results");
data.results.forEach(film => {
console.log(film.title);
var filmInfo = film;
var Filmcontainer = document.createElement("div");
Filmcontainer.setAttribute("class", "row film-container");
var filmContainerLeftPanel = document.createElement("div");
filmContainerLeftPanel.setAttribute("class", "film-container-left-panel column small-3");
var filmContainerRightPanel = document.createElement("div");
filmContainerRightPanel.setAttribute("class", "film-container-right-panel column small-9");
var li = document.createElement("li");
li.setAttribute("class", "film-container-right-panel-li");
var ul = document.createElement("ul");
var h1 = document.createElement("h1");
h1.setAttribute("class", "film-container-right-panel-h1");
h1.textContent = film.title;
var ahref = document.createElement("a");
// ahref.setAttribute("class", "button");
ahref.setAttribute("data-open", "exampleModal1");
var paragraph = document.createElement("p");
paragraph.setAttribute("class", "film-container-right-panel-p");
var paragraphMaxLength = 125;
var filmOverview = film.overview;
var trimmedFilmOverview = filmOverview.substr(0, paragraphMaxLength);
trimmedFilmOverview = trimmedFilmOverview.substr(0, Math.min(trimmedFilmOverview.length, trimmedFilmOverview.lastIndexOf(" ")));
trimmedFilmOverview = trimmedFilmOverview + "...";
paragraph.textContent = trimmedFilmOverview;
var baseImgURL = "https://image.tmdb.org/t/p/w154" + film.poster_path;
var filmImage = document.createElement("img");
filmImage.src = baseImgURL;
filmImage.setAttribute("class", "film-container-right-panel-img");
// film.forEach(filmImage.src.indexOf("null"))
// filmImage.src = "/img/imagenotavailable.png";
app.appendChild(Filmcontainer);
Filmcontainer.appendChild(filmContainerLeftPanel);
Filmcontainer.appendChild(filmContainerRightPanel);
filmContainerLeftPanel.appendChild(filmImage);
filmContainerRightPanel.appendChild(ul)
.appendChild(li)
.appendChild(ahref)
.appendChild(h1);
li.appendChild(paragraph);
generateModal(filmInfo);
})
}
function generateModal(filmInfo){
var modal = document.getElementById("exampleModal1");
var h1 = document.createElement("h1");
h1.textContent = filmInfo.title;
modal.appendChild(h1);
console.log(filmInfo);
}
Maybe you want to take a look at Event.target and currentTarget.
--UPDATE--
Here is an example:
let ctas = document.querySelectorAll('.see-details');
ctas.forEach(cta => {
cta.addEventListener('click', (movie) => {
let movieId = movie.target.getAttribute('data-movie-id');
console.log(movieId);
});
});
<button data-movie-id="toy-story-1" class="see-details">See movie details</button>
You can solve this problem using event.target in JavaScript.
var div = document.createElement('div');
document.body.appendChild(div);
var button = document.createElement("button");
button.innerHTML = "John Wick";
button.style.margin= "10px";
div.appendChild(button);
var button2 = document.createElement("button");
button2.innerHTML = "John Wick: chapter 2";
button2.style.margin= "10px";
div.appendChild(button2);
var button3 = document.createElement("button");
button3.innerHTML = "John Wick: chapter 3";
div.appendChild(button3);
function showName(e){
alert("you have clicked "+e.target.innerHTML);
}
div.addEventListener('click', showName, false);
In this code I have created 3 buttons and whenever you clicks on any button it will trigger an event showName and event.target helps us to get the element that triggered a specific event (i.e click in our case) .
and try to run console.log(event.target), this will give you the whole information about the event triggered here.
I hope this helps.

How to I perform a delete request one item at a time using Axios?

So, I am building a basic to-do list app using a to-do list api and I am having trouble figuring out how to delete one to-do at a time when the user clicks a delete button. I am using the id# that gets created for a new todo that is made.
I thought the code I currently have would work, but nothing happens when I click the delete button.
Any insights into what I am doing wrong?
Here's all my JavaScript, but what I am having trouble with is the last addEventListener at the bottom of the code:
function Todo(title, description, price){
this.title = title;
this.description = description;
this.price = price;
}
document.todo.addEventListener("submit", function(e){
e.preventDefault();
var titleForm = document.todo.title.value;
var descriptionForm = document.todo.description.value;
var priceForm = document.todo.price.value;
var newTodo = new Todo(titleForm, descriptionForm, priceForm);
axios.post("https://api.todo.io/name/todo", newTodo).then(function(response){
console.log(response.data);
})
})
axios.get("https://api.todo.io/name/todo").then(function(response){
for(var i = 0; i < response.data.length; i++){
var h1 = document.createElement("h1");
var h3 = document.createElement("h3");
var h3Price = document.createElement("h3");
var div = document.createElement("div");
var delButton = document.createElement("button");
var displaytitle = document.createTextNode(`Title: ${response.data[i].title}`);
var displayDescription = document.createTextNode(`Description: ${response.data[i].description}`);
var displayPrice = document.createTextNode(`Price: ${response.data[i].price}`);
var displayButton = document.createTextNode("Delete");
h1.appendChild(displaytitle);
h3.appendChild(displayDescription);
h3Price.appendChild(displayPrice);
delButton.appendChild(displayButton);
div.appendChild(h1);
div.appendChild(h3);
div.appendChild(h3Price);
div.appendChild(delButton);
document.body.appendChild(div);
delButton.addEventListener("submit", function(e){
e.preventDefault();
axios.delete(`https://api.todo.io/name/todo/${response.data[i]._id}`).then(function(response){
console.log("Todo Deleted!");
})
})
}
console.log(response.data);
});
From the docs for the 'submit' event:
Note that submit is fired only on the form element, not the button or submit input. (Forms are submitted, not buttons.)
As for your scoping problem, if you extract the body of your for loop as a function:
function addTodo({ _id, description, price, title }) {
const h1 = document.createElement("h1");
const displaytitle = document.createTextNode(`Title: ${title}`);
h1.appendChild(displaytitle);
const h3 = document.createElement("h3");
const displayDescription = document.createTextNode(`Description: ${description}`);
h3.appendChild(displayDescription);
const h3Price = document.createElement("h3");
const displayPrice = document.createTextNode(`Price: ${price}`);
h3Price.appendChild(displayPrice);
const delButton = document.createElement("button");
const displayButton = document.createTextNode("Delete");
delButton.appendChild(displayButton);
delButton.addEventListener("click", function(e) {
e.preventDefault();
axios
.delete(`https://api.todo.io/name/todo/${_id}`)
.then(function(response) {
console.log("Todo Deleted!");
});
});
const div = document.createElement("div");
div.appendChild(h1);
div.appendChild(h3);
div.appendChild(h3Price);
div.appendChild(delButton);
document.body.appendChild(div);
}
axios.get("https://api.todo.io/name/todo").then(function(response) {
for (var i = 0; i < response.data.length; i++) {
addTodo(response.data[i]);
}
console.log(response.data);
});

Categories