JavaScript Event Listener runs twice - javascript

As reference, please see my example in JSFiddle below. Every time somebody clicks on the plus button, a new row should be inserted below. This works fine except the fact that the amount of new rows inserted is always twice the amount of current existing rows. How can I avoid this strange behavior, or what's the reason for it? Please click the first rows button to see the issue.
http://jsfiddle.net/jrxeua6L/
var answers = [{
order: 1,
content: "placeholder"
}],
appendAnswer = function() {
answers.push({
order: answers.length + 1,
content: $(this).parent().prev().val()
});
$("#answers").empty();
$.each(answers, function(key, value) {
$("#answers").append('<div class="input-group"><input type="text" class="form-control" placeholder="Enter your answer"><span class="input-group-btn"><button type="button" class="btn btn-default" title="Add a question" data-action="add"><span class="glyphicon glyphicon-plus"></span></button><button type="button" class="btn btn-default" title="Delete this question" data-action="delete" disabled><span class="glyphicon glyphicon-trash"></span></button></span></div>');
$("#answers button[data-action='add']").one("click", appendAnswer);
});
};
$("#answers button[data-action='add']").one("click", appendAnswer);

Use event-delegation
$("#answers").on("click", "button[data-action='add']",appendAnswer);
The cause of your problem is that you are binding multiple events on same elements in the each loop, so remove the delegation there.
Remove this line below from the .each() loop
$("#answers button[data-action='add']").one("click", appendAnswer);
DEMO

Here is a working solution http://jsfiddle.net/jrxeua6L/4/
var answers = [{
order: 1,
content: "placeholder"
}],
appendAnswer = function() {
answers.push({
order: answers.length + 1,
content: $(this).parent().prev().val()
});
$("#answers").empty();
$.each(answers, function(key, value) {
$("#answers").append('<div class="input-group"><input type="text" class="form-control" placeholder="Enter your answer"><span class="input-group-btn"><button type="button" class="btn btn-default" title="Add a question" data-action="add"><span class="glyphicon glyphicon-plus"></span></button><button type="button" class="btn btn-default" title="Delete this question" data-action="delete" disabled><span class="glyphicon glyphicon-trash"></span></button></span></div>');
//$("#answers button[data-action='add']").on("click", appendAnswer);
});
};
$('body').on("click", "#answers button[data-action='add']", appendAnswer);

Change this line:
$("#answers button[data-action='add']").one("click", appendAnswer);
To this:
$("#answers button[data-action='add']").off("click").one("click", appendAnswer);

Related

Cannot change the innerHTML element

I want to change a button inside a td tag (see at the bottom an example).
var tableEntryButton = document.getElementById('slButton' + message.content[1])
delivers correctly the td element I am looking for:
<td id="slButtonAudi" data-value="false">
<button id="slButtonActive" class="btn btn-outline-success btn-sm" type="button" onclick="handleClickOnSSButton(this)">Start</button>
</td>
Here my function that should make the change possible.
Here I distinguish by the ID within the button tag what change I can apply (remove the current start/stop button and add the button with the opposite function)
var tableEntryButton = document.getElementById('slButton' + message.content[1])
let activeButton = '<button id="slButtonActive" class="btn btn-outline-success btn-sm" type="button" onclick="handleClickOnSSButton(this)">Start</button>'
let inactiveButton = '<button id="slButtonInactive" class="btn btn-outline-warning btn-sm" type="button" onclick="handleClickOnSSButton(this)">Stop</button>'
if (tableEntryButton.innerHTML.includes('slButtonActive')) {
tableEntryButton.removeChild(tableEntryButton.firstChild)
tableEntryButton.innerHTML = inactiveButton
}
else {
tableEntryButton.removeChild(tableEntryButton.firstChild)
tableEntryButton.innerHTML = activeButton
}
The if/else allocation works correctly.
It appears that only the changes within the if/else statement are somehow not being applied.
To clarify it here an example.
If this is given:
<td id="slButtonAudi" data-value="false">
<button id="slButtonActive" class="btn btn-outline-success btn-sm" type="button" onclick="handleClickOnSSButton(this)">Start</button>
</td>
it should be changed to that:
<td id="slButtonAudi" data-value="false">
<button id="slButtonInactive" class="btn btn-outline-warning btn-sm" type="button" onclick="handleClickOnSSButton(this)">Stop</button>
</td>
You are not using the innerHtml correctly.
I made you an example that will do exactly what you asked in your last example.
if (tableEntryButton.innerHTML.includes('slButtonActive')) {
//Get the children button.
let button = tableEntryButton.querySelector("#slButtonActive");
if (button) {
tableEntryButton.removeChild(button);
tableEntryButton.innerHTML += inactiveButton;
}
}
Here is the working fiddle:
https://jsfiddle.net/vrtfoh9q/20/
Some documentation:
https://plainjs.com/javascript/manipulation/append-or-prepend-to-an-element-29/
https://www.w3schools.com/js/js_htmldom_nodes.asp
Hope it helps!
you can access children by children property in HTML element and use innerHTML once time like this:
HTML
<div id="div1">
<button id="btn1Active">Active</button>
</div>
JS
let divTarget = document.getElementById('div1'),
child = divTarget.children[0],
btnActive = '<button id="btn1Active">Active</button>',
btnInactive = '<button id="btn1Inactive">Inactive</button>'
if (child.id == 'btn1Active') divTarget.innerHTML = btnInactive
else divTarget.innerHTML = btnActive
CodePen example
https://codepen.io/bragamonte/pen/PBLojZ

How to get data from attributes then disable buttons accordingly

I have run a bit of problem with our user interface, here's my code:
I have a button here inside a
<button class="btn btn-info" type="button" id="btnSubmit" data-btn="{{ row[1] }}" data-id="{{ row[2] }}" data-toggle="modal" data-target="#myModal" contenteditable="false" disabled='disabled'> Pay</button>
I have been using row[2] from another function and it worked, so this time i used row[1] to evaluate data. The condition is that
when the row[1] of that row is empty the button would be disabled and would be colored to btn btn-danger and the text would be
made to "Paid" however thorugh my attempts I only made everything disabled or perhaps the last entry only as disabled. Here's my latest attempt:
<script type="text/javascript">
$(document).ready(function() {
var button = document.getElementById('btnSubmit');
var id = button.dataset.id;
$('#btnSubmit').attr('data-btn').onkeyup(function() {
if($(this).val() != '') {
$('#btnSubmit').prop('disabled', true);
}
else{
$('#btnSubmit').prop('disabled', false);
}
});
});
</script>
And its disabling all buttons. I just want the bytton to be enabled when its empty and disabled if its empty, and again as Ive said would be colored to btn btn-danger and the text would be made to "Paid" how do I do this in this case?
I've read the documentations and everything but it didn't work for some reasons. I also tried having an invisible input and getting its id but no luck. Please help
Okay... Assuming that data-bnt is the target element to check on keyup.
(I don't know what data-id is for...)
And that the target must not be empty to enable the submit button.
Then try this:
$(document).ready(function() {
var button = $('#btnSubmit');
var target = $('#'+button.data('btn'));
target.on("keyup",function(){
button.prop('disabled', ($(this).val() == '') ? true : false );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="targetID">
<button
class="btn btn-info"
type="button"
id="btnSubmit"
data-btn="targetID"
data-toggle="modal"
data-target="#myModal"
contenteditable="false"
disabled='disabled'> Pay</button>

How to add fontawesome spinner inside onclick?

So I have this code inside my php echo;
<input type="submit" value="Send Love" class="btn btn-primary" onclick="this.form.submit(); this.disabled=true; this.value=\'Sending Love…\';" />
As you can see the text will change onclick and the button will be disabled and the form will be submitted. But what i'm trying to do is add a fontawesome spinner besides Sending so the button will have a spinner when its being submitted. I tried adding it but it doesn't show up and it breaks the output of the code; I also tried using '\'\ like with the Sending but it still doesn't show up and the onclick functions are broken.
<input type="submit" value="Send Love" class="btn btn-primary" onclick="this.form.submit(); this.disabled=true; this.value=\'<i class="fa fa-spinner fa-spin"></i> Sending Love…\';" />
So anyone could help me fix this thing? Really want to add that spinner. Thanks in advance!
You have to take <button ... > for that. Try this:
<button type="submit" class="btn btn-primary" onclick="sendLove(this);" > Send Love</button>
<script>
function sendLove(this1)
{
//alert('asdasd');
this1.disabled=true;
this1.innerHTML='<i class="fa fa-spinner fa-spin"></i> Sending Love…';
}
</script>
Hello, here is full-fledged working example..
https://jsbin.com/bezomapeba/edit?html,js,console,output
Made it to work using Chay22's suggestion of using jquery click
Button:
<button type="submit" id="sendbtn" class="btn btn-primary">Send Love</button>`
Script:
$('#sendbtn').click(function(){
this.form.submit();
this.disabled=true;
this.innerHTML='<i class="fa fa-spinner fa-spin"></i> Sending Love…';
});
the problem is of browser's part, cos he think it html and handle it, try to do that with js, echo '<input type="submit" value="Send Love" class="btn btn-primary" onclick="this.form.submit(); this.disabled=true; this.value=\'<i class="fa fa-spinner fa-spin">Sending Love…</i>\';>';
JavaScript's way
Hope this is helpful and better. Add a div above your submit button
<div class="loading" style="display: none;"><i class="fa fa-spinner fa-spin"></i> Progressing …</div>
or add button like below
<button type="submit" class="btn btn-primary"><i style="display:none" class="fa fa-spinner fa-spin loading"></i> Send Love</button>
$(document).ready(function(){
$("#sendbtn").click(function(){ // your submit button id
var isValid = document.querySelector('#myform')
if (isValid.checkValidity())
$(".loading").show();
});
});
Smallest, lightweight, and reusable
We made a custom jQuery.fn:
jQuery.fn.extend({
spin: function () {
this.data("original-html", this.html());
var i = '<i class="fa fa-spinner fa-pulse fa-3x fa-fw" style="font-size:16px; margin-right:10px"></i>';
this.html(i + this.html());
this.attr("disabled", "disabled");
},
reset: function () {
this.html(this.data("original-html"));
this.attr("disabled", null);
}
});
This can be used as follows:
$("button").click(function () {
var b = $(this);
b.spin();
$.ajax({
url: "",
button: b,
success: function (result) {
// do something
b.reset();
}
});
});

jQuery: Button add and remove closest

I have a HTML as follows:
<div class="parent-wrapper">
<div class="test-guided-search-row">
<select class="form-control test-guided-search-row-select-bool-query">
<option>AND</option>
</select>
<select class="form-control test-guided-search-row-select-query-path">
<option>ALL</option>
</select>
<select class="form-control test-guided-search-row-query-type">
<option>abcd</option>
<option>efg</option>
</select>
<input class="form-control" type="text">
<button class="btn btn-primary btn-sm" type="button" data-button-action="addRow">+</button>
<button class="btn btn-primary btn-sm" type="button" data-button-action="deleteRow">-</button>
</div>
</div>
How can I make it so that the button + will add the entire row div next to the div in which the button that was clicked? I am having trouble with this because there are multiple of these row divs and I want to be able to add row next to this div row and remove only that row.
To achieve this you need to use delegated event handlers as the button elements will be dynamically appended to the DOM. From there you can use closest() to find the row, along with clone() and append() or remove() respectively.
Firstly, add classes to the buttons to make identifying them easier:
<button class="btn btn-primary btn-sm btn-add" type="button" data-button-action="addRow">+</button>
<button class="btn btn-primary btn-sm btn-delete" type="button" data-button-action="deleteRow">-</button>
Then you can attach events to them:
$('.parent-wrapper').on('click', '.btn-add', function() {
$(this).closest('.test-guided-search-row').clone().appendTo('.parent-wrapper');
}).on('click', '.btn-delete', function() {
$(this).closest('.test-guided-search-row').remove();
});
Example fiddle
find your row, clone it, append it.
$('.button').on('click', function() {
var row = $(this).closest('.test-guided-search-row').clone();
$('.parent-wrapper').append(row);
})
find your row, delete it.
delete
$('.button').on('click', function() {
var row = $(this).closest('.test-guided-search-row').remove();
})
// you need to define what button is + what button is - with a class name
$('.parent-wrapper').on('click', '.btn-add', function() {
var row = $(this).closest('.test-guided-search-row').clone();
$(this).closest('.test-guided-search-row').after(row);
}).on('click', '.btn-delete', function() {
$(this).closest('.test-guided-search-row').remove();
});
This is what exactly solved my issue. I wanted to append to the closest button click row.
If you want to be able to add row next to a particular div row and remove only that row, you need to add a number as the id to each
This might help:
Pass
$(this).closest('.new-wrapper')[0].id
to addRow(rowId) when clicking on the + button.
function addRow(rowId){
var next = rowId+1;
$(".parent-wrapper #rowId").after('<div id="'+next+'" class = "new-wrapper"> $(".test-guided-search-row").html() </div>);
}

Knockout.JS 'enable' binding on length condition not working

All the data displaying and adding / deleting buttons seem to work until I change the delete button to do a check to make sure that there is always at least one person on the screen:
<!-- Check number of items before enabling delete button !-->
<button type="button" data-bind='enable: people().length > 1, click: $root.removePerson'>Delete</button>
The error is as follows:
Uncaught ReferenceError: Unable to process binding "foreach: function (){return people }"
Message: Unable to process binding "enable: function (){return people().length > 1 }"
Message: people is not defined
HTML
<div data-bind='foreach: people'>
<div class="personWell">
<input type="text" data-bind="value: name"></input>
<input type="text" data-bind="value: company"></input>
<button type="button" class="btn btn-sm btn-warning" data-bind='click: $root.removePerson'>Delete</button>
</div>
</div>
<button type="button" class="btn btn-sm btn-primary" data-bind='click:addPerson'>Add Person</button>
JavaScript
var ObservedPersonModel = function(people) {
var self = this;
self.people = ko.observableArray(people);
self.addPerson = function() {
self.people.push({
person_id:"",
name: "",
company: "",
positive_observation_id:""
});
};
self.removePerson = function(person) {
self.people.remove(person);
};
};
//originalPeopleObserved is a JSON encoded list of objects
var peopleViewModel = new ObservedPersonModel(originalPeopleObserved);
ko.applyBindings(peopleViewModel);
Resources
Here are some of the links where I learned about this functionality:
http://jsfiddle.net/rniemeyer/7RDc3/
http://knockoutjs.com/examples/gridEditor.html
Try this:
<button type="button" data-bind='enable: $root.people().length > 1, click: $root.removePerson'>Delete</button>
Actually i got your code running in a fiddle. First thing i changed was two > you forgot in your html code:
<input type="text" data-bind="value: name"></input>
<input type="text" data-bind="value: company"></input>
Then i added an empty object for testing:
originalPeopleObserved = null;
var peopleViewModel = new ObservedPersonModel(originalPeopleObserved);
ko.applyBindings(peopleViewModel);
And on Safari i can use your sample as expected.
Try this fiddle here

Categories

Resources