AngularJS Bootstrap Popover custom trigger - javascript

In my WebApp I want to show a customized popover that will be triggered when a variable in my controller is set. To achieve this I've created a custom trigger event and set it with $tooltipProvider.setTriggers({"showChat": "hideChat"}]
Here is a plnkr.co of my code that does not working.
I also checked other solutions here on StackOverflow (like AngularJS Bootstrap Tooltip - trigger on event or Good way to dynamically open / close a popover (or tooltip) using angular, based on expression?) that seem to work, but I can't figure out where my code is wrong.
I assume it's just a little thing (like always.. :-) )

Angular-bootstrap seems to use addEventListener to subscribe to this event, which means you cannot trigger it with .trigger(), what you'll need is dispatchEvent:
if(scope.showPopover) {
console.log('trigger showChat')
element.get(0).dispatchEvent(new Event("showChat"));
} else {
console.log('trigger hideChat')
element.get(0).dispatchEvent(new Event("hideChat"));
}
See in this fixed plunker.
Btw: unless you do something more complicated in your app, you can simply use popover-is-open="showPopover" to trigger the popover, like in this plunker

Related

Why only single change event is working on select element in jQuery?

I need to change behavior of jQuery library (date range picker), it have code like this:
box.find('.month').off("change").change(function(evt) {
dateChanged($(this));
});
box.find('.year').off("change").change(function(evt) {
dateChanged($(this));
});
Those are two select elements. It don't return false and functions inside handler don't access the event. But for some reason my events that use delegation doesn't work. They are ignored.
$picker.on('change', 'select', function() {
console.log('CHANGE');
});
The console log is not executing, but if I remove previous lines from the library, my event delegation code works fine.
NOTE: $picker is object in my code that is parent of box element. But I also have event added on $(document) that is also not working.
First time I see something like this. Adding event directly to element, prevents event propagation. Can someone explain what is happening here? Is this documented anywhere?
This happens in Firefox and Chrome.
If someone need simple example, I can create one. But thought that this is self explanatory.
EDIT: I've created a simple reproduction and it works fine. I have complex application with a lot of files (R Shiny Application), but I don't see any change events in dev tools. Are there any way of making the event not propagate? Maybe using event capturing. What should I search for in order to find the code that is preventing the events from propagating?

How can I trigger an angularjs event handler from another handler?

I'm using AngularJS 1.3.0-beta.2, jQuery 2.1.0, Angular UI 0.11, and my custom version of Angular UI's Tooltip widget, and I want buttons within my tooltip to close the tooltip when clicked.
Plunkr
The key part is at crud_tooltip.js:372:
scope.closePopup = function() {
var trigger = element.prev();
if (scope.mode === 'timeout') {
$timeout(function() {
trigger.triggerHandler('click');
});
}
else {
trigger.triggerHandler('click');
}
};
The version using $timeout works, but there's a noticeable delay between clicking the button and seeing the popup close.
The version not using $timeout gives an error: [$rootScope:inprog] $apply already in progress. It then closes the popup anyway... I'm not sure why.
How can I modify closePopup (or the ng-click that calls it) to make the tooltip close immediately when the user clicks the button within the tooltip?
Note: I adapted my custom_tooltip.js code from Angular UI's tooltip code, using this Plunker as a guideline. I've also tried directly changing the tt_isOpen value and defining a new crudtooltip-toggle attribute, both with very limited success.
Maybe I'm missing the point, but your code seems incredibly complicated and convoluted for such simply functionality. In any case, the delay is actually due to a $timeout which is waiting for some animation to finish. The timeout is triggered because scope.tt_animation evaluates to truthy. Simply changing the timeout to 0 at line 258 of crud_tooltip.js fixes the issue. See this plunk
Here's the problem area:
if ( scope.tt_animation ) {
transitionTimeout = $timeout(removeTooltip, 500);
} else {
removeTooltip();
}
You're looking at the wrong thing.
That delay is coming from elsewhere and is definitely not bound to the $timeout, but also to the notimeout method (ignoring the error, of course, but that can be easily fixed by checking for $scope.$$phase first).
Also, when you click the original links, both of them, the closing delay is there.
So, in 4 cases you get the same delay, which means it's something in the code. I'll give it another look and update the answer if I find what's causing it.

How do you think about respective callback for bootstrap modal triggers?

On bootstrap modals, we know that we can bind events for triggers like show or hide using show, shown, hide, hidden, but this event binding only works for general case. What I want is 'specific case' such as:
$("#myModal").modal("show", function(e){
alert("This pops-up after #myModal is shown properly.");
});
or maybe using dictionaries for more options.
Anyway, I want to call some functions as callback after these modal triggers are done.
I do know that there can be alternative implementations, like using setTimeout to wait until the modal is completely shown or hidden, or just unbind the event inside the callback function so the event handler works only for once. Either way, it's not very convenient and ugly.
Can this feature be feasible feature request for bootstrap?
Also, I'm not very satisfied that to change modal's property after its init, I have to change it by directly managing $("#myModal").data("bs.modal").options.
Again, I'm asking about particular situation. I don't want to make callback function called for every show, shown, hide or what ever. Just for specific situation where the modal is triggered manually via javascript.
Here is an example:
Let's say that there are #myModal, and #btn-a, #btn-b.
$(document).ready(function(){
$("#myModal").on("shown.bs.modal", function(e){
console.log("myModal shown.");
})
$("#btn-a").click(function(e){
$("#myModal").modal("show");
});
$("#btn-b").click(function(e){
// There is no such thing like below. It's just pseudo code.
$("#myModal").modal("show", function(e2){
console("myModal shown by b.");
});
});
}
Then if #btn-a is clicked,
myModal shown.
will appear while if #btn-a is clicked,
myModal shown.
myModal shown by b.
will appear.
Again and again, I'm actually not asking how to make it. I already made what I want. What I'm asking is, will this feature be feasible feature request for bootstrap.
Check out the section titled Events here:
http://getbootstrap.com/javascript/#modals
Hopefully, it will give you all the information you need
You can use shown events to detect when the modal has been made visible on the screen:
$('#myModal').on('shown.bs.modal', function (e) {
alert("This pops-up after #myModal is shown properly.");
})
You can check for more information in the events section of modal here.

Wrote alternative to jQuery Accordion, it spazzed. Why?

I wrote an alternative to the jQuery Accordion, as that didn't offer multiple open section support (any idea why they opted to not include support for that? What's the history there?). I did some research on StackOverflow, as well on Google to see what other options others came up. I needed something that could be used on the fly on multiple elements.
After seeing several solutions and experimenting with them, in the end, I wrote my own version (based on Kevin's solution from http://forum.jquery.com/topic/accordion-multiple-sections-open-at-once , but heavily modified).
jsFiddle can be found here: http://jsfiddle.net/3jacu/1/
Inline Code:
$(document).ready(function(){
$.fn.togglepanels = function(){
return this.each(function(){
h4handler = $(this).find("h4");
$(h4handler).prepend('<div class="accordionarrow">▼</div>');
$(h4handler).click(function() {
$(h4handler).toggle(
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('►');
$(barclicked).next().slideUp('slow');
window.console && console.log('Closed.');
return false;
},
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('▼');
$(barclicked).next().slideDown('slow');
window.console && console.log('Open.');
return false;
}
);
});
});
};
$("#grouplist").togglepanels(); }
Oddly, the accordion arrow at the right side stopped working once I pasted it in jsFiddle, while it works in my local copy.
In any case, the issue is that toggling isn't working as expected, and when it does, it fires duplicate toggle events which result in it closing, opening, then ultimately closing the section and it won't open from that point on (it toggles open then closes back). That's assuming it works! At first, it won't work as it doesn't respond. I think there's a logic error somewhere I'm missing.
From what I wrote/see in the code, it searches the given handle for the corresponding tag (in this case, h4), pops the handle into a variable. It then adds the arrow to the h4 tag while applying the accordionarrow class (which floats it to the right). It then adds a click event to it, which will toggle (using jQuery's toggle function) between two functions when h4 is clicked.
I suspect the problem here is that I may be mistakenly assuming jQuery's toggle function will work fine for toggling between two functions, that I'll have to implement my own toggle code. Correct me if I'm wrong though!
I'm trying to write the code so it'll be as efficient as possible, so feedback on that also would be appreciated.
Thanks in advance for your time, assistance, and consideration!
You have the toggle binding (which is deprecated by the way) inside of the click binding, so a new event handler is getting attached every time you click the header.
As a random aside you should also fire events within the plugin (where you have the console lines would make sense) so that external code can react to state changes.
I believe your issue is the $(h4handler).click(function() { you have wrapped around the toggle listener. Essentially what this was doing was making so every click of the tab was adding the toggle listener, which was then also firing an event. Removing the click listener will have the behaviour you expect.
You forgot to paste the trailing characters ); to close the function call to jQuery function ready. Fixed: http://jsfiddle.net/LeZuse/3jacu/2/
UPDATE: I've just realised I did not really answer your question.
You are duplicating the .toggle functionality with binding another .click handler.
The doc about .toggle says:
Description: Bind two or more handlers to the matched elements, to be executed on alternate clicks.
Which means the click event is already built in.
NOTE: You should use local variables instead of global, so your plugin won't pollute the window object. Use the var keyword for this:
var h4handler = $(this).find("h4");

Locating an element in a 'Facebox' box

Heres my link:
http://tinyurl.com/6j727e
If you click on the link in test.php, it opens in a modal box which is using the jquery 'facebox' script.
I'm trying to act upon a click event in this box, and if you view source of test.php you'll see where I'm trying to loacte the link within the modal box.
$('#facebox .hero-link').click(alert('click!'));
However, it doesn't detect a click and oddly enough the click event runs when the page loads.
The close button DOES however have a click event built in that closes the box, and I suspect my home-grown click event is being prevented somehow, but I can't figure it out.
Can anyone help? Typically its the very last part of a project and its holding me up, as is always the way ;)
First, the reason you're getting the alert on document load is because the #click method takes a function as an argument. Instead, you passed it the return value of alert, which immediately shows the alert dialog and returns null.
The reason the event binding isn't working is because at the time of document load, #facebox .hero-link does not yet exist. I think you have two options that will help you fix this.
Option 1) Bind the click event only after the facebox is revealed. Something like:
$(document).bind('reveal.facebox', function() {
$('#facebox .hero-link').click(function() { alert('click!'); });
});
Option 2) Look into using the jQuery Live Query Plugin
Live Query utilizes the power of jQuery selectors by binding events or firing callbacks for matched elements auto-magically, even after the page has been loaded and the DOM updated.
jQuery Live Query will automatically bind the click event when it recognizes that Facebox modified the DOM. You should then only need to write this:
$('#facebox .hero-link').click(function() { alert('click!'); });
Alternatively use event delegation
This basically hooks events to containers rather than every element and queries the event.target in the container event.
It has multiple benefits in that you reduce the code noise (no need to rebind) it also is easier on browser memory (less events bound in the dom)
Quick example here
jQuery plugin for easy event delegation
P.S event delegation is pencilled to be in the next release (1.3) coming very soon.

Categories

Resources