modifying jquery widget - jquery-ui

I'm using Eric Hynds' multiselect widget.
I'd like to modify it, adding an option and including an extra step in the _refresh method. Now I can modify the plugin easily enough to accomplish my aims, but what I'd like to do is to create a wrapper or similar that means I can update the widget in future, while keeping my changes separate.
The widget is built using jquery ui 1.8 widget factory .
What is the best way to achieve my aims?

Without knowing all your details, you can try extending the widget.
$.extend($.widget, {refresh:function(){your function here}});
I've used this for adding functionality to a widget, but not for overriding existing functions.
You also try using inheritance, which is probably the right call here. When defining your new widget there is an argument to pass in an existing base widget
(function ($) {
$.widget('an.originalwidget', $.a.yourwidget, {
...
refresh: function() {
// override code
}
});
}(jQuery));
Here is a great link to try:
http://msdn.microsoft.com/en-us/library/hh404085
Edit: I did this using Jquery 1.7.2, I notice you are using 1.8, while I don't think there will be any changes to this, you might want to check

Related

Syntax for using a plugin's custom event method

I'm having trouble figuring out the correct syntax to use when a plugin/widget requires using a custom 'event' method instead of the standard jQuery events.
The jQuery UI MultiSelect Widget doesn't support the change method, and instead provides a click event which is fired when a checkbox is checked or unchecked. I'm trying to use the syntax supplied in the widget's documentation for the click event so that I can replace several change functions including the one shown below, but I'm having trouble figuring out the correct syntax. The structure for the click event is:
$("[name=Item]").on("multiselectclick", function (event, ui) {...});
I've tried inserting the function in between the curly brackets, and I've also tried .on("multiselectclick", function () {...}); without success, so I'm assuming that I need to insert something here: (event, ui)
I've managed to get the functions partially working by using a slightly different method $("[name=Item]").multiselect({ click: function (event, ui) {...}, but I'd really like to understand how to use the plugin's custom event so that I can get the functions working properly. I posted a fiddle with a very simple example here http://jsfiddle.net/chayacooper/cZRy9/5/, and included notes to indicate what wasn't working properly.
One of the functions where I'm trying to replace a change event with the widget's click event:
$("[name=Item]").change(function(){
$("#Styles1, #Styles2").hide();
$(".accordion").accordion("option", "active", false);
if( $("[name=Item]").val() === "Dresses"){
$("#Styles1").show();
$(".accordion").accordion("option", "active", 0);
$('varItem').val('Dresses');
}
else {...}
});
First issue about not hiding the Styles element when dresses is unchecked is straightforward. There is nothing in code to check state of the checkbox, only the value
Fix with:
if ((ui.value) === "Dresses" && ui.checked)
Using the ui object within a jQuery UI patterned widget is usually best source for your data or state , rather than using jQuery selector to look for the same thing.
I have never used this plugin, so to figure out what was available to me, I simply used console.log(ui) within the click handler so I could inspect the ui object to see what properties it contained, and found the checked property to add to above if conditional
If you do the same on a more complex widget like jQueryUI datepicker will see quite a significant number of ui properties , some of which are also method functions
DEMO (using custom event)
http://jsfiddle.net/cZRy9/2/

jQuery UI widget 'change' event

I'm trying to maintain a widget that triggers events using one of these two lines of code:
this.element.trigger('change'); // or...
stop: function (event, ui) { that.element.change(); }
The word 'change' occurs only 4 times in the code, in one of the 2 forms above. However, I've got no idea what's going on here. There's no event handler in the change call, and there are no bind, delegate, on, or live calls, so something external is presumably setting this up. Can anyone fill me in? Are there any docs on this? Thanks.
Those two lines of code simply trigger a change event to this.element using two different allowed syntax.
Using .trigger():
this.element.trigger('change');
Or using a shorthand method .change():
that.element.change();
You can actually bind an event handler to the element represented by this.element to handle this event.
Without knowing your plugin, it is difficult to answer you precisely on what is this.element.
But take the example of the autocomplete plugin. In this one, this.element is actually the input field the autocomplete plugin is applied to. If the change event was triggered like supposedly done in your question, you could bind an event handler to the input like this:
$('#myinput')
.autocomplete()
.bind('change', function() { });
Now if this plugin relies on the jQuery UI Widget Factory, it is advisable to use the method _trigger() to trigger events instead of the jquery .trigger().
Using _trigger() will make sure to execute any callback defined in the plugin's option with a correct context and also trigger that event for this.element (like above). So you could have:
$('#myinput')
.somePlugin({
change: function(e, someData) {
// "this" here will be `this.element´
}
})
.bind('change', function() { ... });
The answer turned out to be simple - there was no event handler, there were no bind/etc calls, jQuery does nothing behind the scenes, so the trigger calls did nothing. I commented them out and the widget behaved exactly the same. Doh.

ui-dialog, getTitleId method is not in the prototype literal, why?

I want to increase my knowledge concering jquery-ui, so I look at their source code.
I work with jquery-ui 1.19m5.
When I look at the 1.19m5 source code of ui-dialog I see after the call to the widget factory:
$.extend($.ui.dialog, {
...
getTitleId: function($el) {
...
I do not understand this. Why don't they put the getTitleID method directly into the prototype literal (the 3rd parameter with the widget factory call)?
jQuery UI is designed to trigger methods from the appropriate widget API. So to call a method, you would do $('.selector').widgetName('methodName',arguments);
This allows the plugin developer to easily add private/public functions, as well as avoid namespace collision. It is possible to have an object that is resizeable, draggable, and dropable all at one...these three plugins share some method names, such as the enable/disable function.
In this example, if they added it to the prototype under 'enable', this would only allow you to enable/disable the functionality of the last widget you added, making it impossible to have control over all of the widget types. With their API, you can specifically select a widget to modify. Ex. $('.selector').draggable('disable'); which would disable the drag feature, and keep the resizable and droppable widgets fully functional. Keep in mind, many widgets have the same or similar methods, events, and/or option names.
Long and short, it is for namespacing purposes. This also makes it easier on the developer because he only has to worry about the top level widget name when writing his/her own widgets, without worry of what other methods, options, data, etc that has been added to the prototype directly.
They could add it to the prototype under a second layer, possibly, but this doesn't really save you (the user) any time, and probably would not look as clear in code. or they could add a prefix to every single function to specify namespace, but that would clutter your code, and create more checks and potential points of failure for developers creating their own widgets.

How to derive a custom widget from jquery-ui dialog

I want to build a jquery-ui widget and I am unsure of the best way to approach this.
The widget will manage the sate of some data that is hosted inside of a jquery-ui dialog.
Should I build a custom widget, in the widget create function add some elements to the widget target and then call the dialog widget on my widgets target.
Or
Is there a way to inherit from the jquery-ui dialog and just override the content part of it?
There is a way to extend other widgets:
$.widget("ui.customwidget", $.ui.dialog, {
options: {
// your options
},
_create: function() {
$.ui.dialog.prototype._create.apply(this);
// constructor
},
destroy: function() {
// destructor
$.ui.dialog.prototype.destroy.apply(this);
},
_setOption: function(key, value) {
$.ui.dialog.prototype._setOption.apply(this, arguments);
// process the setting of options
}
// other methods
});
But I'd not encourage using it on a dialog, slider etc. because e.g. buttonset relies on the existence of the button widget and will (and can) not recognize if the element is an instance of a widget that extended button. Therefore it just creates new pure button widgets, what leads to a messed up layout and DOM. Overriding parts of a widget is also critical: The extending mechanism for widgets was introduced not so long ago, when some widgets already existed. The developers of them did not have this feature in mind, so there may still be issues with this.
I aggregate my widgets (your first option): Just extend the $.Widget and make the element a dialog too. Then add event listeners for the properties that need to be synchronized between the dialog and your custom widget.
$.widget("ui.customwidget", $.Widget, {
// ...
_create: function() {
$.Widget.prototype._create.apply(this);
this.element.dialog();
}
// ...
});
This way more robust than extending other widgets (except you built the parent and know what you are doing), but it has it's disadvantages too. E.g. do you accept setting options of the aggregated widget too, or just parts of it? Or do you do none of these and force the user to call the dialog for everything that is not handled in your custom widget? I prefer the second option: It's at least honest, because your widget does't promise things it can't hold, but it's ugly too, because you may once call one, then the other widget.
I'm still not that happy with my solution, but extending widgets put me in front of a whole load of new problems whose solutions would have been either to patch the jQuery UI source or to write an ugly hack.
(I just noticed that this question is about a year old, and the asker may not have this problem anymore. But I'd written all the stuff above already and think it's not that bad to not be posted.)

Determine if an element is a jQueryUI Widget

I have written a jquery-ui widget using the Widget Factory...
I need to be able to determine in code whether the element is already a widget or not...
My investmentGrid widget is created on #container with
$('#container').investmentGrid()
I need to be able to determine elsewhere in the code if $('#container') is already an investmentGrid
You can query the element's jQuery.data() function, like so:
if ($('#container').data('investmentGrid')) {
...
}
You could try the pseudo selector that is created for you when using the widget factory. $(":namespace-widgetname")
#dan-story may have had the answer at the time he answered it, but I have found that that method doesn't work anymore. Well, not entirely. At least not with jQueryUI 1.10. According to the documentation at http://api.jqueryui.com/jQuery.widget/ in the "Instance" section, you now need to have the widget's full name.
For example, if you create your widget factory with this:
$.widget("Boycs.investmentGrid", ...);
Then, to check if container has it, you would check with this:
if ($('#container').data('Boycs-investmentGrid'))
{
...
}
It is no longer enough to just use the name.
#Boycs: As per my understanding, using Widget Factory protects you from instantiating a plugin multiple times on the same element. (ref: http://jqueryui.pbworks.com/widget-factory)
In addition if you want to confirm if "container" is already an investment grid you can try the following option from inside your plugin code:
this.element.data("investmentGrid")
=== this;
For more details you can refer to docs.jquery.com/UI_Developer_Guide
Current versions of jQuery UI (I can confirm it with 1.11.x) allow you to query for an instance of a widget via the instance() method. This will then look like this:
$('#container').investmentGrid('instance')
If the element does not have an investmentGrid widget assigned, you will get undefined back.
You may also use call this instead:
$(#container').is(':data("namespace-investmentGrid")')
This has the advantage, that it also works even when the widget is not loaded.

Resources