how to make the button click executes code only one time - javascript

I want the button with the id #show-text-area execute the postButton(); function only once so it won't create a second elements whenever clicked (i want it to create it for only one time and won't work again until clicked another button).
Hope my question was clear enough.
HTML
<div id="post-creator" class="creator-container">
<div class="post-type">
<div class="text-post" id="post">
<button onclick="postButton();">Post</button>
</div>
<div class="media-post">Image & Video</div>
<div class="link-post">Link</div>
</div>
<div class="post-title">
<input type="text" class="title-text" name="post-title" placeholder="Title">
</div>
<div class="post-content">
</div>
<div class="post-footer">
<div class="spoiler">Spoiler</div>
<div class="nsfw">NSFW</div>
<button class="post">post</button>
</div>
</div>
Javascript
let postButton = function() {
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
}

You could disable the button after activation, this has the benefit of informing the user that further clicks won't do anything.
let postButton = function() {
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
document.getElementsByTagName("button")[0].disabled = true;
}
Otherwise you could simply have the function short-circuit if it has already been called.
// alreadyPosted is scoped outside of the function so it will retain its value
// across calls to postButton()
let alreadyPosted = false;
let postButton = function() {
// do nothing if this isn't the first call
if (alreadyPosted) { return; }
// mark the function as called
alreadyPosted = true;
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
document.getElementsByTagName("button")[0].disabled = true;
}

The following works.
let postButton = function(event) {
event.target.disabled = true;
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
};
document.getElementById('post').addEventListener('click', postButton);
<div id="post-creator" class="creator-container">
<div class="post-type">
<div class="text-post" id="post">
<button>Post</button>
</div>
<div class="media-post">Image & Video</div>
<div class="link-post">Link</div>
</div>
<div class="post-title">
<input type="text" class="title-text" name="post-title" placeholder="Title">
</div>
<div class="post-content">
</div>
<div class="post-footer">
<div class="spoiler">Spoiler</div>
<div class="nsfw">NSFW</div>
<button class="post">post</button>
</div>
</div>

You can also use hide show function on textarea if you do not want to create one.
let postButton = function() {
let d = document.getElementById('post_data').style.display;
if(d=='none'){
document.getElementById('post_data').style.display = 'block';
}
}
document.getElementById('post_data').style.display = 'none';
document.getElementById('post_btn').addEventListener('click', postButton);
<div id="post-creator" class="creator-container">
<div class="post-type">
<div class="text-post">
<button id="post_btn">Post</button>
</div>
<div class="media-post">Image & Video</div>
<div class="link-post">Link</div>
</div>
<div class="post-title">
<input type="text" class="title-text" name="post-title" placeholder="Title">
</div>
<div class="post-content">
<textarea class="post-data" id="post_data" placeholder="Text (optional)"></textarea>
</div>
<div class="post-footer">
<div class="spoiler">Spoiler</div>
<div class="nsfw">NSFW</div>
<button class="post">post</button>
</div>
</div>

Related

How to add plus 1 if the answer is correct in drag and drop API on JavaScript?

I'm so new that I don't know how to make a scoring system in JavaScript. All I need is; if the drag1 is dropped on div1, 1 score must add up. Here's my index.php, css, and js files
function submit() {
document.getElementById('handler').style.display = 'block'
const quest1 = document.getElementById('div1')
const ans1 = document.getElementById('drag1')
const totalScore = document.getElementById('score')
const score = 0
totalScore.textContent = score;
}
<div id="drop_area">
<div id="div1 drop" ondrop="drop(event);" ondragover="allowDrop(event);" value="10000 Years"></div>
<div id="div2 drop" ondrop="drop(event);" ondragover="allowDrop(event);" value="Evil Queen"></div>
<div id="div3 drop" ondrop="drop(event);" ondragover="allowDrop(event);" value="12"></div>
<div id="div4 drop" ondrop="drop(event);" ondragover="allowDrop(event);" value="Nana"></div>
<div id="div5 drop" ondrop="drop(event);" ondragover="allowDrop(event);" value="Maurice"></div>
</div>
<div id="drag_options">
<div id="wrapper">
<div id="drag1 option" draggable="true" ondragstart="drag(event)">Evil Queen</div>
<div id="drag2 option" draggable="true" ondragstart="drag(event)">Maurice</div>
<div id="drag3 option" draggable="true" ondragstart="drag(event)">Nyla</div>
<div id="drag4 option" draggable="true" ondragstart="drag(event)">Cruela Devil</div>
<div id="drag5 option" draggable="true" ondragstart="drag(event)">4</div>
<div id="drag6 option" draggable="true" ondragstart="drag(event)">Moris</div>
<div id="drag7 option" draggable="true" ondragstart="drag(event)">10000 Years</div>
<div id="drag8 option" draggable="true" ondragstart="drag(event)">1000 Years</div>
<div id="drag9 option" draggable="true" ondragstart="drag(event)">12</div>
<div id="drag10 option" draggable="true" ondragstart="drag(event)">Nana</div>
</div>
</div>
<div id="submit_button">
<button type="submit" id="submit" onclick="submit()">Submit</button>
</div>
NEVER call anything in a form id or name=submit. Also do not call your function submit.
You do not have a form,so no need to use a submit button. Just have <button id="run" type="button">Run</button>.
Use eventListeners and delegation
Here is a full version for you to study
I took the drag/drop from MDN
I have not added error handling when the same answer is dropped twice.
I guessed a point calculation
window.addEventListener("DOMContentLoaded", () => { // when page has loaded
const target = document.getElementById("drop_area");
const source = document.getElementById("drag_options");
const resetBut = document.getElementById("reset");
const runBut = document.getElementById("run");
const answerDiv = document.getElementById("answers");
let dragged = null;
source.addEventListener("dragstart", (event) => {
// store a ref. on the dragged elem
dragged = event.target;
});
target.addEventListener("dragover", (event) => {
// prevent default to allow drop
event.preventDefault();
});
target.addEventListener("drop", (event) => {
// prevent default action (open as link for some elements)
event.preventDefault();
// move dragged element to the selected drop target
if (event.target.dataset.value) {
// dragged.parentNode.removeChild(dragged);
event.target.textContent = dragged.textContent;
}
});
const pointsPerCorrect = 5;
runBut.addEventListener("click", () => {
const correct = [...target.querySelectorAll("div")].filter(div => div.textContent === div.dataset.value); // run filter on the child divs
const numberOfCorrect = correct.length;
const answers = correct.map(div => div.textContent).join(", ");
answerDiv.innerHTML = `You had ${numberOfCorrect} answer${numberOfCorrect===1?"":"s"} correct.<br/> ${answers}`; // using template strings
});
resetBut.addEventListener("click", () => {
target.querySelectorAll("div").forEach((div,i) => div.textContent = (i+1));
});
});
#drop_area {
background-color: green;
}
#drag_options {
background-color: red;
}
#drop_area div {
padding: 2px;
border: 1px solid black;
}
#drag_options div {
padding: 2px;
border: 1px solid black;
}
<div id="drop_area">
<div data-value="10000 Years">1</div>
<div data-value="Evil Queen">2</div>
<div data-value="12">3</div>
<div data-value="Nana">4</div>
<div data-value="Maurice">5</div>
</div>
<hr/>
<div id="drag_options">
<div draggable="true">Evil Queen</div>
<div draggable="true">Maurice</div>
<div draggable="true">Nyla</div>
<div draggable="true">Cruella de Vil</div>
<div draggable="true">4</div>
<div draggable="true">Moris</div>
<div draggable="true">10000 Years</div>
<div draggable="true">1000 Years</div>
<div draggable="true">12</div>
<div draggable="true">Nana</div>
</div>
<div id="submit_button">
<button type="button" id="reset">Reset</button>
<button type="button" id="run">Submit</button>
</div>
<div id="handler">
<div id="score_board">
<div id="wrap">
<h1>SCORE</h1>
<div id="answers"></div>
</div>
</div>
</div>

querySelectorAll Need to select all divs

I'm in need of getting a working search bar for these cards (only one included in the code to save space), the js I've been using worked fine for now, but recently I had to add a new div (with class sce-all) which made it search only some of the items or actually too many from different divs and makes the other info into display:none when I search for anything from div (with class sce-e). When I try to search anything right now, it also searches from div (with class sce-e), I only need it to search from div (with class sce-tt) or it could be both, but it gives it the display:none tag currently. I tried changing up the ('.card div:nth-child(2)') in the js which is the cause of the problem it seems.
Thanks for any help
const searchEl = document.querySelector('.searchbox');
const x = document.querySelectorAll('.card div:nth-child(2)');
function search(e) {
x.forEach((item, index) => {
if (!item.innerHTML.toLowerCase().includes(e.target.value)) {
item.parentElement.style.display = 'none';
} else {
item.parentElement.style.display = 'block';
}
})
}
searchEl.addEventListener("keyup", search);
<form class='searchbox'>
<input class="searchbar" type="text" placeholder="Search.." name="search">
</form>
<div class="main-container">
<div class="cards-vid">
<div class="video anim card">
<div class="video-wrapper">
<div class="video-wrapper-inside">
<a href="vid.mp4"><video preload="metadata">
<source src="vid.mp4#t=139" type="video/mp4">
</video></a>
</div>
</div>
<div class="sce-all">
<div class="sce-e">Link Title<span class="length-t">0ms</span></div>
<div class="sce-tt">Title</div>
</div>
<div class="tags-and-info">
<div class="tags"><a><span class="category-tag">Main</span></a><span class="language-edit">ENG</span></div>
<hr class="sce-hr">
<div class="sce-inf">Info<span class="seperate video-seperate"></span>0h 46m<span class="seperate video-seperate"></span>2023</div>
</div>
</div>
</div>
</div>
Change x to just select the .sce-tt divs. Then when it decides whether to hide or show the parent, use closest('.card') to find the containing card, rather than specifying .parent.
const searchEl = document.querySelector('.searchbox');
const x = document.querySelectorAll('.card .sce-tt');
function search(e) {
x.forEach((item, index) => {
if (!item.innerHTML.toLowerCase().includes(e.target.value)) {
item.closest(".card").style.display = 'none';
} else {
item.closest(".card").style.display = 'block';
}
})
}
searchEl.addEventListener("keyup", search);
<form class='searchbox'>
<input class="searchbar" type="text" placeholder="Search.." name="search">
</form>
<div class="main-container">
<div class="cards-vid">
<div class="video anim card">
<div class="video-wrapper">
<div class="video-wrapper-inside">
<a href="vid.mp4"><video preload="metadata">
<source src="vid.mp4#t=139" type="video/mp4">
</video></a>
</div>
</div>
<div class="sce-all">
<div class="sce-e">Link Title<span class="length-t">0ms</span></div>
<div class="sce-tt">Title</div>
</div>
<div class="tags-and-info">
<div class="tags"><a><span class="category-tag">Main</span></a><span class="language-edit">ENG</span></div>
<hr class="sce-hr">
<div class="sce-inf">Info<span class="seperate video-seperate"></span>0h 46m<span class="seperate video-seperate"></span>2023</div>
</div>
</div>
</div>
</div>

How to create elements and delete them with native javascript without using jQuery

In the below link, there is a add more button, i want the add more to create the same input field with a delete button associated with it, but i would like to do it all with native js if possible.
https://codepen.io/aazim-khaki/pen/vYZmMRq
Current JS :
$(function() {
$(".btn-copy").on('click', function() {
var ele = $(this).closest('.example-2').clone(true);
ele.find('input').val('')
if (ele.find('button').length < 2) {
let btn = document.createElement("button");
btn.innerHTML = "Delete";
btn.onclick = (e) => {
e.preventDefault()
ele.remove()
}
ele[0].appendChild(btn);
}
$(this).closest('.example-2').after(ele);
})
})
Delegate
I moved the form tag and gave the button a delete class
window.addEventListener("load", function() {
document.querySelector(".row").addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains('delete')) {
tgt.closest('.example-2').remove()
} else if (tgt.classList.contains('btn-copy')) {
const ele = tgt.closest(".example-2").cloneNode(true);
ele.querySelector("input").value = "";
if (ele.querySelectorAll("button").length < 2) {
let btn = document.createElement("button");
btn.innerHTML = "Delete";
btn.classList.add("delete");
ele.appendChild(btn);
}
tgt.closest(".card-body").appendChild(ele)
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Add Class</h5>
</div>
<form action="#">
<div class="card-body">
<div class="example-2 form-group row">
<!--<label class="col-form-label col-md-2">Input Addons</label>-->
<div class="col-xs-2">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">Class Name</span>
</div>
<input class="form-control" type="text">
<div class="input-group-append">
<button class="btn-copy btn btn-primary" type="button">Add More</button>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-xs-2">
<button class="btn btn-primary" type="button">Submit</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
Use a container and event delegation so you only use one listener rather than attaching a listener to each remove button.
This is a very simple example but the principles are the same.
// Cache your elements
const container = document.querySelector('#container');
const add = document.querySelector('button');
// Add your container an add button listeners
container.addEventListener('click', handleEvent, false);
add.addEventListener('click', handleAdd(), false);
// If a remove button is clicked, find the
// the closest div wrapper and remove it from
// the container
function handleEvent(e) {
const { id } = e.target.dataset;
const row = e.target.closest('.row');
container.removeChild(row);
}
// `handleAdd` returns a function (closure) that
// is used for the add listener rather than
// maintaining a global variable.
// We initialise the id at this point
function handleAdd(id = 0) {
// And now return the function that will be called
// when the add button is clicked
// For the purposes of this example it simply adds new HTML
// to the container, and then increases the id
return function() {
const html = `<div class="row"><input value="${id}" /><button data-id="${id}">Remove</button></div>`;
container.insertAdjacentHTML('beforeend', html);
++id;
}
}
<button>Add</button>
<div id="container"></div>

How to change the order of added elements by clicking the button?

I need help with following code. I have to add new li elements and them swap elements by clicking on img up or down. I need to do it dynamically. Thank you so much.
$(document).ready(function(){
$(".p-title").hide().fadeIn(1500);
const nameInput = document.querySelector('#f-name');
nameInput.focus();
$('form').on('submit', e=>{
e.preventDefault();
let name = nameInput.value;
addItem(name);
})
let addItem = (name)=>{
$('#list').append('<li>'+name+'<img src="/assets/img/site/up_arrow.png" class="upArrow"/><img src="/assets/img/site/down_arrow.png" class="downArrow"/</li>');
nameInput.value = '';
nameInput.focus();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<main class="container">
<div class="row">
<div>
<h4>
<span class="text-muted">List</span>
</h4>
<ul id='list' class="list-group mb-3">
</ul>
</div>
<div class="col-md-7 order-md-1">
<form class="needs-validation row-form">
<div class="mb-3">
<label for="nazov">Name</label>
<input id="f-name" type="text" class="form-control" placeholder="name" required>
</div>
<hr class="mb-4">
<button>Submit</button>
</form>
</div>
</div>
</main>
To reorder those dynamically added list' items using images (buttons) we set a click handler by selecting their parent container first because those images are also dynamically added !
$('#list').on('click', '.downArrow', function(e) {
Then we use insertAfter() to move Down or insertBefore() to move Up their position in the list.
$(document).ready(function(){
$(".p-title").hide().fadeIn(1500);
const nameInput = document.querySelector('#f-name');
nameInput.focus();
$('form').on('submit', e=>{
e.preventDefault();
let name = nameInput.value;
addItem(name);
})
let addItem = (name)=>{
$('#list').append('<li>'+name+'<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Green_Arrow_Up_Darker.svg" class="upArrow"/ width="16"><img src="https://upload.wikimedia.org/wikipedia/commons/0/04/Red_Arrow_Down.svg" width="16" class="downArrow"/</li>');
nameInput.value = '';
nameInput.focus();
}
$('#list').on('click', '.downArrow', function(e) {
var curLi = $(this).closest('li');
var tarLi = curLi.next('li');
curLi.insertAfter(tarLi);
});
$('#list').on('click', '.upArrow', function(e) {
var curLi = $(this).closest('li');
var tarLi = curLi.prev('li');
curLi.insertBefore(tarLi);
});
});
body{
font-size:1.2em;
}
li:last-child img.downArrow,li:first-child img.upArrow{
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<main class="container">
<div class="row">
<div>
<h4>
<span class="text-muted">List</span>
</h4>
<ul id='list' class="list-group mb-3">
</ul>
</div>
<div class="col-md-7 order-md-1">
<form class="needs-validation row-form">
<div class="mb-3">
<label for="nazov">Name</label>
<input id="f-name" type="text" class="form-control" placeholder="name" required>
</div>
<hr class="mb-4">
<button>Submit</button>
</form>
</div>
</div>
</main>
[UPDATE] optimized the answer by changing the styling to hide button on the edges... which is better than doing it with jQuery. thanks to #bhoodream comment

Javascript Function back to it's original place

I'm not actually a programmer but I have to do this website work properly. And for that I'll need your help.
I'm messing with some javascript and I manage to maek this:
<script>
function funcaosabores1() {
document.getElementById("testeagora1").innerHTML = "";
document.getElementById('contento1').style.visibility="visible";
document.getElementById('contento2').style.visibility="hidden";
document.getElementById('contento3').style.visibility="hidden";
document.getElementById('contento4').style.visibility="hidden";
document.getElementById('contento5').style.visibility="hidden";
}
function funcaosabores2() {
document.getElementById("testeagora2").innerHTML = "";
document.getElementById('contento2').style.visibility="visible";
document.getElementById('contento1').style.visibility="hidden";
document.getElementById('contento3').style.visibility="hidden";
document.getElementById('contento4').style.visibility="hidden";
document.getElementById('contento5').style.visibility="hidden";
}
function funcaosabores3() {
document.getElementById("testeagora3").innerHTML = "";
document.getElementById('contento3').style.visibility="visible";
document.getElementById('contento1').style.visibility="hidden";
document.getElementById('contento2').style.visibility="hidden";
document.getElementById('contento4').style.visibility="hidden";
document.getElementById('contento5').style.visibility="hidden";
}
function funcaosabores4() {
document.getElementById("testeagora4").innerHTML = "";
document.getElementById('contento4').style.visibility="visible";
document.getElementById('contento1').style.visibility="hidden";
document.getElementById('contento2').style.visibility="hidden";
document.getElementById('contento3').style.visibility="hidden";
document.getElementById('contento5').style.visibility="hidden";
}
function funcaosabores5() {
document.getElementById("testeagora5").innerHTML = "";
document.getElementById('contento5').style.visibility="visible";
document.getElementById('contento1').style.visibility="hidden";
document.getElementById('contento2').style.visibility="hidden";
document.getElementById('contento3').style.visibility="hidden";
document.getElementById('contento4').style.visibility="hidden";
}
</script>
And I can't find on how to make for example: funcaosabores1 is clicked and is now visible, when I click funcaosabores2, the first one is hidden and the second is showing. But I can't click on the first one back because it was already clicked. (Idk if it's called return)
This is the div's called in the script:
<div class="animacao_saborgingerale" id="contento2" style="visibility:hidden;"></div>
<div class="animacao_saboruvasyrah" id="contento3" style="visibility:hidden;"></div>
<div class="animacao_sabortangerina" id="contento4" style="visibility:hidden;"></div>
<div class="animacao_saboruvabranca" id="contento5" style="visibility:hidden;"></div>
<div class="sabor-melancia"><p onclick="funcaosabores1()" id="testeagora1">MELANCIA</p> </div>
<div class="sabor-gingerale"><p onclick="funcaosabores2()" id="testeagora2">GINGER ALE</p></div>
<div class="sabor-uvasyrah"><p onclick="funcaosabores3()" id="testeagora3">UVA SYRAH</p></div>
<div class="sabor-tangerina"><p onclick="funcaosabores4()" id="testeagora4">TANGERINA</p></div>
<div class="sabor-uvabranca"><p onclick="funcaosabores5()" id="testeagora5">UVA BRANCA</p></div>
This seems quite messy but I'm here if you guys can help me! Thanks.
The CodePen of how it is right now. #nielsdebruin
I think you just want to do something like this:
let prevButton;
let prevContent;
function toggle(e) {
if (prevButton) prevButton.style.visibility = 'visible';
prevButton = e.target;
e.target.style.visibility = 'hidden';
let id = e.target.id;
let number = id.slice(-1);
if (prevContent) prevContent.style.visibility = 'hidden';
prevContent = document.getElementById('contento' + number);
prevContent.style.visibility = 'visible';
}
<div class="content animacao_saborgingerale" id="contento1" style="visibility:hidden;">1</div>
<div class="content animacao_saborgingerale" id="contento2" style="visibility:hidden;">2</div>
<div class="content animacao_saboruvasyrah" id="contento3" style="visibility:hidden;">3</div>
<div class="content animacao_sabortangerina" id="contento4" style="visibility:hidden;">4</div>
<div class="content animacao_saboruvabranca" id="contento5" style="visibility:hidden;">5</div>
<div class="button sabor-melancia"><p onclick="toggle(event)" id="testeagora1">MELANCIA</p> </div>
<div class="button sabor-gingerale"><p onclick="toggle(event)" id="testeagora2">GINGER ALE</p></div>
<div class="button sabor-uvasyrah"><p onclick="toggle(event)" id="testeagora3">UVA SYRAH</p></div>
<div class="button sabor-tangerina"><p onclick="toggle(event)" id="testeagora4">TANGERINA</p></div>
<div class="button sabor-uvabranca"><p onclick="toggle(event)" id="testeagora5">UVA BRANCA</p></div>

Categories