How to avoid collapse actions trigger multiple times - javascript

I want to change a text and show/hidde an svg icon with classes when click on collapse.
Every time I execute the code above the code executes one more time and I don't know why,
example:
1st time = `alert(show)`
2nd time = `alert(hide), alert(hide)`
3er time = `alert(show), alert(show), alert(show)`
etc...
here is my code:
$('span[name="serviceCollapse"]').click(function() {
var target = $(this).attr("data-target");
var label = $(this).find("label");
var span = $(this);
$(target).on('hide.bs.collapse', function () {
label.text("Mostrar más servicios ");
alert("hide");
var arrowUp = span.find(".d-inline");
var arrowDown = span.find(".d-none");
arrowUp.removeClass("d-inline");
arrowUp.addClass("d-none");
arrowDown.removeClass("d-none");
arrowDown.addClass("d-inline");
});
$(target).on('show.bs.collapse', function () {
label.text("Mostrar menos servicios ");
alert("show");
var arrowDown = span.find(".d-inline");
var arrowUp = span.find(".d-none");
arrowDown.removeClass("d-inline");
arrowDown.addClass("d-none");
arrowUp.addClass("d-inline");
arrowUp.removeClass("d-none");
});
});
EDIT:
Here is the html code:
<div class="col-12 mt-2">
<span name="serviceCollapse" data-target="#service1" data-toggle="collapse">
<label class="text-custom-primary bold-300">Mostrar más servicios </label>
<span class="d-inline">arrowDownSvgIcon</span>
<span class="d-none">arrowUpSvgIcon</span>
</span>
<div id="service1" class="collapse mt-3">
collapsable
</div>
</div>

Actually as per your code you are adding multiple event handlers instead you just need to add event handlers on listeners once initially and that would be it.
Every time click is happening more handlers are appended on the event listeners that's causing the problem.

SOLUTION:
Set the event handler only once. And in the click event of 'serviceCollapse' check for its state to print the alert message.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<div class="col-12 mt-2">
<span class="collapsed" name="serviceCollapse" data-target="#service1" data-toggle="collapse">
<label class="text-custom-primary bold-300">Mostrar más servicios </label>
<span class="d-inline">arrowDownSvgIcon</span>
<span class="d-none">arrowUpSvgIcon</span>
</span>
<div id="service1" class="collapse mt-3">
collapsable
</div>
</div>
<script>
$(document).ready(function() {
var target = $('span[name="serviceCollapse"]').attr("data-target");
$(target).on('hide.bs.collapse', function () {
var label = $(this).find("label");
var span = $(this);
label.text("Mostrar más servicios ");
var arrowUp = span.find(".d-inline");
var arrowDown = span.find(".d-none");
arrowUp.removeClass("d-inline");
arrowUp.addClass("d-none");
arrowDown.removeClass("d-none");
arrowDown.addClass("d-inline");
});
$(target).on('show.bs.collapse', function () {
var label = $(this).find("label");
var span = $(this);
label.text("Mostrar menos servicios ");
var arrowDown = span.find(".d-inline");
var arrowUp = span.find(".d-none");
arrowDown.removeClass("d-inline");
arrowDown.addClass("d-none");
arrowUp.addClass("d-inline");
arrowUp.removeClass("d-none");
});
$('span[name="serviceCollapse"]').click(function() {
console.log($(this).attr("class"));
if ($(this).attr("class") === "collapsed") alert ("show");
else alert("hide");
});
});
</script>
</body>
</html>

Related

Materialize datepicker is not opening inside a modal

In my webpage I have a button to trigger a modal. Inside that modal there is a input field for date. If I click the datepicker it is supposed to be opened.
However, the code is not working if the input date field is inside a modal. For testing purpose I brought it outside and then it is working perfectly.
My code is below,
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
</head>
<body>
<div class="container">
<button class="btn modal-trigger" href="#testModal">Open Modal</button>
<div id="testModal" class="modal modal-fixed-footer">
<input type="text" name="testDate1" class="datepicker">
</div>
<input type="text" name="testDate2" class="datepicker">
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.datepicker');
var instances = M.Datepicker.init(elems,{});
});
</script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
});
</script>
</html>
There are two input field. One is named 'testDate1' which is inside the modal. Another one is named 'testDate2' which is outside. The outside one is working. Not the inside one.
How can I use datetime modal inside another modal?
Your datepicker inside modal is getting loaded, but do not have height. Set the height to 100%.
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.datepicker');
var instances = M.Datepicker.init(elems,{});
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
});
#testModal .modal {
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet"/>
<div class="container">
<button class="btn modal-trigger" href="#testModal">Open Modal</button>
<div id="testModal" class="modal modal-fixed-footer">
<input type="text" name="testDate1" class="datepicker">
</div>
<input type="text" name="testDate2" class="datepicker">
</div>
Add
container: "body"
to the options, when initializing the materialize modal and it will open inside the body, not inside the modal!
Jquery add line ' container: "body" '
$(document).ready(function(){
$('.timepicker').timepicker({
container: "body", // carregar dentro do MODAL ------------------------
default: 'now', //hora atual
fromnow: 0, // padrão para o milesegundos
twelvehour: false, // AM/PM = false | 24h = true
format: "HH:ii:SS",
donetext: 'ok', // btn OK
cleartext: 'limpar', // bnt clear
canceltext: 'cancelar', // btn cancel
autoclose: false, // fechar automatico
ampmclickable: true, // AM PM clicavel
vibrate: true
});
});

LocalStorage removes the wrong value

I keep having the same issue again and again : When I add a task, it gets added to the localStorage correctly. But once I have multiple tasks and I click complete on a random one, sometimes it happens that the LocalStorage removes the task before it or after it. I can't figure out a way how to let it work.
let addBtn = document.getElementById("addButton");
let textInput = document.getElementById("textInput");
let mainList = document.getElementById("mainList");
let storage = JSON.parse(localStorage.getItem("toDos")) || [];
if (storage.length != 0){
for (let i=0; i<storage.length;i++){
addTask(mainList, storage[i]);
};
};
function addTask(list,task){
var newTask = document.createElement("li");
newTask.textContent=task
newTask.className="task d-flex justify-content-between list-group-item bg-primary mt-2";
addCompleteBtn(newTask);
list.appendChild(newTask);
}
function addCompleteBtn (newTask){
let completeBtn = document.createElement("button");
completeBtn.className="btn btn-success completeBtn";
completeBtn.textContent="Completed";
newTask.appendChild(completeBtn);
};
addBtn.addEventListener("click", ()=>{
if(textInput.value === ""){
alert("Error: The field is either empty or you entered more than 100 characters!");
}else{
storage.push(textInput.value);
addTask(mainList, textInput.value);
textInput.value="";
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
mainList.addEventListener("click",(evt)=>{
if (evt.target.className==="btn btn-success completeBtn") {
let listItem = evt.target.parentNode;
let mainUl = listItem.parentNode;
let toBeRemoved = listItem.textContent;
storage.splice(storage.indexOf(toBeRemoved),1);
mainUl.removeChild(listItem);
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>To-do-list App</title>
</head>
<body>
<div class="jumbotron bg-info">
<div class="container">
<h1 class="display-4 text-center">Task List</h1>
<p class="lead text-center">Click on the Add button to add a task</p>
</div>
</div>
<div class="container">
<div class="firstInput input-group mb-5">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" id="addButton">Add Task</button>
</div>
<input type="text" title='Enter a Task' class="form-control" id="textInput" maxlength="200">
</div>
</div>
<ul class='tasksList container' id="mainList">
</ul>
<script src="script.js"></script>
</body>
</html>
Shows all the values in the LocalStorage
Once task 2 is removed, task 3 is removed from the Storage instead
this is the specific part that causes me issues :
mainList.addEventListener("click",(evt)=>{
if (evt.target.className==="btn btn-success completeBtn") {
let listItem = evt.target.parentNode;
let mainUl = listItem.parentNode;
let toBeRemoved = listItem.textContent;
/* This is the part of code causing me issues
storage.splice(storage.indexOf(toBeRemoved),1);
*/
mainUl.removeChild(listItem);
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
The problem is here let toBeRemoved = listItem.textContent;,this will return the text content of all elements inside that li. So if you add a task named 'Task 1', when you press Completed the value of toBeRemoved will be Task 1Completed since this will return the text of the button as well since your button is a child of the li.
So change let toBeRemoved = listItem.textContent; to let toBeRemoved = listItem.childNodes[0].nodeValue; and you should be fine, this will get the text of the li only.

Javascript onclick firing when the page loads [duplicate]

This question already has answers here:
Calling functions with setTimeout()
(6 answers)
Closed 6 years ago.
I'm having issues using Javascript to run a function. What I want to happen is I want the function to fire off when the user clicks a button. However, it fires off when the page loads.
Here is the entire code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<input type="submit" id="btn" value="Load">
<div id="description">
<div id="info">
<h1 id="title"></h1>
<p id="description"></p>
<ul id="list"></ul>
</div>
</div>
</div>
<div class="col-md-2"></div>
</div>
</div>
<script>
var btn = document.getElementById('btn');
var title = document.getElementById('title');
var description = document.getElementById('description');
var list = document.getElementById('list');
btn.onclick = load();
function load() {
alert("Working.");
}
</script>
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
Right now, it obviously doesn't do much except fire off an alert box. But I'll by using it to load in a file via XMLHttpRequest object later. But right now, its not working the way it should.
I should also point out that the code works fine with an anonymous function, But the whole idea is to have a normal function. I'm just not sure why it would work with an anonymous function and not a normal one.
It should be
var btn = document.getElementById('btn');
var title = document.getElementById('title');
var description = document.getElementById('description');
var list = document.getElementById('list');
btn.onclick = load;
function load() {
alert("Working.");
}
DEMO

Need help in moving divs to another div after an onclick function

I have a container holding four divs. After I click on one div, the remaining three neeed to be appended to another div. How can I achieve this?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Week 4 Game</title>
<link rel = "stylesheet" type = "text/css" href = "assets/css/reset.css">
<link rel="stylesheet" type="text/css" href="assets/css/style.css">
<!-- Added link to the jQuery Library -->
<script src="https://code.jquery.com/jquery-2.2.3.js" integrity="sha256-laXWtGydpwqJ8JA+X9x2miwmaiKhn8tVmOVEigRNtP4=" crossorigin="anonymous"></script>
<script type="text/javascript" src = "assets/javascript/game.js"> </script>
</head>
<body>
<div class = "characters">
<div class="charContainer darth">
<h2 id="c1"></h2>
<img class="vade" src="assets/images/vader.jpg">
<p id="c1hp" data-hp = "120"></p>
</div>
<div class="charContainer luke">
<h2 id="c2"></h2>
<img class="skywalker" src="assets/images/luke.jpg">
<p id="c2hp" data-hp = "100"></p>
</div>
<div class="charContainer won">
<h2 id="c3"></h2>
<img class="obi" src="assets/images/obiwan.jpg">
<p id="c3hp" data-hp = "150"></p>
</div>
<div class="charContainer maul">
<h2 id="c4"></h2>
<img class="dmaul" src="assets/images/maul.png">
<p id="c4hp" data-hp = "180"></p>
</div>
</div>
<div id="your">
<h2>Your Character</h2>
<!-- <img class="dmaul" src="assets/images/maul.png"> -->
</div>
<div id="enemies">
<h2>Enemies</h2>
<!-- <img class="dmaul" src="assets/images/maul.png"> -->
</div>
</body>
</html>
JQuery
$(document).ready(function(){
var yourCharacter;
var enemy1;
var enemy2;
var enemy3;
$('#c1').text("Darth Vader");
$('#c2').text("Luke Skywalker");
$('#c3').text("Obi Won");
$('#c4').text("Darth Maul");
var health = $('#c1hp').data('hp');
$('#c1hp').html(health);
var health = $('#c2hp').data('hp');
$('#c2hp').html(health);
var health = $('#c3hp').data('hp');
$('#c3hp').html(health);
var health = $('#c4hp').data('hp');
$('#c4hp').html(health);
$('.charContainer').on('click', function(){
yourCharacter = $(this);
$('#your').append(yourCharacter);
enemy1 = $('.vader');
$('#enemies').append(enemy1);
})
});
I need to append the remaind charContainers that were not clicked to the enemies container div
This works for me. You may want to add a check for equality, since the chosen div will be initially appended to enemies, then moved:
$('.charContainer').on('click', function(){
$('.charContainer').each(function() {
$('#enemies').append($(this));
})
yourCharacter = $(this);
$('#your').append(yourCharacter);
})
Since "your character" has already been moved by the time the rest of the characters need to be moved, the selector '.characters>.charContainer' (all the "charContainer" children of "characters") will not select your character (since it's already moved) - just the remaining characters
$('.charContainer').on('click', function() {
$('#your').append($(this));
$('.characters>.charContainer').each(function() {
$('#enemies').append($(this));
});
})
Alternate version using arrow function:
$('.charContainer').on('click', function() {
$('#your').append($(this));
$('.characters>.charContainer').each( (undefined, char) => { $('#enemies').append($(char)) } );
})
Or borrowing Tekebo's use of appendTo:
$('.charContainer').on('click', function() {
$(this).appendTo('#your');
$('.characters>.charContainer').appendTo('#enemies');
})
Note: the main advantage of using the children selector as opposed to the siblings of the clicked div or all divs of the 'charContainer' class is that it doesn't matter which order it's done in - the result will be the same. (However, moving the clicked div last will cause more work to be done)
You could simply use siblings(), like this:
$(document).ready(function(){
$(".charContainer").on("click",function(){
$(this).siblings().appendTo("#enemies");
$(this).appendTo("#your");
});
});

Including Bootstrap Classes with js

As exercise, I'm creating a simple quiz app without using jQuery. I'm trying to add radio buttons as answer options using javascript
html body as follows
<div class="row">
<div class="col-md-6 col-md-offset-3">
<p id="question"></p>
<form name="answers">
<fieldset class="form-group">
<div class="form-check" id="answersId">
</div>
</fieldset>
</form>
</div>
</div>
my js script below would add radio buttons within div class="form-check"
function firstQuestion() {
var answerSection = document.getElementById("answersId");
for(var i = 0; i < allQuestions[0].choices.length; i++) {
var radioElement = [];
radioElement[i] = document.createElement("input");
radioElement[i].setAttribute("class", "form-check-input");
radioElement[i].setAttribute("type", "radio");
radioElement[i].setAttribute("name", "choice");
radioElement[i].setAttribute("value", i);
var label = [];
label[i] = document.createElement("label");
label[i].setAttribute("class", "form-check-label");
var labelText = [];
labelText[i] = document.createTextNode(allQuestions[0].choices[i]);
label[i].appendChild(radioElement[i]);
label[i].appendChild(labelText[i]);
answerSection.appendChild(label[i]);
};
}
I'm not able to get the bootstrap appearance, i.e.:
-each radio button is inline, rather than in a new line (arranged vertically)
-spacing between the button and label is not like bootstrap example
Why is this so? Could someone point out to me?
thats because bootstrap relies on jquery, you can't expect bootstrap to work without jquery
var answerSection = document.getElementById("answersId");
var radioElement = [];
var label = [];
var labelText = [];
var span;
for (i = 1; i < 4; i++) {
span = document.createElement("span");
span.setAttribute("style", "padding:15px");
radioElement[i] = document.createElement("input");
radioElement[i].setAttribute("class", "form-check-input");
radioElement[i].setAttribute("type", "radio");
radioElement[i].setAttribute("name", "choice");
radioElement[i].setAttribute("value", i);
label[i] = document.createElement("label");
label[i].setAttribute("class", "form-check-label");
labelText[i] = document.createTextNode("choice " + i);
label[i].appendChild(radioElement[i]);
label[i].appendChild(labelText[i]);
span.appendChild(label[i]);
answerSection.appendChild(span);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="row">
<div class="col-md-6 col-md-offset-3">
<p id="question"></p>
<form name="answers">
<fieldset class="form-group">
<div class="form-check" id="answersId">
</div>
</fieldset>
</form>
</div>
</div>
You should add these 3 lines to make bootstrap work. These are the CDN links, but if you have these on your computer then add them properly
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
And as said by #leccionesonline bootstrap.min.js requires jquery.min.js file. Hence you should load jquery.min.js before bootstrap.min.js
Here is refrence link

Categories

Resources