SAPUI5: Handle click events properly - javascript

I am using the SAPUI5 control GenericTile and added both headerImage and click event. When this icon is clicked, the event handler of the tile is triggered first so that I am not able to react on the icon click itself (which should perform another action of course).
var oGenericTile = new sap.suite.ui.commons.GenericTile({
frameType: "TwoByOne",
header: "My HEader",
headerImage: "sap-icon://settings",
tileContent: oTileContent
});
oGenericTile._oImage.attachPress(function(oEvent) {
sap.m.MessageToast.show("Icon has been pressed");
oEvent.cancelBubble();
oEvent.preventDefault();
});
oGenericTile.attachPress(function() {
sap.m.MessageToast.show("I am always triggered first!!! :-(");
});`
Any idea how I can avoid this?

you could e.g. also cancel the event on the tile manually in order to avoid this behavior... you'd just need to track whether the icon has been pressed, see a simplified example on JSBin:
http://jsbin.com/daqifomoge/3/edit
Extending existing controls and overriding methods always bears the potential to break things when the original control gets an update from the developers...
Maybe there's a more elegant way to do it, though.
Best,
Christiane

Related

Google Maps API event listener priority

I have a map which has a google.maps.event.addListener set on the map object for click events to place a marker on the map. Now I want to add a context menu to the markers, so am creating a custom overlay in the floatPane. Again google.maps.event.addListener is used to add a rightclick event to each marker to position and display the menu.
Once the menu is displayed I want it to be cleared by either a menu item being selected, escape being pressed, or a click on the map.
The menu has a div for each items using jQuery .on to attach a click handler to them, whilst when the menu is displayed a keydown handler is attached to the document using .on to check for escape being pressed. These work as desired but I am unable to find a satisfactory solution to detecting a click on the map.
If I use google.maps.event.addListener on the map object to cancel the menu it works, but also registers with the listener to add a marker and event.stopPropagation() does not affect this. i.e. Cancelling the menu also adds a marker. I believe the Google API triggers the handlers in the order they were added with no way to change the priority.
I have also tried using a jQuery .on handler on the div to which the map is attached. But if I use click or mouseup event it is triggered by the right click which adds the menu. i.e. The menu flashes on screen as it appears but immediately closes. A mousedown event avoids this problem, but obviously still triggers the Google API handler to add a marker. It also registers the click to drag the map to scroll it, which the Google API does not and would be the preferred behaviour.
So it seems to me there are only two solutions to this problem.
One would be to cancel any handlers on the map when the menu is displayed, then re-add them once it closes. This seems unnecessarily excessive though.
The other is to make wrap the content of the handlers in a conditional statement to detect whether the menu is open. This could be either by using a global variable as a flag or adding a status property to the menu's object.
But this would make the code less reusable and go against the point of having separate event handlers. I may as well just put the code to close the menu in the original handler too.
Is there anything I am missing? It does not seem to be too obscure a thing to want to do but the inability to set the priority of handlers in the Google API means either having to code the handlers around each other.
For what it's worth, I believe your first approach (adding and removing handlers) is the "cleanest" (or most elegant?) approach.
If you think of the handlers as only having use/meaning when the menu is present, from a conceptual perspective, there's no need for them to exist when the menu is not visible.
If you bundle the event-wiring into the same function(s) or method(s) that handle the menu, then it becomes a self-contained, re-usable element that doesn't leave any "garbage" behind.
Since I don't have your code in front of you, here's some pseudocode:
function displayMenu() {
$menu.show()
.on('click', function() { /* etc */ });
}
function hideMenu() {
$menu.hide()
.off() // remove ALL event handlers
}
Or, even better, encapsulate it in an object:
var menu = {
show: function() {
// ...
}
hide: function() {
// ...
}
};
Or you could use a jQuery function too (though I generally eschew jQuery when I'm working with a map API, just to keep the number of dependencies low).

Adding Overlay in JavaScript

I am using jsplumb to create a flow-chat. Once the flow-chart creation is over and acknowledged by the user I want to make the created structure un-editable.
For this, have added an overly to the parent that holds the flow-chart, but the mouse clicks are still happening on the flow-chart.
How to - not allow the mouse clicks happen on these components after adding the overlay.
Thank you
Add a handler to the overlay that swallows all click events:
document.getElementById('yourOverlayID').onclick = function () {
return false;
};
Keep in mind that anyone can simply remove the overlay via the console and continue modifying the chart if they desire. You may want to look at the jsplump API for a way to do this instead, such as unbind().

Javascript override user mouse event

I have a bit of javascript that will allow the user to move stuff around using the mouse, so the user can click and drag things around, which is working all fine, but what I am struggling with is being able to override the users click event.
So what I am trying to do is, if the user moves the item to a certain position I want to stop the click and hold event, this would mean the user would have to the go an reselect the item again and click and drag again.
Can you override the users mouse action from javascript? It seems simple but I am unable to find a way in my javascript to stop the mousehold event
You can try to override onmousedown to store the mouse coordinates and fire the "real click" event on onmouseup if the mouse position did not changed (or if the change is less than say 5 pixels).
document.getElementById('myElement').addEventListener('click', function(e) {
e.preventDefault(); // here is your override
doSomethingElse(); // or not
});
Same thing for IE but use attachEvent instead of addEventListener
Perhaps instead of blocking events, you can put some logic inside your onclick handler to check for this condition?
For example, maybe a couple of properties to maintain state. You could call one itemSelected, which must be true in order for the the item to move. Then if you set itemSelected to false, another click will be necessary to toggle it again.

Can jQuery click events be unbound or reset?

I've discovered a resource leak on a webpage I'm working on.
This webpage has two textfields, that upon click show a modal dialog, perform a data request to the backend, and then present that information in a table that the user can select an entry from for use in the textbox they originally clicked.
I'm binding the click events to the textboxes like so:
var $field = $('#one-of-the-text-fields');
$field.click(function () {
App.DialogClass.show();
App.DialogClass.PopulateTable();
App.DialogClass.GotoPageButtonAction(actionArgs); // Offender!
});
...Which calls...
App.DialogClass = (function($) {
var pub {},
$gotoPage = $('#pageNumberNavigationField'),
$gotoPageButton = $('#pageNumberNavigationButton');
// ...SNIP unimportant other details...
pub.GotoPageButtonAction = function (args) {
$gotoPageButton.click(function () {
var pageNumber = $gotoPage.val();
pub.PopulateTable(args); // Breakpoint inserted here...
});
};
return pub;
})(jQuery);
I noticed the leak because when I ran through using Chrome's JavaScript debugger, I'm always having one extra breakpoint hit every time I click a different button (e.g. the first time I click field A, the breakpoint is hit twice. When I hit field B after that, the break point is hit three times. If I click A after that, the breakpoint is hit four times. Extrapolate as necessary.)
Nowhere in my code am I doing anything about an existing click event for a given field. I suspect my leak stems from the fact that the events are not getting cleaned up. That being said, I am also not terribly familiar with JavaScript/jQuery. What are some techniques for removing click events from a control?
Sure. Just unbind them:
$field.unbind('click');
However, bear in mind that this will remove all event handlers for click, not just yours. For safety, you should use namespaces when binding handlers:
$field.bind('click.mynamespace', function(){
// do something
});
Then,
$field.unbind('click.mynamespace');
So, then, only your handler will be removed.
If you have used .bind() to bind them .unbind() removes the events
If you have used .on() to bind them .off() removes the events
JQuery offers the unbind function to unbind event listeners.
Note that you may also do it in vanilla JS using removeEventListener.
But instead of unbinding, you probably should not bind each time in GotoPageButtonAction : once is enough.

JavaScript/jQuery: global variable inexplicably being reset, causing menu contraction issue

http://jsfiddle.net/VhjR7/1/
When you click the my lists menu once, it expands, but if you click it again, it doesn't contract.
The problem is listsExpanded being inexplicably reset to false after it is set properly to true by listsExpand(). This causes the check within $('#mid-wrap').delegate() to inappropriately call listsExpand() again, instead of listsContract() like it should.
I can't figure out where or why this reset is occurring, but I think it has something to do with the sticky light blue menu functionality. Before I started removing and replacing this blue bar after scrolling to fix an IE7 bug, there was no issue with expansion/contraction of the little white menu.
Any ideas on what's causing this?
The issue is that the hover event does not support both function arguments (in and out) when used with .delegate(). You will need to use mouseenter and mouseleave instead of hover.
Change to this:
$('#mid-wrap').delegate('#lists', 'mouseenter', function() {
listsMouseIn = true;
}).delegate('#lists', 'mouseleave', function() {
listsMouseIn = false;
});
FYI, if these HTML objects are static, not added dynamically, you could significantly simplify your code by using direct event handlers on that actual objects rather than .delegate and just stopPropagation() when you've processed the click. Then, you'd see the click first in the object and wouldn't be processing the same click multiple times causing you to need all these global flags to keep track of state.
You could also just use the visibility of the object as your detection mechanism for whether the menu is open/closed too rather than a global variable.
The first part of your hover handler (with listsMouseIn = true;) never actually fires so whenever you click, your $('body').mouseUp() handler assumes that you are not hovering the lists button, and therefore hides the menu just for the $('#mid-wrap').delegate(...) handler to show it again milliseconds later.
Replacing
$('#mid-wrap').delegate('ul#lists', 'hover', funcIn, funcOut);
with
$('#mid-wrap').delegate('ul#lists', 'mouseover', funcIn).
delegate('ul#lists', 'mouseout', funcOut);
seems to do the trick.

Categories

Resources