Extending widgets in Jquery UI with redefining parent methods - javascript

I try to extend UI dialog according to documentation (UI version 1.8.16):
(function($) {
$.widget('ui.mydialog', $.extend(true, $.ui.dialog.prototype, {
_create: function() {
return $.Widget.prototype._create.apply(this, arguments);
}
}));
})(jQuery);
$(function() {
$('div#dialog').mydialog();
});
Executing of this code causes JS error: "this.uiDialog is undefined".
And if try to override the _init() method there are no errors, but parent method call takes no effect.
I'm confused.. Which way is legal to extending for e.g. put some custom initialize code?

I think this post would solve your question: Inherit from jQuery UI dialog and call overridden method.
In short, if you want to build a widget inheriting jQuery UI Dialog, you can do this:
(function($) {
$.widget("ui.mydialog", $.ui.dialog, {
_create: function() {
$.ui.dialog.prototype._create.call(this);
}
});
})(jQuery);
See this in action: http://jsfiddle.net/william/RELxP/.
This tutorial will enlighten you: http://wiki.jqueryui.com/w/page/12138135/Widget%20factory. In short, $.Widget is the base widget object. Even though it has a _create function, it by default does nothing, leaving the initialisation code to the subclass. Take a look at this updated example: http://jsfiddle.net/william/RELxP/1.

From jQuery 1.9 and on, if you want to add functionality to a widget and don't want to replace the existing function, after you do your code call the parent method. To do this, instead of what William Niu suggests, you can simply do this:
_create: function()
{
// Custom code here
// Call the _create method of the widget
this._super();
}
This applies to all existing methods. (eg _setOption, _trigger etc)

I posted a simple example of extending a jQueryUI Dialog using the Widget factory.
http://jsfiddle.net/Artistan/jWUGZ/
This example extends a dialog to create a simple loading modal.

Related

JS selector combined with jquery

I wonder if there's a way to combine a JS selector with jQuery functions methods like that:
document.getElementsByClassName("example").on("click", function() {
...
});
You can pass your node list to the jQuery constructor:
$(document.getElementsByClassName("example")).on("click", function() {
// ...
});
I don't know for sure how long jQuery has recognized when node lists are passed to the constructor, but it seems to work now.

How to destroy a jQuery UI widgets from within it's prototype

I've gotten on board to using the Widget Factory for creating plugins. However I can't seem to find a way to destroy the plugin from within.
In all the examples and tutorials I've found so far they destroy the plugin from the DOM. Which is all good and well but I would also like to be able to destroy the plugin from within my prototype.
Say for example the plugin is invoked with incorrect parameters or a incorrect element or after some time it does not validate. I would like to be able to call this.destroy() afterwards and destroy the plugin. When i call this.destroy() it does call the $.Widget.prototype.destroy() and my subsequent _destroy() method but the instance is still on the DOM element. Only when calling $(el).pluginName('destroy') does it get truly destroyed.
Quick example here
Say we have some html
<p>Lorem ipsum</p>
and our jQuery UI widget, which aims to destroy it as soon as it's created
$.widget('ns.test', {
_create: function() {
this.destroy();
},
_destroy: function() {}
});
and we invoke the pluging so
$('p').test();
I would expect that the instance would not be set on the $('p') but it is
$('p').data();
>> Object {ns-test: $.widget.$.(anonymous function).(anonymous function)}
Only when calling the method from the DOM it gets destroyed
$('p').test('destroy');
>> Object {}
Any thoughts anyone?
+blgt insight was more or less correct. So I'm adding it and accepting it.
You can call this.destroy() from any method other than _create and _init and it will work as you expect, but I'm not entirely sure why. Probably has something to do with how the .data data is managed

Backbone.js getting callback of render, within the view

I have a Backbone app and we have stuff like this:
render: function() {
this.$el.html(_template());
$('#id').plugin();
return this;
}
The #id is from an element that's being rendered. This only works sometimes, as it can take longer for it to actually insert into dom.
Is there a way within this view, to define a callback or somehow know for sure that the dom has been updated, before calling our plugin() function?
Thank you!
Your problem is that this:
$('#id').plugin();
is looking for #id inside the DOM but this.$el isn't in the DOM yet; so, if #id is inside this.$el, then #id isn't in the DOM either and $('#id') will be empty. You want to look for #id inside this.$el and Backbone provides the this.$ shortcut for that:
$ (jQuery or Zepto) view.$(selector)
If jQuery or Zepto is included on the page, each view has a $ function that runs queries scoped within the view's element. [...] It's equivalent to running: view.$el.find(selector).
So you want to do this:
this.$('#id').plugin();
If your plugin needs its element to be rendered (perhaps it needs size and position information), then you'll have to kludge around a bit:
The caller can call a method on your view after it has added it to the DOM.
You can use setTimeout(..., 0) or _.defer to bind the plugin after the browser has updated the DOM. This only works if everyone is using the common x.append(v.render().el) pattern though.
Symply trigger an event:
MyView = Backbone.View.extend({
initialize: function(){
this.on('view:rendered', this.initPlugin, this);
},
render: function(){
this.$el.html(_template());
this.trigger('view:rendered', this/*or some useful data*/)
},
initPlugin: function(){
this.$('#id').plugin()//watch on this.$ to apply selector inside this view only
}
I am not sure but give a try
bind it to the view as event , fire it after the view being rendered
var viewobject = {};
_.extend(viewobject, Backbone.Events);
viewobject.on("alert", function(msg) {
$('#id').plugin();
});
object.trigger("alert", "an event");

Is there a way to trigger an event when inserting html?

It's for a backbone application,
I'm using Jquery html() function to insert my views templates into the layout everywhere, and I would like to be able to trigger an event each time the html() function of jQuery is called to check the html of the page.
Is there a way to do that ?
( Like App.on('html', blablabla...); )
Thank you !
As Marc B suggested DOM MutationEvents is available on some browsers (not many). By default jQuery does not fire any event when using html, but you can define your own behaviour for this, for example:
(function($) {
var html_ref = $.fn.html;
$.fn.extend({
html : function() {
$(document).trigger( 'html_change' );
return html_ref.apply(this, arguments);
}
});
})($);
It should work, didn't test it though. You can use the same with .text method. Now you can simply use:
$(document).bind( 'html_change', function() {
// Hurray! Html changed!
});
That's the idea, use it as you wish.
AFAIK, the jQuery html() method doesn't fire any subscribable events per se, but you could probably roll your own implementation of a simple Observer pattern. I use this across a large number of projects and it provides a great, clean, lightweight way to encapsulate arbitrary event handling across loosely-coupled modules.
However, this is presuming that you have programmatic control over every time the html() method is called - if not, then this would be more difficult, as there is no callback function to hook into.

How can I check if a particular jQuery UI function is available and use a different function if it isn't?

I'm writing a jQuery plugin and I would like my code to take advantage of the jQuery UI show(effect, [options], [speed], [callback]) and hide(effect, [options], [speed], [callback]) functions, which allow you to show and hide elements with a nice animation.
However, I'd also like my plugin to degrade gracefully if jQuery UI isn't available, switching back to use the basic, non-animating show() and hide() functions present in the standard jQuery API.
I'll need to test for the show and hide functions specifically, as even if jQuery UI is available it could potentially be a custom version, without the Effects components included.
At first I thought that I might be able to do something like:
if(typeof myelement.show('blind', 'slow') == 'undefined')
{
myelement.show('blind', 'slow');
}
else
{
myelement.show();
}
But of course this doesn't work, as even if UI isn't present, show() is still a function, it just has a different signature—so typeof returns object in either case.
So, what's the best way for me to check if jQuery UI is available to my plugin? Any help is much appreciated!
You can check for an effect like this:
function hasEffect(effect) {
return $.effects && $.effects[effect];
}
Then you can use that anywhere:
if(hasEffect('blind')) {
myelement.show('blind', 'slow');
} else {
myElement.show();
}
//or, you can shorten it further:
//$.fn.show.apply(myelement, hasEffect('blind') ? ['blind','slow'] : []);​
You can view a demo here, check/uncheck jQuery UI on the left and click "Run" up top to see it in action. This works because effects are declared like this:
$.effects.blind = function(o) { ...effecty stuff... };
For example, you can see "blind" here. The reason I check for both $.effects and $.effects.effect in the code above is you can only download some of the effects when you download jQuery UI, so this accounts for that possibility.
Nick's function worked perfectly; for consistency, I ended up adding it as a jQuery utility function from within my plugin code:
$.extend({
hasEffect: function (effect) {
return $.effects && $.effects[effect];
}
});
So now I can call $.hasEffect(effectname) anywhere I want to check for the presence of a particular jQuery UI effect.

Categories