This question is an ongoing learning / discovery of these three questions. This issue for me started here:
First Post
Second Post
Now this post is regarding #StephenMuecke post about attaching the event handler dynamically. This was new to me so I had to read up but now I see that it does make sense.
Well after reading documentation and numerous SO posts I still can't seem to get the click event handler to fire??
This time I decided to take a different approach. I created a jsfiddle demonstrating the problem. http://jsfiddle.net/ramjet/93nqs040/17/
However the jsfiddle I had to change somewhat from reality to get it to work within their framework. Below is the actual code.
Parent Window script that launches modal...the alert Bound does fire.
<script>
$(document).ready(function ()
{
$("#new").click(function (e)
{
e.preventDefault();
var ischanging = false;
var financierid = 0;
var detailsWindow = $("#window").data("kendoWindow");
if (!detailsWindow)
{
// create a new window, if there is none on the page
detailsWindow = $("#window")
// set its content to 'loading...' until the partial is loaded
.html("Loading...")
.kendoWindow(
{
modal: true,
width: "800px",
height: "400px",
title: "#T("...")",
actions: ["Close"],
content:
{
url: "#Html.Raw(Url.Action("ActionName", "Controller"))",
data: { financierId: financierid, isChanging: ischanging }
}
})
.data("kendoWindow").bind('refresh', function (e)
{
alert('Bound');
$('document').on("click", "#save", function () { alert("i work");});
}).center();
}
detailsWindow.open();
});
</script>
The modal full html I didn't think was needed but if it is I will update it. This is just the element I am trying to dynamically bind to.
<input type="button" id="save" style="margin-right:10px;" value="Save Record" />
document doesn't need quotes:
$(document).on("click", "#save", function () { alert("i work");});
"document" searches for an element of document, not the actual document
$("document").length; //0
$(document).length; //1
Related
I use a jQuery window libray https://github.com/humaan/Modaal
which triggers events this way $("class of element").modaal({arg1, arg2,...});
--- I updated my question here to make it more general and used an iframe / Html instead of an external svg ---
To trigger an element e.g. in an external Html which is loaded within an iframe, I applied the following code to the iframe:
<iframe src="External.html" id="mainContent" onload="access()"></iframe>
which calls this function:
function access() {
var html = document.getElementById("mainContent").contentDocument.getElementById("IDofDIVelement");
html.addEventListener('click', function() {clicker();});
}
function clicker()
{
// console.log('hooray!');
$("#mainContent").contents().find("IDofDIVelement").modaal({});
//return false;
}
Actually it will only work on every second click. Any idea what I did not consider properly?
Best
You do not need to wait windows loading but iframe only:
$(function() {
$("#mainContent").bind("load",function(){
var myIframeElement = $(this).contents().find(".modaal");
myIframeElement.modaal({
content_source: '#iframe-content',
type: 'inline',
});
});
});
The reason why it did not work was that the iframe was not completely loaded, while jQuery tried to attach the function. As $(document).ready(function(){} did not work, the workaround was to initialize it with
$( window ).on( "load",function() {
$("#mainContent").contents().find("IDofDIVelement").modaal({});
});
This worked properly to attach the functionallity to an element within the iframe.
Actually modaal will vanish the envent handler after the overlay was opened and closed again.
So maybe someone wants to trigger an iframe element for modaal, too, here is a setup which would solve this issue.
(It can be optimised by #SvenLiivaks answer):
$(window).on("load", function() {
reload();
});
function reload() {
var length = $("#iframeID").contents().find("#IDofDIVelement").length;
// The following check will return 1, as the iframe exists.
if (length == 0) {
setTimeout(function() { reload() }, 500);
} else {
$("#iframeID").contents().find("#IDofDIVelement").modaal({
content_source: '#modalwrapper',
overlay_close: true,
after_close: function reattach() {
reload();
}
});
}
}
Just adding the bootstrap-confirmation extension for Bootstrap popover to some buttons on a project. I'm having issues with the options not being respected. I'm trying to get the popups to work as singletons and dismiss when the user clicks outside of them singleton and data-popout options, respectively - both set to true. I'm also not seeing any of my defined callback behavior happening.
I defined the options both in the HTML tags and in a function and neither works. Still getting multiple boxes and they don't dismiss as expected.
My JS is loaded after all other libraries and is in my custom.js file in my footer.
JS is as follows:
$(function() {
$('body').confirmation({
selector: '[data-toggle="confirmation"]',
singleton: true,
popout: true
});
$('.confirmation-callback').confirmation({
onConfirm: function() { alert('confirm') },
onCancel: function() { alert('cancel') }
});
});
An example of the box implemented on a button in my HTML is the following:
<a class="btn btn-danger" data-toggle="confirmation" data-singleton="true" data-popout="true"><em class="fa fa-trash"></em></a>
Any pointers would be appreciated. I even changed the default options in the bootstrap-confirmation.js file itself to what I want and still no luck.
Turns out I needed to rearrange a couple things to get this to work. I've left in the last_clicked_id etc stuff as I needed to add that to get the id value of what I'd just clicked.
// Product removal popup logic
var last_clicked_id = null;
var last_clicked_product = null;
$('.btn.btn-danger.btn-confirm').click(function () {
last_clicked_id = $(this).data("id");
last_clicked_product = $(this).data("product");
});
$('.btn.btn-danger.btn-confirm').confirmation({
singleton: true,
popout: true,
onConfirm: function () {
alert("DEBUG: Delete confirmed for id : " + last_clicked_product);
// TODO: Add AJAX to wipe entry and refresh page
},
onCancel: function () {
alert("DEBUG: Delete canceled for id : " + last_clicked_product);
}
});
I was a step ahead of myself with the callback logic which was not getting executed. Fixed by simply adding it to onConfirm: and onCancel: key values in the .confirmation() function. A bit of a RTFM moment there but this was unfortunately not very clear in the documentation.
I am using MVC Razor - The overall goal is to create a "print view" pop-up page.
The print view button is on the parent page, when clicked, an ajax event is fired which will populate an empty div with the contents that are to be included in the print preview:
//from the view
#Ajax.ActionLink("prntPreview", "Display", new { ID = Model.Detail.ID }, new AjaxOptions { UpdateTargetId = "modal" }, new { #class = "btnPreview" })
then, using JavasScript/jQuery I clone the contents of that newly populated div and create a new window with the contents:
//in the scripts file
$('.btnPreview').on('click', function () {
$(document).ajaxStop(function () {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
}, 300);
});
});
function PopupPrint(data) {
var mywindow = window.open('', '', 'height=500,width=800,resizable,scrollbars');
mywindow.document.write(data);
mywindow.focus();
//do some other stuff here
}
This is where I run into difficulty. The first time I click, everything is working as expected - however, if you do not navigate away from the parent page and try to use the print preview button a second time, the popup will be created twice, then three times etc. with each additional click.
I think that the problem is because each time the .btnPreview is clicked, a new $(document).ajaxStop event is being created, causing the event to fire multiple times.
I have tried to create the ajaxStop as a named function which is declared outside the scope of the click event and then clear it but this produces the same result:
var evnt = "";
$('.btnPreview').on('click', function () {
evnt =
$(document).ajaxStop(function () {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
evnt = "";
}, 300);
});
});
I also have other ajaxStop events initialised so don't want to completely unbind the ajaxStop event. Is it possible to get the name or something from each ajax event so that I can clear just that event or similar?
You can prevent adding additional triggers by checking with a variable outside of scope like this:
(function() {
var alreadyAdded = false;
$('.btnPreview').on('click', function() {
if (!alreadyAdded) {
$('.eventTrigger').click(function() {
console.log('printing!');
});
alreadyAdded = true;
}
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="btnPreview">Add Event</button>
<button class="eventTrigger">Trigger</button>
Please note that the variable and function are encapsulated in a self-executing anonymous function and do not pollute global space.
The output of the sample can be seen in the developer console. If you remove the if-check then every click on the "Add Event" button produces an additional print statement on the "Trigger" button each time it is clicked (which is your problem). With the if, there will ever only be one event on the trigger button.
There were 2 issues which I needed to address.
The answer is to unbind the ajax event after it has checked that the request had completed and to unbind and reattach the button click trigger.
This is how I did it:
//in the scripts file
$('.btnPreview').off('click').on('click', function () {
$(document).ajaxComplete(function (e) {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
}, 300);
$(this).off(e);
});
});
I unbound the click event by adding .off('click') before the .on. this is what stopped it popping up multiple times.
The other issue was that anytime any ajax event completed (triggered by something else) that would also create the popup - to get around that, I added $(this).unbind(e); to the end of the code block which removed the ajaxComplete binding which was being triggered each time any ajax event completed.
I have a page loading content with the waypoints infinite scroller plugin.
On the success of the AJAX call and after DOM elements are added, a callback runs to re-initilize javascript functionality, like carousels, buttons and other animation.
On the first AJAX call, buttons tasked with toggling work properly. On the next AJAX call, the new DOM items work, but the previous buttons now execute toggles twice when clicked. On the third call, original items now run three times, the second items twice and the new ones once, so on and so fourth, continuing to compound as AJAX content is called.
How can I isolate the callback to not affect the previously loaded content, or, is there a way to set a global state for the JS, so that I don't need the callback each time?
Some pseudo code:
$('.infinite-container').waypoint('infinite', {
onAfterPageLoad: function() {
//Carousel options
$('.carousel-container').carousel({
options: here,
....
});
//Button Toggles
$('.button').click(function(){
var self = $(this);
$(this).siblings('.caption').animate({
height: 'toggle'
}, 200, function() {
// Callback after animate() completes.
if(self.text() == 'Hide Details'){
self.text('Show Details');
} else {
self.text('Hide Details');
}
});
});
}
});
Edit: Thanks everybody. All the answers lead me to differing but appropriate solutions. The selected was picked as it's a great collection of all the suggested issues and worth the read.
Check out this answer. I think it is the same situation you are having and has a solution:
Best way to remove an event handler in jQuery?
You are attaching a new click handler each time that block of code gets executed. The result is multiple click handlers being bound to your button. Use jQuery's unbind: http://api.jquery.com/unbind/ to remove any click handler(s) before adding a new one:
$('.infinite-container').waypoint('infinite', {
onAfterPageLoad: function() {
//Carousel options
$('.carousel-container').carousel({
options: here,
....
});
// Un-bind click handler(s)
$('.button').unbind('click');
//Button Toggles
$('.button').click(function(){
var self = $(this);
$(this).siblings('.caption').animate({
height: 'toggle'
}, 200, function() {
// Callback after animate() completes.
if(self.text() == 'Hide Details'){
self.text('Show Details');
} else {
self.text('Hide Details');
}
});
});
}
});
Try bind only once click event to button. Of course you can use on instead of live.
$('.button').live('click', function(){
var self = $(this);
$(this).siblings('.caption').animate({
height: 'toggle'
}, 200, function() {
// Callback after animate() completes.
if(self.text() == 'Hide Details'){
self.text('Show Details');
} else {
self.text('Hide Details');
}
});
});
$('.infinite-container').waypoint('infinite', {
onAfterPageLoad: function() {
//Carousel options
$('.carousel-container').carousel({
options: here,
....
});
//Button Toggles
}
});
$('.button').click(function(){
You add an event handler to every button that has the class button. When the second button is added then you add it to every ... which means button 1 and button 2. And so on.
Try
$('.button').last().click(function(){
In our application we use a general function to create jQuery dialogs which contain module-specific content. The custom dialog consists of 3 buttons (Cancel, Save, Apply). Apply does the same as Save but also closes the dialog.
Many modules are still using a custom post instead of an ajax-post. For this reason I'm looking to overwrite/redefine the buttons which are on a specific dialog.
So far I've got the buttons, but I'm unable to do something with them. Is it possible to get the buttons from a dialog (yes, I know) but apply a different function to them?
My code so far:
function OverrideDialogButtonCallbacks(sDialogInstance) {
oButtons = $( '#dialog' ).dialog( 'option', 'buttons' );
console.log(oButtons); // logs the buttons correctly
if(sDialogInstance == 'TestInstance') {
oButtons.Save = function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
}
}
}
$('#dialog').dialog({
'buttons' : {
'Save' : {
id:"btn-save", // provide the id, if you want to apply a callback based on id selector
click: function() {
//
},
},
}
});
Did you try this? to override button's callback based on the need.
No need to re-assign at all. Try this.
function OverrideDialogButtonCallbacks(dialogSelector) {
var button = $(dialogSelector + " ~ .ui-dialog-buttonpane")
.find("button:contains('Save')");
button.unbind("click").on("click", function() {
alert("save overriden!");
});
}
Call it like OverrideDialogButtonCallbacks("#dialog");
Working fiddle: http://jsfiddle.net/codovations/yzfVT/
You can get the buttons using $(..).dialog('option', 'buttons'). This returns an array of objects that you can then rewire by searching through them and adjusting the click event:
// Rewire the callback for the first button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons[0].click = function() { alert('Click rewired!'); };
See this fiddle for an example: http://jsfiddle.net/z4TTH/2/
If necessary, you can check the text of the button using button[i].text.
UPDATE:
The buttons option can be one of two forms, one is an array as described above, the other is an object where each property is the name of the button. To rewire the click event in this instance it's necessary to update the buttons option in the dialog:
// Rewire the callback for the OK button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons.Ok = function() { alert('Click rewired!'); };
$('#dialog').dialog('option', 'buttons', buttons);
See this fiddle: http://jsfiddle.net/z4TTH/3/
Can you try binding your new function code with Click event of Save?
if(sDialogInstance == 'TestInstance') {
$('#'+savebtn_id).click(function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
});
}