I have a piece of code that initialises a resize handler in the following way:
dojo._hasResource["dojox.layout.ResizeHandle"] = true;
dojo.provide("dojox.layout.ResizeHandle");
dojo.experimental("dojox.layout.ResizeHandle");
dojo.declare("dojox.layout.ResizeHandle", [dijit._Widget, dijit._Templated], {
_init: function(){},
create: function(){
this.connect(this.resizeHandle, "mouseover", "_init");
}
// ... more properties
});
This is written in a core app file which I cannot edit. I need to rebind this resize handler to respond to touch events. I was thinking of overwriting this widget and rebind the resize handler with "touch" events. Something like so,
this.connect(this.resizeHandle, "touchstart", "_init");
I have never worked on Dojo before. So, I am not sure how the module system works. I tried creating a new widget by changing the string that identifies the widget ("dojox.layout.ResizeHandle") but no luck there.
How do I destroy the existing widget and rebind with touch events?
This code does not initialize a widget. The declare function creates a class. In this case it creates a class called "dojox.layout.ResizeHandle". To use this class you need to require it and then instantiate it. Something like this
require(["dojox/layout/ResizeHandle"], function(ResizeHandle) {
var resize = new ResizeHandle();
}
From there you can attach new handlers.
on(resize.resizeHandle, "touchstart", "_init);
It's also worth pointing out that you are using old deprecated dojo syntax (connect vs on, etc) although you may be using an older version of dojo.
Related
I am making a JQuery plugin that needs to know the the context event that called the plugin so I can do e.preventDefault(); from inside.
The plugin is here: https://github.com/brenosilver/JQuery.PopupBox
Currently I have this:
$("#el").click(function(event){
$("#targetEl").popupBox(event);
});
But I don't want the event to be passed as I'm trying to make it as user friendly as possible.
Inside the plugin I have this:
$.fn.popupBox = function(event, options){
event.preventDefault();
event.stopPropagation();
}
I had success using:
var contextObject = window.getSelection().getRangeAt(0).startContainer.parentNode;
var event = $._data( $(contextObject)[0], "events" );
but this doesn't return a native event type object. So I can't use event.preventDefault();.
Further explanation:
I need to have event.stopPropagation because if not, the element the plugin handles just shows on the screen then hides instantly.
Based on the comments and the example of the plugin usage, it's seems to me that the design of the plugin should be a little different.
Plugin should not be concerned with outside-world events, and of course it should not mess with events and whatever happens outside of it. After all this is the purpose of the plugin - to be plugged in and operate.
I recommend to change the strategy to the one where you bind click events on the click target inside of the plugin.
The configuration then might look like this:
$("#targetEl").popupBox({
clickOn: '#el'
});
or other way around:
$("#el").popupBox({
target: "#targetEl"
});
In both cases you would bind click event inside of the plugin yourself and be able to do with event whatever you need.
I have a custom dojo widget that I need to listen for an event on another 3rd party widget and then emit that an event with the event object to another custom widget. For some reason, my custom widget is not emitting the event or the event is not registering properly with my second custom widget.
Here is the event-related code in my 1st custom widget:
onSelectComplete : function(evt) {
// this custom widget inherits from dojo/Evented. I've tried using this.emit and I've tried inheriting from _WidgetBase
on.emit(self, "select", evt);
},
startDrawing : function() {
//self._drawToolbar is the 3rd party widget from an API
self._drawToolbar.activate(Draw.POLYGON);
self._drawEndHandle = self._drawToolbar.on("draw-end", self.onSelectComplete);
},
Here is the listener in my 2nd custom widget:
on(self._selector, "select", function(evt) {
console.log(evt);
});
For the listener, I've tried listening for onSelectComplete, selectComplete, SelectComplete, selectcomplete, select-complete and none have worked. I've also tried using aspect.after instead of on, but that also didn't work. I was able to determine while debugging that the onSelectComplete of the 1st custom widget is being called correctly.
I'm stuck...
Sorry I didn't provide the answer sooner, but I did discover a solution.
Instead of having my dojo module inherit from dojo/Evented, I made it inherit from dijit/_WidgetBase. By doing so, my custom dojo module/widget now implements the on function.
So in my 1st widget I have an empty function called onSelectComplete : function (evt) {}, which I call when I want to emit the event.
And in my 2nd widget my code is:
on(self._selector, "selectComplete", function(evt) {
console.log(evt);
});
Do make things clear: The onXXX functions was the old way to emit.
I was fine with it, but it is deprecated!
What the hell is 'self'? Did you mean: 'this'?
Any widget inheriting from dojo/Evented can
on.emit(this, "select", {anyProperty: 'will be mixed in the event'});
The above is bubbling up which seems to be what you want to do ?
You could also do
this.emit("select", {anyProperty: 'will be mixed in the event'});
But this is only triggered once and not bubbled up.
From any other widget you can subscribe as you stated.
Tell me if you need a working example.
using Backbone.js with Marionette.js (Go Derick Bailey!). Need to detect when a view is removed from the page. Specifically, I'm overwriting it with another view.
Is there an event I can detect of function I can overload to detect when this happens?
Thanks!
Marionette provides the View.onClose method for this purpose:
Backbone.Marionette.ItemView.extend({
onClose: function(){
// custom cleanup or closing code, here
}
});
In vanilla Backbone you can override the View.remove method:
Backbone.View.extend({
remove: function(){
// custom cleanup or closing code, here
// call the base class remove method
Backbone.View.prototype.remove.apply(this, arguments);
}
});
Neither of these methods will work if you are simply clobbering the view's DOM element. If that is your case, the solution is simple: Don't do that. Remove the previous view explicitly before rendering another view in its place.
The region show function is going to do most of what you are looking for
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#basic-use
And look at the on show event later in the page
There is a 'View' in the model with the event click. After using the Quicksand effects plug-in for jQuery, the objects loose their event handlers. I have tried to add the listener for the event with standard methods in backbone.js:
events: {
"click .objContact" : "openChat"
}
and the same tools jQuery delegate:
var self=this;
this.$el.delegate('.objContact','click', function(){
self.openChat();
});
and live:
var self=this;
this.$el.find('.objContact').live('click', function(){
self.openChat();
});
but the click event disappears.
What could be the problem? And how do I solve it?
UPD: Calling 'Quicksand' is in Backbone.Router (subject to change is obtained directly by means of jQuery, not Backbone), so changes are not handled in Backbone.View
UPD 2: The problem is solved in the following way - by moving the handling of the click event from the View-model to View-collection. And treated with live (did not work in on)
Simple Answer: instead of linking the function to the link with the classic ajax method that is
$('a.oldJqueryClass').click(function(){....
you need to make that function standalone, declaring a new function
function myfunction(params) {alert(params);}
than in the link you call that with the old school way:
Click here
In this way the cloned element will contain itself the call to the function and you can forget about restoring the dom integrity broken by the cloning of quicksand.
I did it in my project, it works fine.
Do a call to delegateEvents() after the related DOM entries have changed or become overwritten. In a traditional Backbone app this is typically done in the render method, but you probably need for figure out when and where quicksand does it's magic (I do not know anything about it), and call delegateEvents that will reactivate the events for the current elements in the DOM.
I have a knockout binding handler that uses plupload for drag and drop and ajax uploads.
To use the plupload script I create an instance of plupload which in turn is binding event listeners to DOM elements.
That works fine.
However, I have a list of "folders" and when I click a folder I display a list of files in that folder. I reuse the same DOM elements for this by binding selectedFolder().documents using foreach.
The problem I have is that in my binding handler I do all my plupload stuff in the init function and since I reuse the DOM elements they get multiple event handlers bound to them. This causes the drag and drop events to be sent to alla handlers. This means that if I drop a file on the rendered file list, the drop event fires on all previously rendered file lists too.
What I am looking for is some sort of teardown or cleanup function in the binding handler, so that I can unregister all of the events whenever a file list get unrendered (is that a word?).
Maybe we cannot detect unrendering? How would I then handle this? I would prefer not to have a global instance, since that would prevent me from using the binding on multiple places at the same time.
Sorry about not giving you any code. I'm on my cell phone atm.
Cheers!
You can register a handler that will be executed whenever KO removes elements (like when a template is re-rendered). It looks like:
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).datepicker("destroy");
});
So, in your "init" function you would register a dispose callback for the element that is being bound and you would have an opportunity to run whatever clean-up code that you would like.
I believe the solution provided here will only work if Knockout is the one that removes the DOM node (ie when it rejigs templates). I had a hard time getting it to trigger under certain conditions. There might be scenarios where you need a callback to be executed regardless of how your element got removed; whether it be with Knockout, or via jQuery.html(), etc (especially in a single page application).
I brewed a different approach for adding such a hook with a little help from jQuery. Using the special events API (which are well described here), you can add a method that gets execute when a particular event is removed from a DOM node (something that happens on teardown).
If you are using Knockout in conjunction with jQuery, you can wrap this into a knockout binding to look something like this:
ko.bindingHandlers.unload = {
init: function (element, valueAccessor) {
var eventName = 'your_unique_unLoad_event'; // Make sure this name does not collide
if (!$.event.special[eventName]) {
$.event.special[eventName] = {
remove: function (o) {
o.data.onUnload()
}
};
}
$(element).on(eventName, { onUnload: valueAccessor()}, $.noop);
}
};
You can then use this on any element like this:
<div id="withViewModelMethod" data-bind="unload: aMethodOnMyViewModel" />
<div id="withInLineMethod" data-bind="unload: function() { /* ... */ }" />
I owe credits to this SO post.