Query select elements everytime partial is loaded by Vanilla Javascript in Rails - javascript

I have a partial inside a partial which has radio buttons or check boxes. What I want to do is to get the radio button or checkboxes which are clicked. Now initially when the page is loaded I am able to get the buttons but when I go to the next partial I am not able to get the new buttons. How can I get the buttons of the new partial everytime some button is clicked in a separate js. If I use onclick function inline with radio button or checkbox then the function is called correctly but I want to get the present displayed elements in a separate js file.
I tried to use window.addEventListener('change'). If I use this then the function is not called on first click but in the subsequent clicks it calls that many number of times i.e., on second click the function is called once, on third click the function is called twice and so on.
// window.addEventListener('change', () => {
window.addEventListener('DOMContentLoaded', () => {
if (document.querySelectorAll('[name="question[answer_id]"]').length !== 0) {
document.querySelectorAll('[name="question[answer_id]"]').forEach((questionAnswerButton) => {
questionAnswerButton.addEventListener('click', (event) => {
console.log(event);
fetchCall(event.target.value);
});
});
}
});
radio_button_partial.html.erb
<%= radio_button_tag 'question[answer_id]',
answer.id,
(user_answer == answer.id),
{
class: 'answer_opt',
// onclick: fetchCall("<%= answer.id %>")
} %>
Here if I uncomment the onclick function then I get the desired functionality. But what should I change in this that I get the present displayed radio buttons from the separate js file?

Instead of attaching a listener directly to the elements you want to use event bubbling:
document.addEventListener('click', (event) => {
if (event.target.matches('[name="question[answer_id]"]')) {
console.log(event);
fetchCall(event.target.value);
}
});
When an event is fired it up bubbles up the DOM until a handler is found. Unlike attaching event handlers directly to the elements this is idempotent and the handler will work for elements dynamically inserted into the page. Its also compatible with turbolinks.
This code should not be placed in a script tag or .js.erb abomination as it will add a handler every time the code is executed. Put it in the assets pipeline.
If fetchCall does an ajax call you will want to use a debouncing technique such as disabling the input and re-enabling it when the promise is resolved.
document.addEventListener('click', (event) => {
if (event.target.matches('[name="question[answer_id]"]')) {
console.log(event);
// Todo refactor fetchCall so that it returns a promise
let promise = fetchCall(event.target.value);
event.target.disabled = true;
promise.then((successMessage) => {
event.target.disabled = false;
});
}
});

Related

JQUERY Click event doesn't work only at the first click call

In the code, I try to print the name that is saved as a data value for each button.. but on the first click event call it doesn't work. while after the first time it works normally.
NOTE: off('click') function it is because without it this function fires multiple times with the following rate: 1times on a click, 2times on the next click, 3times on the next click, 4times on the next click, ...... and so on.
So it(off('click')) prevents this to happen.
$(document).on('click', '.btn-add', () => {
$(".btn-add").off('click').on('click', (obj) => {
const nameOfProduct = obj.currentTarget.value;
console.log("name selected = " + nameOfProduct);
})
})
This is probably what you want to do, after document is ready, add button click handler:
$(document).ready(() => {
$(".btn-add").on('click', (obj) => {
const nameOfProduct = obj.currentTarget.value;
console.log("name selected = " + nameOfProduct);
})
})
Your code removes handler then adds handler to the button click after every click on button..
So after first click, you try to remove, then you add handler.
After that you fire handler function, remove handler and add handler, which is probably not what you want to do.

How to prevents events from firing multiple time

For some reason I have to call the same function twice because of that my event are firing twice. How can I prevent this?
function renderSeats(movieImg, title, release_date, dummyPrice = '3000') {
// selected items
//this is only a part of the code .
contianer.addEventListener('click', function (e) {
if (
e.target.classList.contains('seat') &&
!e.target.classList.contains('unavailable')
) {
e.target.classList.toggle('selected');
payoutBtn.classList.add('active');
console.log('yes');
updateCountTotal(); //function call
}
contianer.setAttribute('listener', 'true');
});
const ticketOverlayClose = document.querySelector('.ticket__close-svg');
// overlay deactive
ticketOverlayClose.addEventListener('click', function (e) {
overlayseats.classList.add('hidden');
payoutBtn.classList.add('active');
ticketContainer.classList.remove('active');
});
}
Every time I am calling the function from another function because I have to update the dom, suppose 3 times the event then also fire 3 times
I also attached an image. In the console, you see after I clicking back (it is a single-page app) and again load by page calling our rendered seat function, and this time when I click on the seats the even is firing twice.
[gif][1]:https://i.stack.imgur.com/Ik1CG.gif

Double-click prevention on save

I have a kendo grid with its dataSource, the grid has an editor dialogue with save button. I need to prevent the save button being double clicked. The onsave functions fire when the save button is clicked. I have a requestEnd event that fires when the save is to be re-enabled.
The problem: onSave1 looks to fail 1 time in 100 . It's based on adding an additional click handler, invoking preventDefault(). Is it fundamentally flawed?
Is onSave2 any better?
onSave1: function (e) {
$(event.srcElement)
.addClass("k-state-disabled")
.bind("click", disable = function (e) { e.preventDefault(); return false; })
this.dataSource.one("requestEnd", function () {
$("[data-role=window] .k-grid-update")
.off("click", disable)
.removeClass("k-state-disabled");
})
}
onSave2: function (e) {
$(event.srcElement)
.removeClass(".k-grid-update")
.addClass("k-state-disabled")
.addClass("disabledMarker");
this.dataSource.one("requestEnd", function () {
$("[data-role=window] .disabledMarker")
.addClass(".k-grid-update")
.removeClass("k-state-disabled")
.removeClass("disabledMarker");
})
}
First Jquery bind has been deprecated since version 3.0 so I would recommend not using it anymore. http://api.jquery.com/bind/
You do not need an onClick event or in your case bind because onSave is already being called during the click. So simply disable the button onSave. Second you should use complete or whatever kendo grid uses for when the save event is finished instead or requestEnd. Code listed below.
onSave: {$(event.srcElement)addClass("k-state-disabled")}, complete:{ $(event.srcElement)removeClass("k-state-disabled")};

jQuery - Bind click to specific Ajax content element

I have this form that loads using jQuery $.ajax another form inside a container.
The list:
The loaded content within the container called form_load_dropdown_content:
On the left I have two small icons for edit and add. I want to use another ajax call to run specific PHP scripts to carry on the action desired.
I have the following problem:
when I click on each icon submit and respectively reset buttons display
when I click on the reset the both submit and reset are set to display: none
when I click on any the icon again, the click remains bind to the previous icon clicked before.
This is what I am doing:
form_load_dropdown_content.on("click", ".icon", function() {
// reusable selectors
var icon_box = $(".box_edit_icons");
var button_box = $(".box_buttons");
var submit_btn = $(".box_buttons input[type='submit']");
var reset_btn = $(".box_buttons input[type='reset']");
var option_value_input = $("input.option_value");
var option_order_input = $("input.option_order");
// common functions
button_box.show();
icon_box.hide();
if($(this).hasClass("ico_edit_small"))
{
// editing
form_load_dropdown_content.on("click", "input[type='reset']", function(event){
alert("reset from edit");
button_box.hide();
icon_box.show();
});
}
else if($(this).hasClass("ico_add_small"))
{
// adding
form_load_dropdown_content.on("click", "input[type='reset']", function(event){
alert("reset from add");
button_box.hide();
icon_box.show();
});
}
How can I differentiate between the two clicks, so that when I display the submit and reset from a specific icon type to run differentiated actions?
More clear:
when I click icon_add_small and then reset => output: 'reset from add'
then when I click icon_edit_small and then reset => output: 'reset from edit'... and so on without mixing the clicks.
I truly appreciate any help. I tried everything regarding stopping the propagation of the click... but nothing worked.
-----------------------------------------------------------
Edit:
I changed the if part to the following code and it works. Should I expect any problems for unbinding the click?
if($(this).hasClass("ico_edit_small"))
{
// editing
reset_btn.off("click");
reset_btn.click(function(event){
alert("reset from edit");
button_box.hide();
icon_box.show();
});
}
else if($(this).hasClass("ico_add_small"))
{
// adding
reset_btn.off("click");
reset_btn.click(function(event){
alert("reset from add");
button_box.hide();
icon_box.show();
});
}

Assigning click event handler inside keyup event causes the click event to be fired multiple times

I am attempting to add an event handler to an anchor only when certain form fields are populated, like so:
$('#newName, #newFrom').keyup(function (e) {
if ($('#newName').val() || $('#newFrom').val()) {
$('#add-person').click(function (e) {
//Handle event, includes adding a row to a table.
$('this').off();
});
}
});
It seems like the first event is getting propagated to the second one since I end up with the same number of rows in my table as keys I have typed.
I've tried adding
e.stopPropagation();
But with no success.
$('this').off(); should be $(this).off();
also probably you'd better go using the input event instead of keyup. input event will trigger even if one pastes content into your fields.
nevertheless I'd go the other way around:
// (cache your selectors)
var $newName = $("#newName"),
$newFrom = $("#newFrom");
// create a boolean flag
var haveNewValue = false;
// modify that flag on fields `input`
$newName.add( $newFrom ).on("input", function() {
haveNewValue = ($.trim($newName.val()) + $.trim($newFrom.val())).length > 0;
});
// than inside the click test your flag
$('#add-person').click(function (e) {
if(!haveNewValue) return; // exit function if no entered value.
// do stuff like adding row to table
});
What was wrong:
on every keyup you was assigning a new (therefore multiple) click event/s to the button, but the (corrected to:) $(this).off() was triggered only after an actual button click.
Also a better way to use .on() and off.() (notice the difference in using the .click() method and the .on() method) is:
function doCoffee() {
alert("Bzzzzzzzz...BLURGGUZRGUZRGUZRG");
}
$("#doCoffeeButton").on("click", doCoffee); // Register "event" using .on()
$("#bossAlertButton").click(function() {
$("#doCoffeeButton").off("click"); // Turn off "event" using .off()
});

Categories

Resources