How do I destroy all instances of Bootstrap Popover? - javascript

I have a single page app using Backbone, and whenever I over over something and then click the "back" button, the popover forever stays.
I want to destroy all instances of popover when a new instance is loaded.

Finding the popovers that are created through the data API is not difficult and has been covered in other answers like those of David Mulder and Amir Popovich. You just do:
$("[data-toggle='popover']").popover('hide');
Or you can use destroy if you need to or prefer to.
The challenge is to handle those popovers that are created dynamically.
Marking the Elements with Popovers
I would implement something like this. I'd override the default popover method and I'd try to perform this override as early as possible so that everything that needs a popover uses my override. What it does is just mark elements that use a popover with a class. Bootstrap does not mark them itself:
// Override popover so as to mark everything that uses a popover.
var old_popover = $.fn.popover;
function my_popover() {
this.addClass('marked-as-having-a-popover');
return old_popover.apply(this, arguments);
}
$.fn.popover = my_popover;
Then to clear everything before the unloading, I'd put in the code that detects the unloading the following:
$(".marked-as-having-a-popover").popover('hide');
Or it could use destroy rather than hide if testing shows that it works better for your use-case.
Now, the method above will work if the override happens early enough and you do not have a page where multiple jQueries are loaded. (Yep, this is possible.) I use something similar to deal with tooltips in one of my applications so I know the principle is sound. It so happens that in my app, all tooltips are created by my code so there is no risk of missing something.
Finding All Elements with Popovers, Even Unmarked
If you are in a situation where a popover can be created without being marked (I call this an "escapee"), then you need to query the whole DOM and find which elements have popovers. There is no shortcut here. You cannot rely on attributes like data-content because popovers can be created wholly dynamically (i.e. without any of the data- attributes). Also, all kinds of elements can get popovers, so you cannot reliably assume that only button elements will have a popover. The only surefire way to find everything that needs handling is to look at each element in the DOM and check whether it has a popover:
// Obviously this is quite expensive but in a situation where there *can* be escapees
// then you have to check all elements to see if they have a popover.
$("*").each(function () {
// Bootstrap sets a data field with key `bs.popover` on elements that have a popover.
// Note that there is no corresponding **HTML attribute** on the elements so we cannot
// perform a search by attribute.
var popover = $.data(this, "bs.popover");
if (popover)
$(this).popover('hide');
});
Again, destroy could be used rather than hide.
Proof of Concept
Here is a fiddle that illustrates the entire thing:
"Add a Dynamic Popover" simulates code that would add a popover when the override is in effect.
"Add an Escapee" simulates code that would add a popover and somehow manage to use the original Bootstrap code.
"Clear Marked" clears only the marked popovers.
"Clear All" clears every single popover marked or not.

try with this:
$('YOUR_ELEMENT_SELECTOR').popover('dispose');
reference url: https://getbootstrap.com/docs/4.1/components/popovers/

Its very simple, just you have to call one function popover() with argument "destroy" to destroy the popover. It will destroy all popovers which is created by $("[data-toggle=popover]").popover();
you can check documentation for more options and arguments of popover().
I suggest you to destroy popovers with having specific class name instead of using following code.
$("[data-toggle='popover']").popover('destroy');
The above code will destroy all popovers in the page. So instead of this, use class selector.
$(".YourClassName").popover('destroy');

If you have problems and need to remove all for sure:
$('.popover').remove();
will help (Popover automatic add this class, even for dynamicly created objects). It destroys all the popover DOM-Object incl. callbacks, etc.
But thats the rough way. Typically I displose all by popover class (clean way) and to be sure I do a hard clean up after. Works for me fine!
$('.popover').popover('dispose');
$('.popover').remove();
If you like to remove all execpt one, use a filter() with :not-Selector
$('.popover').filter(':not(#yourID)').popover('dispose');
$('.popover').filter(':not(#yourID)').remove();
popover adds also a id with a random number
#popoverxxxxx where xxxxx is a five digit number.
this helps sometimes to compare popovers. Of cause this could also be used to identify the popovers.

Something generic like this (assuming you're using data-bindings) should do the trick:
$('[data-toggle="popover"]').popover('hide')
or the more extreme call
$('[data-toggle="popover"]').popover('destroy')
though I doubt that would make sense often. Still to address the specific bug you're encountering you should create a minimal test case so that that bug itself can be addressed.
Oh and if you specifically want to check for open popovers you can use .data("bs.popover").$tip.parent().length (which is a bit of an hack), for example:
$('[data-toggle="popover"]:eq(0)').data("bs.popover").$tip.parent().length == 1

You can hide all popovers by using this:
$("[data-toggle='popover']").popover('hide');
You can destroy all popovers by using this:
$("[data-toggle='popover']").popover('destroy');
The difference between hide and destory is that when you hide a popover you do not need to reactive it, but when you destroy it you do.
Check out my JSFIDDLE and then:
Click on all popovers and then click hide. After clicking hide you can click on the popovers again.
Click on all popovers and then click destroy. After clicking destroy try clicking on the popovers again and see that nothing will happen since they are destroyed. In order to make them functional again, you will need to click on reactive and then try.

Popovers must be initialized manually, so you know exactly what you have to destroy because you did initialize it.
You should just call the destroy function with the same selector.
Or maybe I am missing something ?

Related

Two way binding for checkbox inside an accordion not workiing

In my angular 1.5 html5 application, I have an accordion group and inside it's body I have Couple of check-boxes. Since direct scope binding will not work inside accordion, I'm using ng-click event as attached.
This works as expected, I'm getting click events with correct value.
I have another reset button on screen, when user clicks this button I have to reset all filters including the checkbox inside the accordion. Even after I reset the model value to false, checkbox still shows as checked. I know this is because the binding is not there.
How can I update the checkbox value from javascript. Is there any angular way. I'm not a big fan of JQuery.
Regards,
Nixon
We faced a similar issue with the data bindings while using accordian.
Instead of using directly model variable, we created an object of it.
For eg, instead of using $scope.includeLocalParties, try using $scope.checkbox.includeLocalParties.
Also initialize it in your controller. Something like this:
$scope.checkbox = { includeLocalParties : false};
Hope it helps!

React render, change radio button programmatically

I was creating a Dropdown component for React. Inside the dropdown, I have a form of radio group buttons.
<DropdownButton />
<DropdownForm />
In the DropdownButton, I have an state to know if it is open or not. Depends on that, DropdownForm it's hidden or not (using display: none).
The use case is: User selects a radio button, click apply and something happen. However, if user selects some radio button, and mouse out the dropdown (without clicking the apply button), the one that is selected should be the one that I get from the store.
Something like:
render: function () {
...
if(store.getSomeParam() != this.state.someParam && !this.props.isOpen){
someParam = store.getSomeParam()
}
Then the radio buttons are like:
<input checked={someParam == "something"} ... />
It doesn't really work. It re-renders but it doesn't change the button that is checked. I also tried with refs:
this.refs.myInput.getDOMNode().checked = true
But still nothing. Is this a correct behaviour?
The only solution I found so far is not using a css hiding class (display: none). So what I do is that the DropdownButton renders the DropdownForm depending on if it's open or not (so if you close it, you are forcing DropdownForm to unmount). Then when opening again, it is taking the values from the store (getInitialState) and it shows the correct radio button selected. But, I am not sure if this is the best solution and if there is any drawback in unmounting the component instead of just css hiding it.
This probably has nothing to do with React at all.
Most browsers don't validate the value of the checked attribute, but merely if it is there or not: http://jsfiddle.net/7jzm7gvw/
Just set the checked attribute to either true or null:
<input checked={someParam == "something" ? true: null} ... />
TL;DR: You must use the componentDidMount lifecycle method, not render, to work with the rendered dom nodes directly.
I was struggling with this as well, and after doing some online research I figured I might as well look into it for myself. Here's what I came up with:
Use the componentDidMount lifecycle method and update whatever you need to in there. Here's a Pen I used to prototype this, and I think it looks okay: http://codepen.io/gholts/pen/GpWzdb
You could drop this in pretty easily to what your'e working on by just putting a componentDidMount method on your object and doing it there. I used document.getElementById but you could definitely use jQuery or whatever else you wanted in there, as once the component has mounted it's available to DOM selectors.
I'm using this now to update 20 radio button groups (so it has to check a prop for three different states and update accordingly) and it loads instantly.
Hope it helps! I used the ES6 class syntax in my Pen, you should check it out if you have some time to refactor :) It's fun.
EDIT: So I figured it out, I'm a dummy. You don't need to do the whole document.getElementById business that I was doing. Just use your this.refs.whichever.getDOMNode().checked = true and it'll work, so long as you do it in componentDidMount. It works there because there is an actual DOM element on the page at that point.

Add jquery datepicker dynamically after page load

Upon a button click, I have some jquery that will add some html to the 'body' element. In that html, I have a datepicker input field which refuses to appear when it should.
I use the ui-datepicker in several other spots in my app, and it works perfectly.
I have tried calling the datepicker when the document loads:
jQuery ->
$('.my-datepicker-class').each ->
input = $(this)
input.datepicker()
and after the click event which adds the new html to the page:
$('.my-button').click ->
$('body').ipadoverlay
titleStyle: false
contentWidth: 500
topSpc: true
content: $('#popup-for-' + thing_id).html()
$('.my-datepicker-class').each ->
input = $(this)
input.datepicker()
But the picker refuses to show up. My guess is that it has to do with when jquery builds and places the datepicker, but I really don't know.
Let me know if you have any ideas or could use more information.
UPDATE
I changed the way I call datepicker() so that it only applies to the element I want the datepicker attached to.
$('.ipadoverlay .date-picker').datepicker()
This eliminates the first issue with the .each =>.
Now it silently fails. No error or warning. The datepicker simply does not show up.
I am going to begin digging into jquery.ui.datepicker.js to see if I can figure out whats going on, but if you have any ideas why the datepicker fails to response, please let me know.
UPDATE 2
Ok, I got a step further. The class 'hasDatepicker' was already attached to the element I want add the datepicker to (which means $('.date-picker').datepicker() was being called somewhere else, while the element was hidden and unused), but the datepicker didn't work. I fixed this by removing the class from my element, and calling .datepicker() again
$('.ipadoverlay .date-picker').removeClass('hasDatepicker')
$('.ipadoverlay .date-picker').datepicker()
Now the datepicker shows up on click, but selecting a date doesn't do anything... Help would be much appreciated
You need to use the fat arrow. Your use of 'this' loses its context.
jQuery ->
$('.my-datepicker-class').each => # <-- Fat arrow
input = $(this)
input.datepicker()
I'd explain, but coffeescript.org does a better job than I ever could.

jQuery UI Multiselect widget clear all check boxes

Hopefully a quick one...
I need to fire the uncheckAll event in the click event of a separate button on my page, I have tried the following:
$('.masterProviderOrgsListBox').multiselect().uncheckAll();
but this isnt a recognised method. I basically want to fire the same method that is fired when you click the "Uncheck All" box in the header.
I was previously doing this:
$('.masterProviderOrgsListBox option:selected').removeAttr("selected");
but this removes the selections on the actual multiselect rather than the jQuery UI widget.
Couldnt find anything in the documentation, any ideas?
Methods
After an instance has been initialized, interact with it by calling
any of these methods:
// example: $("#multiselect").multiselect("method_name");
...which can be found in the widgets documentation under Methods
$("#multiselect").multiselect("uncheckAll");
1) first, you need to set default value of the control.
jQuery('#multiselect').val("");
2) Then, execute below code to reset the control.
jQuery('#multiselect').multiselect("refresh");
$("#multiselectoption:selected").removeAttr("selected");
$("#multiselect").multiselect('refresh');
refresh should be call after clearing the drop down.

How to fix dynamic added elements aren't dragging or sorting jquery

I have one button, and when i click it it adds elements that are with same class, for example my class is image_class, the default added elements are being dragged, but when i add new element with the class i can't drag it or sort it.How can i fix that ?I want when dynamically added element shows up to be dragged or sorted .There is no problem with the default ones.
I'm using jquery ui
Okay, here's one way of doing it (and since I have no idea what your button code does...)
http://jsfiddle.net/TrowthePlow/qZz5j/
By default, events are added at runtime and not bound to elements created after the point of binding, even when they have the same selector.
To make sure that events are bound to items with the same selector dynamically, make sure you use the jQuery live method to bind your events.
$('.clickme').live('click', function() {
// Live handler called.
});

Categories

Resources