backbone.js click and blur events - events

I'm having some trouble with blur and click events in backbone. I have a view (code below) that creates a little search entry div with a button. I pop open this div and put focus on the entry field. If someone clicks off (blur) I notify a parent view to close this one. If they click on the button I'll initiate a search.
The blur behavior works fine, however when I click on the button I also get a blur event and can't get the click event. Have I got this structured right?
BTW, some other posts have suggested things like adding timers to the div in case its being closed before the click event fires. I can comment out the close completely and still only get the blur event. Do these only fire one at a time on some kind of first-com-first-served basis?
PB_SearchEntryView = Backbone.View.extend({
template: _.template("<div id='searchEntry' class='searchEntry'><input id='part'></input><button id='findit'>Search</button></div>"),
events: {
"click button": "find",
"blur #part": "close"
},
initialize: function(args) {
this.dad = args.dad;
},
render: function(){
$(this.el).html(this.template());
return this;
},
close: function(event){ this.dad.close(); },
find: function() {
alert("Find!");
}
});

I am not sure what the problem was, but here is the jsbin code.

Related

Prevent the delete key from working on Kendo ListBox

I'm using Kendo on Razor pages using MVVM. On a particular page I have a pair of ListBoxes. I want to stop users from deleting items from the boxes with the delete key.
If I trap and prevent the remove event from working, that solves the problem, except you can't then use the toolbox or drag and drop to transfer items from one box to the other (edit: because move is a combination of change & remove events).
This is how I was stopping the remove event...
<select style="min-width: 600px" id="listboxImports" data-role="listbox"
data-text-field="title"
data-value-field="id"
data-selectable="multiple"
data-toolbar='{tools: ["transferTo", "transferFrom"]}'
data-connect-with="listboxSelected"
data-draggable="true"
data-template="template"
data-drop-sources="['listboxSelected']"
data-bind="source: imports, events: {remove: viewmodel.events.remove}"></select>
<script>
var viewmodel = new kendo.observable({
events: {
remove: function(e) {
e.preventDefault();
},
//
}
});
<script/>
I've also tried to trap the delete key's keydown event, but I cannot identify which of the many elements rendered when the ListBox is rendered is actually handling the event.
Can anyone tell me how I can have my cake and eat it please?
Took ma a while, inspired by the same question for kendo's Multiselect: https://docs.telerik.com/kendo-ui/controls/editors/multiselect/how-to/selection/prevent-removing-selected-items-on-backspace:
$("#listBoxA").parent().get(0).addEventListener('keydown', function(e) {
if (e.keyCode == kendo.keys.DELETE) {
e.stopImmediatePropagation();
e.preventDefault();
}
}, true)
Full dojo: https://dojo.telerik.com/aFaCIkez/3
The _keyDown handler is attached to the <ul> element. My solution attaches a new handler to its parent, using event capturing, so that handler will be executed before Kendo's, and thus stopping the event's propagation if the pressed key was delete.
Alternatively, a possible workaround is to set navigatable to false, but you obviously lose all keyboard functionality. Example: https://dojo.telerik.com/IHICAziR

Prevent hiding for cytoscape qtip

I'm using the Cytoscape Qtip extension to display qtips when you click nodes.
Usually you can prevent qtips from hiding when with the hide: false option. When this is used, you can still hide the qtips if it has a button.
However, when using cytoscape, this appears to not work. When clicking else where, a hide event will be triggered.
cy.elements().qtip({
content: function(event, api){
api.set('content.button', true);
return 'Example qTip on ele ' + this.id();
},
position: {
my: 'top center',
at: 'bottom center'
},
hide: false,
style: {
classes: 'qtip-bootstrap',
tip: {
width: 16,
height: 8
}
}
events: {
hide: function(event, api){
console.log(event);
}
}
});
I can prevent the hide event from following through with event.preventDefault(), but this will also stop the the close button from hiding the event, which is a bit messy.
Any idea while it's behaving this way?
Here's the quick and dirty to make this work (closes on button close only) if you need it:
events:{
hide: function(event, api){
if(event.originalEvent.target.parentElement.parentElement.id != this[0].id){
event.preventDefault();
}
}
Explanation:
Any mouse clicks will trigger a hide event all visible qtips.
We look at target of that mouse click (event.originalEvent.target.parentElement.parentElement.id) to see it close box of the qtip that is currently try to close. If it's not then we preventDefault().
This is potentially pretty bed performance wise, because it run these preventDefault() for every open qtip on every mouse click.
Remember that because this wraps Qtip on non-DOM elements, bindings to Cytoscape graph elements must be made. These bindings are outside of the DOM and outside of Qtip's control (for example, the hide case).
Did you try setting the hide event to the empty string ""?
Cleanest solution I've found is to give a garbage event for the hide event.
Using null, false or "" all don't seem to work.
hide: {
event: "asdf" //garbage event to allow hiding on close button click only
},

How to add icon to a connection in jsplumb?

I was trying to figure out how to add an icon to connection. This is what I intend to do:
When a user hovers over a connection, a trash icon should appear above/below the connection
When the user clicks on it, it should delete that connection
Right now, to add the trash icon to the connection, I use the following code to add a connectorOverlay.
["Custom",{create:function(component){
return $('<img class="delete-connection" style="display:block;" src="../static/img/Delete.png">');
},location:0.5
}]
I'm trying to add an event to the icon to delete the connection on click through
$('.delete-connection').click(function(){
//jsplumb.detach code goes here
})
But it is invoking the connection click event rather than the event for icon.
As per the answer suggested, I tried the following code:
$(document).on('click','.delete-connection',function(){
console.log('hit')
//detach connection code goes here
});
Please correct me if I'm making a mistake in code.
The jsfiddle link for the question: jsfiddle.net/cipher42/p9gdc4vm
Connections are created dynamically and hence, the overlays might not be present in the DOM when you're attaching the click handler to the delete icon overlay.
Try to attach the click handler as below :
$(document).on('click','.delete-connection',function(e){
//detach the connection here
});
There are many reasons as to why the fiddle in the question doesn't work.
Overlay <img> tag was not having delete-connection class. The correct attribute to give overlays an class is cssClass.
["Custom", {
create: function (component) {
return $('<img style="display:block;" src="https://lh6.ggpht.com/5I4BgwoxVAZH5vcPXwdjuNQ6Ellx9YCGgOYif7o2rMwJ2X7sCV96CqXy3OG4XCfwwhGm2C4=w20">');
},
location: 0.5,
cssClass: 'delete-connection'
}]
The fiddle was throwing error on jsPlumb.animate & hence, the click handler was never attached in the first place.
Here is a working fiddle : http://jsfiddle.net/nitincool4urchat/p9gdc4vm/9/
References:
http://api.jquery.com/on/
We can add events like this:
["Custom", {
create: function (component) {
return $('<img style="display:block;background-color:transparent;" src="img/delete.png">');
},
location: 0.5,
cssClass: 'delete-connection',
events:{
click:function(params) {
alert("hello!");
}
}
}]

Slickgrid - Lost focus to end edit

When editing my grid, if I click outside the grid, the box I was editing is still editable. How do I get the edited cell to "complete" the edit when it looses focus?
The following code will save the current edit.
Slick.GlobalEditorLock.commitCurrentEdit();
You'll need to place this inside an event handler that you think should trigger the save. For example, if you're using the sample text editor plugin, I believe an editor-text CSS class is added to the input field that's created when you're editing a cell so something like this should work:
$('#myGrid').on('blur', 'input.editor-text', function() {
Slick.GlobalEditorLock.commitCurrentEdit();
});
I found that I needed to wrap clav's handler in a timeout:
$("#myGrid").on('blur', 'input.editor-text', function() {
window.setTimeout(function() {
if (Slick.GlobalEditorLock.isActive())
Slick.GlobalEditorLock.commitCurrentEdit();
});
});
to avoid errors like:
Uncaught NotFoundError: An attempt was made to reference a Node in a context where it does not exist.
when using the keyboard to navigate. Presumably the new blur handler fires before SlickGrid can do its own handling and this causes problems.
Unfortunately, probably due to differences in event processing, Grame's version breaks keyboard navigation in chrome.
To fix this, I added another check to only commit the edit, if the newly focused element is not another editor element within the grid (as the result of keyboard navigation):
$('#grid').on('blur.editorFocusLost', 'input.editor-text', function() {
window.setTimeout(function() {
var focusedEditor = $("#grid :focus");
if (focusedEditor.length == 0 && Slick.GlobalEditorLock.isActive()) {
Slick.GlobalEditorLock.commitCurrentEdit();
}
});
});
This seems to work in current versions of firefox, chrome and ie.

Dojo Dialog onEnd() animation exception

I have a problem with the Dojo Dijit Dialog .hide() method during the animation sequence. I am using Dojo 1.7 with Tundra theme. I have a cancel button in my dialog that closes the dialog.
var global_welcome = new Dialog({
id: 'global_welcome',
style: "width: 750px",
draggable: false,
content: '<button type="button" id="global_welcomeCancel"> Cancel </button>',
onShow : function () {
on(dojo.byId('global_welcomeCancel'), "click", function (evt) {
dojo.stopEvent(evt);
global_welcome.hide();
});
});
}
});
This produces the following error on Firebug:
exception in animation handler for: onEnd fx.js (line 152)
TypeError: this._fadeOutDeferred is undefined
this._fadeOutDeferred.callback(true);
Previous answers to this error but with destroyRecursive instead of hide suggests it has to do with the dialog being destroyed before the animation finishes. I tried using dojo.hitch() and setTimeOut but that didn't seem to work. Also what is puzzling is that the first time I open this dialog using global_welcome.show() (called by another button), and press the cancel button, it works without error. The second time and afterwards, it produces the above error message. Additionally, the default close button for dojo dialogs on the top right corner never causes this error. Perhaps I could just have onShow call the methods that the close button calls?
Can someone help me out please? Thanks in advance!
The problem is in your onShow method. You wire up to the click event to hide, but never disconnect it. When you open the dialog the again, you wire the click method to hide the dialog again. The result is that hide will be called twice when you try to close the dialog for the second time. The error gets thrown with the second call to hide because the animations have already been destroyed.
Try this:
var signal = on(dojo.byId('global_welcomeCancel'), "click", function (evt) {
dojo.stopEvent(evt);
signal.remove();
global_welcome.hide();
});

Resources