Bootstrap popover content callback called twice on every second click - javascript

I'm trying to create a feature that will display the popover with manual click event.
My goal is to populate the popover and display newest data through ajax call after every click.
The problem I'm facing is described on the title.
For example:
1st click -> call once
2nd click -> call twice
3rd click -> call once
4th click -> call twice
...
The code look like this:
$popoverButton.popover({
container: 'body',
template: `<div></div>`,
title: 'title',
content: function () {
console.log('*'); // this called twice on every second click
let id = $(this).attr('data-id');
return initPopover(id);
},
html: true,
trigger: 'manual',
});
function initPopover(id) {
let $popover = $('<div class="popover-body"></div>');
$popover.attr({'id': 'popover-body-' + id});
let $spinner = $(`<div class="spinner"><span class="spinner-border"></span></div>`);
$popover.append($spinner);
let $sellers = $('<div class="sellers"></div>');
$popover.append($sellers);
return $popover;
}
To open the popover, I declared the click event with these functions:
$popoverButton.on('click', function () {
closePopover();
openPopover($(this));
});
closePopover() {
$popoverButton.popover('hide');
}
openPopover($targetButton) {
// hide all opened popovers
$('.popover').popover('hide');
$targetButton.popover('show');
getSellersAndAppendData();
}
I'm not sure why this happened. Please help.

Related

Plugin opens only after two clicks

I have a custom made tooltip plugin which should be opened by another plugin. But the plugin opens only after the second click and I can't figure out what the problem is.
The whole thing can be tested under. You have to click on the second input Field.
https://codepen.io/magic77/pen/XWMeqrM
$.fn.packstationFinder = function (options) {
var settings = $.extend({
event: 'click.packstationFinder'
}, options);
this.bind(settings.event, function (e) {
if ($postalCode.val() === '') {
$('#packstation-number').tooltip();
return;
}
});
return this;
};
$('[rel~=packstationFinder]').packstationFinder();
I've checked the code in Codepen. The problem here is because in packstationFinder() you call the tooltip() function for the element. But as you can see inside the tooltip() you just bind the click event on the element and not trigger it. So by current code with a first click on the element (#packstation-number) you just bind the click event and really trigger the tooltip only by the second click. You can see that it work as it should by moving out the calling of tooltip() function from packstationFinder() and call it directly as in the code below:
$.fn.packstationFinder = function (options) {
var settings = $.extend({
event: 'click.packstationFinder'
}, options);
return this;
};
$('[rel~=packstationFinder]').packstationFinder();
$('#packstation-number').tooltip();

$ionicposition only setting correct values on a modal the first time a modal is opened

I have created a custom select directive and within this directive when you tap into the options it should use $ionicposition to locate the selected option based on the HTML element ID, and then scroll to it using $ionicscroll delegate.
This is the function which locates the option, and then scrolls to it:
private scrollToOption(selectedCode: activeh.objects.ICode): void {
this.$timeout(() => {
let item: HTMLElement = document.getElementById("code-" + selectedCode.CodeID);
if(item){
var itemPosition = this.$ionicPosition.offset(angular.element(item));
this.$ionicScrollDelegate.$getByHandle('modalContent').scrollTo(0, itemPosition.top + 40, false);
}
}, 200);
}
This is where the scrollTo function is called:
private createModal(): void {
this.$ionicModal.fromTemplateUrl('app/shared/directives/selectoption/selectoption.modal.html', {
scope: this.$scope,
hardwareBackButtonClose: false
}).then((modal) => {
this.selectModal = modal;
this.selectModal.show();
if (this.selectedVal !== undefined) {
this.scrollToOption(this.selectedVal);
}
});
}
So like mentioned in the title, this code works perfectly but only the first time that the modal is opened. After the modal has been closed and opened again the $ionicposition.offset is returning values of only 0.
I found a (probably partial) solution to this, wherein instead of using .hide() to hide the modal I use .remove() to completely remove it forcing a complete rebuild.
This mimics the behaviour where it worked the first time as now every time the modal is opened is the 'first' time.

Prevent duplcate ajaxLoad event calls added with a click event

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.

Twitter Bootstrap Popover hides immediately after show

I am trying to use Bootstrap popovers for error showing. The code works well only after first click on the button. During next clicks popover is showing but disappear immediately.
Added simple helper for popover re-usage:
var popoverHelper = function (selector) {
var $element = $(selector);
$element.popover({
placement: "bottom",
trigger: 'manual'
});
return {
showPopover: function (text) {
$element.attr('data-content', text);
$element.popover('show');
},
hidePopover: function () {
$element.popover('hide');
},
destroyPopover: function () {
$element.popover('destroy');
}
};
};
Using helper:
var pHelper = popoverHelper('#postInput');
$('#postButton').click(function (e) {
e.preventDefault();
// hide open popover if open
pHelper.hidePopover();
...
// some functionality
...
// show popover if some errors
pHelper.showPopover('error occurs!!');
});
jQuery used - 2.1.1, Twitter Bootstrap - 3.1.1.
Full sample at jsfiddle.
Small note: If I call popover destroy and if I do popover re-init on show, all works well.
But I think it is not optimal.
Jsfiddle sample.
Check this Demo Fiddle
A better solution would be to hide popover on user action on the error field.
$('input').focus(function(){
pHelper.hidePopover();
});

Redefining a jQuery dialog button

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.
});
}

Categories