JavaScript, MooTools - Class.Event - onComplete: Do nothing by default - javascript

I'd like to make it possible to use an onComplete event in my MooTools class by implementing Events and using this.fireEvent("complete"). By default I just want to let the class do nothing. So how would you realize the default "do nothing" thing the cleanest and safest way?
Should I just omit the option onComplete in the default class options object and still use this.fireEvent("complete") in the context? Or is this causing errors or something? I just did it that way all the time, but I'm not sure if this is the best way...
Would you use something like if(this.options.onComplete && instanceOf(this.options.onComplete, Function)) { this.fireEvent("complete") } instead? Or would you specify an empty function as default like options: { onComplete: function(){} }?
I don't care about the shortest code at this point but I was wondering how to do it the most conform and memory saving way.
Thanks for your recommendations! :)

Good question. Have a look at the source code of MooTools:
if (!events || !events[type]) return this;
As you can see, the fireEvent will just return the current instance when an event is not found. Omitting onComplete and keeping this.fireEvent('complete') would therefore not give any errors or weird behaviour.
I would not even specify an empty function in the options. As you can see here, the events are simply left undefined and only mentioned using a comment so people know they are present and can be used:
options: {
//onComplete: $empty
}

Related

Promise object with alerts and return values causing errors

I have an interface that I'm working on that uses javascript to override the keyboard functionality. My initial question, before going into more depth of this issue is, when an alert is called, is there a way to have functions resolve after it without it missing timing, or am I just screwed in this sense.
I have tried using the Promise object but either I am doing something wrong or this is the wrong way to do it. I can get my meta data to reset if I simply just log a response in the callback function that is passed, but if I alert it, and I would assume the same if I did an ajax call, it fails.
So that is my issue, and I'm hoping this makes sense to someone.
I will explain the interface quickly so you can understand, i apologize ahead of time for the crude list layout:
overboard
constructor : Overboard
this.handle_keydown : gets the key event and makes the magic happen
this.handle_keyup : get the key event on up and clears the cache essentially
this.listen : generates the event listeners forkeyup and keydown
#return this
private : keyAction
the main engine of the Overboard class functionality. Checks to see if the option is set within the options object, checks for additional parameter sets, attempts the callback function, resets all meta data.
code: https://jsfiddle.net/gtqqewdd/14/
how you call the class
this is where I was running into the issue with the alert.
var override = overboard(window, {
a : {
ctrlKey : true,
callback : function(k){
if(k.ctrlKey){
alert('ctrl+a worked');
return true;
}
}
}
});
override.listen();
If I didn't explain anything well enough or clarification is needed on something, please let me know! Thank you in advance!
Opps misread the question. You can always use a library, which will be much less error prone, something like https://dmauro.github.io/Keypress/

How to use dojo/behavior on dojo widget?

I read this article (Using dojo.behavior), and want to use the behavior module in my project as event handling module.
But I have a problem that, for DOM nodes, it works wonderful, but how can I use it on the Dojo widgets?
If I use dojo/on module, I can do it like this:
var buttonNode = dijit.byId("myButton");
on(buttonNode, "onClick", buttonHandler);
or
dijit.byId("myButton").onClick = buttonHandler;
But, if I use behavior module,
behavior.add({
"#myButton": {
onClick: buttonHandler
}
});
it doesn't work. (Of course I called behavior.apply() after I finished page render.)
The code below doesn't work either.
behavior.add({
"[widgetid='myButton']": {
onClick: buttonHandler
}
});
After some investigation, I found the reason the code above not work is because a button widget is composed by many s and an inner . And if I use the id specified by data-dojo-id, it will point to a instead of the that I hope the event bind with.
I found a solution which can walk out this situation,
behavior.add({
"[widgetid='myButton'] input": {
onclick: buttonHandler
}
}
but the css selector is too complex and it depends on what type the widget is.
Is there a good solution to apply dojo/behavior on widgets just like on dom nodes?
It looks like what you really what is to hook up an event on the widget object, but behavior is designed to access the DOM instead. So, I think you're stuck with your workaround.

Can I bind action to a specific facebox?

I want to bind a function to the closing of a specific facebox? According to the limited documentation at facebox(at github) you could do something like this to bind actions.
$(document).bind('close.facebox', function() {
//do stuff...
})
But the problem with this is that it will bind the same action to all faceboxes created on the page.
So how could I bind different functions to different faceboxes? I have tried a few variants without success (probably due to my not yet masterlevelskills of javascript and jQuery):
Bind one general function as proposed by the documentation and in the function figure out what facebox was closed and do the wanted thing.
Get handle to facebox when created and use that to bind the action:
var fb = $.facebox('foo');
fb.bind('close.facebox', function() { ...do stuff ...})
Call bind on the facebox directly like:
$.facebox('foo').bind('close.facebox', function() { ...do stuff ...})
Probably more variants that I do not remember...
Please help me understand how I should do this (or why I should not try to do this).
After a quick look at the source I can think of a hack (!) to make this work:
Override the facebox#close method with you own.
The scope within this method will give you access to the "close" link which has just been clicked
Now you can traverse "sideways" to your content and use e.g. a data attribute or class name to identify which box you're currently showing
Based on that you can then make a decision what to do.
Here's an example:
HTML:
Foo
Bar
<div id="foo">
<div data-close="foo">Foo</div>
</div>
<div id="bar">
<div data-close="bar">Bar</div>
</div>
JS:
$.facebox.close = function(e) {
var type = $(this).prev().find('div:first').data("close");
switch (type) {
case "foo":
alert("FOO");
break;
case "bar":
alert("BAR");
break;
}
$(document).trigger('close.facebox');
return false
};
$('a.facebox').facebox();
Try it here: http://jsfiddle.net/SU3se/ .
I believe that the plugin makes the assumption that you'll not use it on multiple "different" objects and since you can have only one facebox open at times, this "should" not be an issue. But I can see why someone might want to do it nevertheless.
Please remember that my solution is a hack and really not very pretty. Maybe someone else can think of something better.

Watch for a property creation event?

I need to be able to determine when an object is created (not a DOM element -- a JavaScript object).
An answer to this question has some very useful looking code for creating observable properties, so you can have a function fire when a property changes.
In my situation I need to do something when the object/property is created, not an existing property changed, and my limited understanding of such matters did not help me figure out if or how I could use that code to do this after much squinting.
The situation is: page loads a bunch of scripts. Some of the scripts create things that are needed by other scripts, e.g:
ThisStuff = (function () {
// blah blah
return self;
} ());
Some other code needs to initialize this ThisStuff, whenever it's available, which may be after the DOM is done loading. The user doesn't actually need ThisStuff right away, so it's fine for it to happen whenever the script is done loading. So I would like to do something along lines of:
$(document).ready(function() {
wheneverIsAvailable(window,'ThisStuff', function(object) {
object.init(args);
})
});
I realize there are other solutions to this problem (changing script order, or loading scripts on demand) but those are difficult because of the architecture. So I'm only interested in a way to do this versus other solutions. If jQuery offers some such functionality, that's fine also as I'm using it.
You could have a setInterval checking a number of times a second to watch the specific variable. You can check whether it is created using obj.hasOwnProperty(prop). When it is created, you invoke the function, and clear the interval.
It might be dirty but it might also just work fine for you.
Edit: I coded this for you: http://jsfiddle.net/jhXJ2/2/. It also supports passing additional arguments to the function.
window.__intervals = [];
function wheneverIsAvailable(obj, prop, func) {
var id = (Math.random()+"").substring(2);
var args = arguments;
window.__intervals[id] = window.setInterval(function() {
if(obj.hasOwnProperty(prop)) {
window.clearInterval(window.__intervals[id]);
func(Array.prototype.slice.call(args, 3));
// Call function with additional parameters passed
// after func (from index 3 and on)
}
}, 1000/ 50);
}
wheneverIsAvailable(window, 'test', function() {
alert(arguments[0]);
}, 'Woot!');
window.setTimeout('window.test = 123', 1000);
This is a bit far-fetched but it might work.
You would need to use knockoutjs, a javascript library. It's awesome but is built for a slightly different purpose.
Anyways it has a dependentObservable thing which allows to fire up an event whenever a certain value changes. Now I know you want on creation but you can check whether your variable holds any value (other than what you provided initially), if yes then consider it initialize.
Let me know if you think this sounds feasible.

dojo how to override dijit class method

I need to override onClick method in the Tree.js. Is there any common way to override dojo/dijit classes methods?
I'm a bit confused, since you were already doing this in the last question you posted.
You've got a few choices, depending on what you want to do.
Clobbering method stubs
In the case of true stubs like onClick, it's potentially as easy as clobbering that method on your widget instance.
Programmatically:
var myWidget = new dijit.Tree({
...,
onClick: function(item, node, evt) {
/* handler code here */
}
};
Or declaratively (this is exactly the same as what you were doing in your last question):
<div dojoType="dijit.Tree" ...>
<script type="dojo/method" event="onClick" args="item,node,evt">
/* handler code here */
</script>
</div>
Connecting to method invocations
In other cases, perhaps you need to do something whenever a given method gets called, in which case you could use the widget's connect method (which is a nicer version of dojo.connect that will automatically clear itself when the widget is destroyed). In that case you could do something like this:
Programmatically:
//execute the given function whenever myWidget's onClick method is called
myWidget.connect(myWidget, 'onClick', function(item, node, evt) {
/* handler code here */
});
Declaratively, this can be done very similarly to the above, except instead of type="dojo/method", make sure you use type="dojo/connect"
<div dojoType="dijit.Tree" ...>
<script type="dojo/connect" event="onClick" args="item,node,evt">
/* handler code here */
</script>
</div>
Note that when you connect like this, your code will execute after the method whose invocation you are connecting to. If you need to do something before, your best option is probably to dojo.declare your own extension to the widget. If you need to go that far, I'll elaborate, but I think you'll likely be set with one of the above options.
Edit #1: Connecting the dots (no pun intended...oh heck, yes it was)
Since it seems that my comment appended to my answer to the original question was somehow not clear enough, here's a code block modifying the original code in that question based on the simple two steps exactly as I explained in that comment. The only tiny wrinkle is that the arguments passed to _onClick are slightly different.
<div dojoType="dijit.Tree" ...>
<script type="dojo/connect" event="_onClick" args="node,evt">
/* handler code here. In this case, item is accessible via node.item */
</script>
</div>
This solution may feel a bit sub-optimal since it involves connecting to a method that's suggested to be private. However, it's a way that should work regardless of whether openOnClick is true or not. If you are certain you're going to have openOnClick set to true, you could potentially write a single function, then connect it to both onClick and onOpen instead (both get passed the item, then the node).
Edit #2: Common functions, connecting programmatically
To answer your follow-up questions, I'd like to actually address them in reverse order - since if you are interested in connecting programmatically, it will actually make the other question easier to answer.
So first, to answer your connect question: you definitely don't want to be using dojo.byId, as that's not giving you the Tree widget, that's giving you some DOM node (probably the topmost) associated with the widget. As a general rule, dojo methods don't know anything about dijit stuff.
What you do want to be doing, is what I suggested above. Here it is applied as per the code you attempted. Also note that onClick has a capital C - another general rule: widget events use camel case notation, as a way to distinguish them from plain DOM events which don't.
var mytree = dijit.byId("mytree");
mytree.connect(mytree, "onClick", function(item) {
/* ... */
});
Now, to take that a step further and resolve your other inquiry, if you want to bind some common functionality to onClick and onOpen and onClose, you could define a function first, then connect it to both. This is one of the many things that makes JavaScript awesome - the availability of functions as first-class objects that can be easily passed around.
function handleClick(item) {
/* do stuff here.
Inside this function you can assume 'this' is the tree,
since connect will ensure it runs in-context.
*/
}
var mytree = dijit.byId("mytree");
mytree.connect(mytree, "onClick", handleClick);
mytree.connect(mytree, "onOpen", handleClick);
mytree.connect(mytree, "onClose", handleClick);
Now there's one important remaining question: where should we do this? The best place is likely inside a function passed to dojo.ready (or dojo.addOnLoad, same thing, ready was added as a synonym in 1.4) so that it will run only after:
The DOM is parsed by the browser
All dojo.required modules have loaded
If you set parseOnLoad: true in djConfig, all widgets defined in the document's HTML will already be instantiated
So, sometime after your dojo.requires, in script, you'd do this:
dojo.ready(function() {
/* code from previous example goes here */
});
Give it a shot.
Also, if you're interested in a bit of reading, I've actually written about a couple of topics I touched on in this edit:
Of Dijits and DOM Nodes
dojo.required Reading
You could use:
dojo.connect(tree, 'onClick', function(item) {
/** Your Action **/
});

Categories