I intend to use the Bootstrap Popover module as a confirmation for a delete event, such that when a <button>
is clicked, instead of simply firing a function it opens a popup which let's the user confirm or dismiss the action.
It should be noted for context that the environment is a self-built, one-page ~mvc webapp, where the elements are added dynamically (I thus do not know the number of elements beforehand, nor can I hardcode the actions for each element)
In the current situation (without the popover) I do something similar to this to trigger the direct (non-conformation) action:
$view.on('click', '.deleteButton', function () {
var id = $(this).attr('data-id');
api.delete('someUrl' + id, successFunction);
}):
Where the button would have a markup similar to this:
<button class="deleteButton" data-id="2">Delete me!</button>
However, now I wish to add a confirmation step (e.g. "Are you sure you want to delete this magnificent button? (Y/N)"), and thought of using bootstrap popover.
After brainstorming a bit, what I came up with was a strategy like the following. It is not the optimal solution (the optimal solution would be to extend the popover module so that I would be able to pass in confirmationFunction and cancelFunction to the popover).
Firstly, I would have to initiate the popovers.
$view.find('.deleteButton').popover({
title: 'Are you sure?', //Example title
html: true, //Essential for the html to work as expected
selector: '.deleteButton', //Allow ajaxing in of new elements
container: '.viewName', //So that the popovers reside w/in the current view and thus can be bound to $view (a jQuery object for the view)
content: [...], //Two <button>s with a specified class, e.g. .viewName__deleteButton--popover
});
Secondly, I would bind an event to the buttons inside the popover
$view.on('click', '.viewName__deleteButton--popover', function () {
var id = ??; // Here comes the troubling part - how do I get the ID of the clicked button? How can I target the original button? If I can do that, I think it would solve everything.
api.delete('someUrl' + id, successFunction);
});
The problem that arises is how do I target the originally clicked button?
The only soultion which I can come up with, which isn't very neat at all is to do something like this:
var popoverId = $(this).parents('.popover').attr('id'); //returns popoverXXXXXX
var parentElement = $view.find('[aria-describedBy="' + popoverId + '"]');
It works, but it is a very dirty solution and does not feel 'nice' att all.
Is there any way this can be done in a neater manner? Preferably I would be able to define a general function such as $element.confirmationPopover({popoverSettings...}, confirmationFunction, declineFunction);
which could be used in multiple cases.
(PS: I couldn't figure out a concise title for this Q, advice is as always appreciated!)
I solved it by creating an extension to jQuery, such that:
$.fn.confirmationPopover = function (passedInOptions) {
var $view = this;
var defaultOptions = {
confirmationLabel: 'Yes',
container: '.' + this.attr('class'),
declineLabel: 'No',
html: true,
placement: 'left', //top | left | right | bottom
rowClasses: false
};
if (!passedInOptions.declineClass) {
passedInOptions.declineClass = passedInOptions.selector + '__popover__decline';
}
var obj = {}; //Merged options
$.extend(true, obj, defaultOptions, passedInOptions);
var popoverContent = '<div class="row ' + (obj.rowClasses ? obj.rowClasses : 'tac') + '">' +
'<button class="button button--small ' + obj.confirmationClass + '">' + obj.confirmationLabel + '</button>' +
'<button class="button button--small button--outline ' + obj.declineClass + '">' + obj.declineLabel + '</button>' +
'</div>';
if (!obj.content) {
obj.content = popoverContent;
}
/* Initiate Popover */
$view.popover(obj);
/**
* Bind confirmation Button
*/
$view.on('click', '.' + obj.confirmationClass, function () {
var popoverId = $(this).parents('.popover').attr('id');
var $this = $view.find('[aria-describedBy="' + popoverId + '"]');
obj.confirmationFunction($this);
});
/**
* Bind decline button
*/
$view.on('click', '.' + obj.declineClass, function () {
var popoverId = $(this).parents('.popover').attr('id');
var $this = $view.find('[aria-describedBy="' + popoverId + '"]');
if (typeof obj.declineFunction === 'function') {
obj.declineFunction($this);
} else {
$this.popover('hide');
}
});
return this;
};