trying to appendChild and removeChild at the same time - javascript

$('#submit').on('click', function(){
$.ajax({
type:'GET',
url:'http://www.boredapi.com/api/activity/',
success: function(data){// my data
console.log(data);
console.log(data.activity);
var body = document.getElementById('add');
var newDiv = document.createElement('div');
newDiv.innerText = data.activity;
console.log(newDiv); //my data
console.log(body);
var num = 0;
body.appendChild(newDiv);
$('#submit').on('click', function(){
body.removeChild(newDiv);
})
}
})
})
I am trying to add one div with one click, and with a second click remove the first div and add a new div in its place. Right now, I figured out a way to have another eventListner to make a second 'click' remove the first div and add a second but the third click it'll go right back to storing every div with each click. I thing a loop between both eventListner will work but not sure how to make that work logically. I hope I've explained this well enough. Thank you in advance for your help.

$('#submit').on('click', function(){
$.ajax({
type:'GET',
url:'http://www.boredapi.com/api/activity/',
success: function(data){// my data
console.log(data);
console.log(data.activity);
var body = document.getElementById('add');
var newDiv = document.createElement('div');
newDiv.innerText = data.activity;
console.log(newDiv); //my data
console.log(body);
$("#add").empty()
body.appendChild(newDiv);
}

You can use replaceWith() in this case:
Like:
var body = document.getElementById('add');
var newDiv = document.createElement('div');
var old_div = document.querySelectorAll('#add>div') !== null;
if(!old_div){
body.appendChild(newDiv);
} else {
old_div.replaceWith(newDiv);
}
If third line is not understandable, see here.
Overall, your code will look sthg like this:
$.ajax({
type:'GET',
url:'http://www.boredapi.com/api/activity/',
success: function(data){// my data
console.log(data);
console.log(data.activity);
var body = document.getElementById('add');
var newDiv = document.createElement('div');
var old_div = document.querySelectorAll('#add>div') !== null;
newDiv.innerText = data.activity;
if(!old_div){
body.appendChild(newDiv);
} else {
old_div.replaceWith(newDiv);
}
})
}
})
*Note:- success, error, complete are depreciated are removed from version 3.0. Refs

You need to check if the div exists before removing it. The first time the form is submitted there is no div, so it's going to be created and then the new click event will be binded. Then when you click again that div already exists, so you are creating it again, before removing the previous one. I suggest you to add an id to the div in the moment you create it
I would do:
$('#submit').on('click', function () {
$.ajax({
type: 'GET',
url: 'http://www.boredapi.com/api/activity/',
success: function (data) {
var body = $('#add');
if($('#NewDiv')){
body.removeChild($('#NewDiv'))
}
// my data
console.log(data);
console.log(data.activity);
var newDiv = $(document.createElement('div'));
newDiv.attr('id', 'NewDiv');
newDiv.innerText = data.activity;
console.log(newDiv); //my data
console.log(body);
var num = 0;
body.appendChild(newDiv);
}
})
})

This solution stores newDiv and ensures that it's not null before it's removed:
<script>
var newDiv = null;
var body = document.getElementById('add');
$('#submit').on('click', function () {
if (newDiv) {
body.removeChild(newDiv);
}
$.ajax({
type: 'GET',
url: 'http://www.boredapi.com/api/activity/',
success: function (data) {// my data
console.log(data);
console.log(data.activity);
newDiv = document.createElement('div');
newDiv.innerText = data.activity;
console.log(newDiv); //my data
console.log(body);
var num = 0;
body.appendChild(newDiv);
}
})
});
</script>

Here is a solution on how you can remove and append divs using clicks, I have added a counter to demonstrate the change, you can accustom this solution to fit your need
let body = document.getElementById('add');
let olddiv = document.getElementById('olddiv');
let divs=document.getElementsByClassName("div");
flag = false
counter = 0
$('#submit').on('click', function() {
if (!flag) {
addiv(counter)
console.log("divadded ",divs)
counter++
flag = true
} else {
addNewDiv(counter)
counter++
flag = false
}
})
function addiv(counter) {
while (body.hasChildNodes()) {
body.removeChild(body.firstChild);
}
var newDiv = document.createElement('div');
newDiv.id = `olddiv${counter}`
newDiv.className = "div"
newDiv.innerText = counter;
body.appendChild(newDiv);
}
function addNewDiv(counter) {
while (body.hasChildNodes()) {
body.removeChild(body.firstChild);
}
addiv(counter)
console.log("removed",divs)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="add"></div>
<button id="submit">changeDiv</button>

Related

Javascript foreach loop calls ajax several times

So I am trying to create to do list with several boards. Each board have add item button. If I click add item button it opens modal where to insert task info. But if I click add item button several times and then insert info to modal and press save ajax fires as many times i clicked add item button. How can I prevent from that?
var addNewItems = document.querySelectorAll("#addNewItem");
var addNewSubmits = document.querySelectorAll("#listItemSave");
addNewItems.forEach(function(addNewItem) {
addNewItem.addEventListener("click", function(e) {
var newItemModal = this.nextElementSibling;
newItemModal.classList.toggle("hidden");
var addNewBtn = newItemModal.querySelector("#listItemSave");
//current board
var board = this.closest("div.list");
//current list
var list = board.querySelector(".todo--items");
addNewBtn.addEventListener ("click", function(e) {
//current board id
var boardId = board.dataset.boardid;
//current title
var title = newItemModal.querySelector("#listTitle");
var titleValue = title.value;
//current content
var content = newItemModal.querySelector("#listTextarea");
var contentValue = content.value;
$.ajax({
type: "POST",
url: "add.php",
data: { content: contentValue , title: titleValue , listid: boardId },
success: function(data, textStatus, jqXHR) {
$("#todoItems-" + id + "").append(data);
}
});
});
});
});
You could use a variable, lets say busy, to validate that an AJAX request isn't already on going.
You could set this variable in the beforeSend callback of AJAx and then updated it back to false in the finally callbac :
var addNewItems = document.querySelectorAll("#addNewItem");
var addNewSubmits = document.querySelectorAll("#listItemSave");
addNewItems.forEach(function (addNewItem) {
addNewItem.addEventListener("click", function (e) {
var newItemModal = this.nextElementSibling;
newItemModal.classList.toggle("hidden");
var addNewBtn = newItemModal.querySelector("#listItemSave");
//current board
var board = this.closest("div.list");
//current list
var list = board.querySelector(".todo--items");
var busy = false;
addNewBtn.addEventListener("click", function (e) {
//current board id
var boardId = board.dataset.boardid;
//current title
var title = newItemModal.querySelector("#listTitle");
var titleValue = title.value;
//current content
var content = newItemModal.querySelector("#listTextarea");
var contentValue = content.value;
if (!busy) {
$.ajax({
type: "POST",
url: "add.php",
beforeSend: () => {
busy = true;
}
data: {
content: contentValue,
title: titleValue,
listid: boardId
},
success: function (data, textStatus, jqXHR) {
$("#todoItems-" + id + "").append(data);
},
complete: () => {
busy = false;
}
});
}
});
});
});
This is a pretty simple solution but it works.
You can use addNewBtn.onclick = function () {} instead to overlap the previous listener in this case.
But it's not recommended to register listeners inside another listener. Try to move it out of there.

Remove dynamically created elements by class name Javascript

So, in plain terms I am creating a Chrome Extension that so far can only save links from the internet but not delete them. What I want to add is a "remove" button for deleting unwanted links. So far I haven't got that to work.
The buttons I want to remove are added using JavaScript. Each new block of HTML features a "remove" button but clicking that button does nothing. I have tried binding listeners to each element using a for loop but that doesn't seem to work.
The code runs without errors and I'm certain that the issue is a slight oversight but I have only just started using JavaScript so I'm lost for solutions at the moment.
I have included all the code because I don't want to leave out anything that might be imperative to finding a solution.
It starts with the code for adding a link, followed by removing a single link and then removing all links at once. Thank you all for any help, really want to get this working.
https://github.com/mmmamer/Drop Repository for the rest of the code. Mainly popup.html and popup.css.
var urlList = [];
var i = 0;
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
// event listener for the button inside popup window
document.getElementById('save').addEventListener('click', addLink);
});
function addLink() {
var url = document.getElementById("saveLink").value;
addUrlToListAndSave(url);
addUrlToDom(url);
}
function getUrlListAndRestoreInDom() {
chrome.storage.local.get({
urlList: []
}, function(data) {
urlList = data.urlList;
urlList.forEach(function(url) {
addUrlToDom(url);
});
});
}
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function addUrlToListAndSave(url) {
urlList.push(url);
saveUrlList();
//}
}
function saveUrlList(callback) {
chrome.storage.local.set({
urlList
}, function() {
if (typeof callback === 'function') {
//If there was no callback provided, don't try to call it.
callback();
}
});
}
// remove a single bookmark item
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
var allButtons = document.getElementsByClassName('remove');
function listenI(i) {
allButtons[i].addEventListener('click', () => removeMe(i));
}
for (var i = 0; i < allButtons.length; i++) {
listenI(i);
}
});
function removeMe(i) {
var fullList = documents.getElementsByClassName('listItem');
listItem[i].parentNode.removeChild(listItem[i]);
}
//remove all button
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("remove-all").addEventListener('click', function() {
var removeList = document.getElementsByClassName("listItem");
while(removeList[0]) {
removeList[0].parentNode.removeChild(removeList[0]);
}
})
});
chrome.storage.local.get() is asynchronous. So when you try to add the event listeners to the Remove buttons, they're not in the DOM yet.
You can add the listener in the addUrlToDom() function instead. That way you'll also add the event listener when you create new buttons.
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
removeButton.addEventListener("click", function() {
var anchor = this.previousElementSibling;
var url = anchor.getAttribute("href");
removeUrlAndSave(url);
this.parentNode.remove();
});
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function removeUrlAndSave(url) {
var index = urlList.indexOf(url);
if (index != -1) {
urlList.splice(index, 1);
saveUrlList();
}
}

Why the click event will not working in jQuery?

I have a html and jQuery code in which there are two img dynamically created and after ajax I'm applying click events on the images but the click events not working. Means they show nothing. that the imae is clicked or not. I'm showing my code following:-
<div id="images">
<img id="image/5c07a4337c76881db6bf9a7f" src="data:image/jpeg;base64,/9j/4AA.....>
<img id="image/5c07a4337c76881db6bf9a7d" src="data:image/jpeg;base64,/9j/4AA.....>
</div>
$( document ).ready(function() {
$.ajax({
url: "/api/v1/get-all-upload-image?sortBy=date",
type: "GET",
success: function(response){
console.log(response);
$.ajax({
url : "/api/v1/base-strings",
type:"GET",
success:function(response){
console.log(response.response.data)
for (i= 0; i < response.response.data.length; i++){
console.log(response.response.data[i])
var base64_string = response.response.data[i].data;
var img = document.createElement("img");
img.setAttribute("id", "image/"+response.response.data[i].files_id);
img.setAttribute("onclick", "addListeners()");
// added `width` , `height` properties to `img` attributes
img.style.width ='340px';
img.style.height ='194px';
img.style.margin = '50px';
img.style.cursor = 'pointer';
img.src = "data:image/jpeg;base64," + base64_string;
var preview = document.getElementById("images");
preview.appendChild(img);
}
}
});
}
});
function addListeners () {
$('img[id^="image"]').on('click', function(){
var val = $(this).attr('id').split('/');
id= val[val.length - 1]
});
}
$('img[id^="image"]').click(function(){
alert("hello")
})
$('img[id^="image"]').on('click', function(){
var val = $(this).attr('id').split('/');
id= val[val.length - 1]
});
});
Error
Uncaught ReferenceError: addListeners is not defined
at HTMLImageElement.onclick
What is the problem with the code why it is not working?
Listen Just do it like I said. Paste the below code after your first ajax call:-
$('body').on('click','img', function(){
alert("I'm here");
});
Hope Works well :)

Adding event handler to non-existent class?

I've seen questions that relate to non-existent elements, but not non-existent classes. Here's what I want to do. When a button of class "see_answer" is clicked, I want to remove the class and replace it with "see_question". However, my click function for a button, once its class is "see_question", is not running. I have tried $(document).on("click", ".see_question", function(event ) and I have tried $(".see_question").on("click", function(event) {etc.... Thanks for the help! My code is below:
$(document).ready(function() {
// initialize variables
var lang = "javascript";
var qno = 1;
var prevText; // holds question/answer
var language = lang + ".html";
// set up tabs, and keep track of which one is clicked
$("#myTabs").tabs({
activate: function (event, ui) {
var active = $("#myTabs").tabs("option", "active");
lang = $("#myTabs ul > li a").eq(active).attr("href");
lang = lang.replace("#", "");
}
});
/* REMINDERS
actual qa part: blah_language
*/
// set up question
$.ajax({
url: language,
dataType: "html",
success: function(data) {
$("#blah_"+lang)
.text($(data).find("#1").text());
},
error: function(r) {
alert("whoops, error in initialization");
}
});
$(".next_question").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("next_question_", "");
var language = id + ".html";
var doc = "#blah_" + id;
$.ajax({
url: language,
dataType: "html",
success: function(data) {
var num = "#" + qno;
$(doc)
.text($(data).find(num).text());
qno = qno + 1;
},
error: function(r) {
alert("whoops");
}
});
prevText = "";
});
// SHOW ANSWER
$(".see_answer").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
var answers = id + "_answers.html";
// Save the question
prevText = $(prev).text();
var obj = $(this);
$.ajax({
url: answers,
dataType: "html",
success: function(data) {
var num = "#" + 3;
$(prev)
.text($(data).find(num).text());
},
error: function(r) {
alert("whoops");
}
});
obj.val("See Question");
obj.removeClass("see_answer");
obj.addClass("see_question");
event.stopPropagation();
});
$(document).on("click",".see_question", function(event) {
event.preventDefault();
obj = $(this);
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
$(prev).text(prevText);
obj.val("See Answer");
obj.removeClass("see_question");
obj.addClass("see_answer");
});
})
Click handling for .see_question elements is delegated to document. For .see_answer elements, a click handler is attached directly. Therefore, swapping the class names will have an undesirable effect.
when see_answer is in force, a click will trigger the "see_answer" handler.
when see_question is in force, a click will trigger the "see_question" handler AND the "see_answer" handler, which is still attached.
There's a number of ways to do this properly. From where you currently are, the simplest solution is to delegate click handling of .see_question and .see_answer elements to document.
$(document).on("click", ".see_answer", function(event) {
...
});
$(document).on("click", ".see_question", function(event) {
...
});
Combine the 2 handlers and figure out which version it is by hasClass() before you change the classes around
$(document).on("click", ".see_question, .see-answer", function(event ){
var $btn =$(this), isAnswer = $btn.hasClass('see_answer');
// we know which one it is so can switch classes now
$btn.toggleClass('see_answer see_question');
if(isAnswer){
/* run code for answer version */
}else{
/* run code for question version */
}
});

jQuery removes first div only once

I have a function:
function removeDiv() {
var topmost = jQuery('.xx');
var totContent = topmost.find('.zz').length;
var $target = jQuery('.xx').find('.zz').eq(0);
if(totContent > 5) {
$target.hide('slow', function(){ $target.remove(); });
}
}
I use it in my ajax call, to remove extra div then there are more than 5, hovewer it remove first div only once!
And this is how ajax call looks:
function saveClubs(array) {
for(i=0; i<array.length; i++) {
var id = array[i];
jQuery.ajax({
type: "GET",
async: true,
url: 'index.php?option=com_events&task=club.save&id=' + id,
dataType: 'json',
success: function(data) {
jQuery('.xx').append('<div class="zz">'+data+'</div>');
removeDiv();
}
});
}
}
Any ideas ?
This is Paul Roub's answer, posted as an answer rather than a comment:
The likely problem is that since you're doing a bunch of ajax calls in a loop, they tend to complete at the same time, and so you end up repeated fading out the same element (since it's still there until it's done fading).
The minimal changes fix would be to, say, add a class as you're fading it out:
function removeDiv() {
// Get the container (I take it there's only one .xx element)
var topmost = jQuery('.xx');
// Get the child elements that aren't fading
var zz = topmost.find('.zz').not('.fading');
// Too many?
if(zz.length > 5) {
// Yup, add 'fading' to the first one and fade it out
// Note that there's no need for the $target variable
zz.eq(0).addClass('fading').hide('slow', function(){ $(this).remove(); });
}
}
The problem is this:
var $target = jQuery('.xx').find('.zz').eq(0);
It's always 0 index.
function removeDiv(x) {
var topmost = jQuery('.xx');
var totContent = topmost.find('.zz').length;
var $target = jQuery('.xx').find('.zz').eq(x);
if(totContent > 5) {
$target.hide('slow', function(){ $target.remove(); });
}
}
function saveClubs(array) {
for(i=0; i<array.length; i++) {
var id = array[i];
jQuery.ajax({
type: "GET",
async: true,
url: 'index.php?option=com_events&task=club.save&id=' + id,
dataType: 'json',
success: function(data) {
jQuery('.xx').append('<div class="zz">'+data+'</div>');
removeDiv(i);
}
});
}
}
LIVE EXAMPLE HERE
NOTE
IN the Fiddle above, try to change this var $target = jQuery('.xx').find('.zz').eq(x); harcoding the value of x to 0 and it'll happen just once.

Categories

Resources