How to get the name of a jQuery UI widget? - javascript

I need a way to read the name of a jQuery UI widget. I have subclassed the dialog widget into two subclasses, myDialog1 and myDialog2. I have created a destroyDialog function to destroy whichever dialog is active. There should be a way to determine the name of the widget instance.
What I want to do is something like this:
var destroyDialog = function() {
activeDialog[activeDialog.widgetName]("destroy");
}
But I don't see a way to get the widget name. For now I'm using ugly nested try-catch statements.
var destroyDialog = function() {
try {
activeDialog.dialog("destroy");
}
catch (e) {
try {
activeDialog.myDialog1("destroy");
}
catch (e) {
activeDialog.myDialog2("destroy");
}
}
}

You can get the widget name (and use it) by using
activeDialog.data("widgetName");
... as tdmartin refers to. So therefore:
activeDialog[activeDialog.data("widgetName")]("destroy");
But to get around this problem personally, I have written a plugin that will allow you to call a widget method without knowing what type the widget is. This will allow you to do:
activeDialog.callWidgetMethod('destroy');
It relies on you using jQuery UI 1.11+. If you are using <1.11, you can take out the "Skip this widget if it does not have the method" check, but the downside of that is that you will get an error if you attempt to call a method that a widget does not have.
Plugin code:
jQuery.fn.callWidgetMethod = function () {
var args = arguments;
var result = null;
if(!this || !this.length)
return this;
this.each(function (i,o) {
var compClass = $(this).data("widgetName");
var func = $(this)[compClass];
// Skip this element if it does not appear to be an initialised jQuery widget
if(!compClass || !func)
return true;
// Skip this widget if it does not have the method (the name of which will be in args[0])
// This relies on the 'instance' method provided in jQuery UI 1.11
if(args.length>1 && !$(this)[compClass]("instance")[args[0]])
return true;
result = func.apply($(this),args);
});
if(this.length>1)
return this;
else
return result;
};

If you standardize your namespace you could use a regex to match the name of the variable where your widget instance is stored (the name of the widget), returned by the $().data() method.
for (i in $(<your element>).data() ) {
if (i.match(/dialog/)) {
$(<your element>).data(i).destroy();
}
}

Related

overwrite arguments while bind multiple dynamic jqgrid

I have below code for binding jqgrid. I have multiple jqgrid in my page.
i bind all dynamically through below code.
var MyGridData = MyGridData || (function() {
return {
init : function(Args) {
_args = Args;
},
initiateGrid: function() {
this.fillGridSchema(_args[6]);
},
fillGridSchema : function() {
$('#' + _args[0]).jqGrid({
//All basic code for binding jqgrid (url,colnames...)
});
}
}
When i want to bind my SalesInquiryDetails Grid, then i call below code.
MyGridData.init([ 'SalesInquiryDetails',...(other required args) ]);
MyGridData.initiateGrid();
if i want to bind SalesReferenceGrid then,
MyGridData.init([ 'SalesInquiryReference',...(other required args) ]);
MyGridData.initiateGrid();
Now, i got _args of last bind grid every time. And not getting events which i have defined for previous grid.
Please guide me.
How can i fire previous grid event functions given in previous args array.
Thanks in advance.
Now, i got _args of last bind grid every time.
Right, because you have only one _args variable, which is a global. Your code is falling prey to what I call The Horror of Implicit Globals by assigning to an undefined symbol in loose mode, which reaches out and creates a global variable. One of JavaScript's major flaws, which was fixed by strict mode in 2009. (I strongly recommend using strict mode.)
In order to have more than one _args, you'll probably want init to return something (an object), store _args on it, and then call initiateGrid on that object. Your singleton can only remember the last state you set, so don't make it a singleton.
One way you might do that would be to use a standard constructor function:
var MyGridData = MyGridData || (function() {
function MyGridData(args) {
this.args = args;
}
MyGridData.prototype.initiateGrid = function() {
this.fillGridSchema(this.args[6]);
};
MyGridData.prototype.fillGridSchema = function(/*shouldn't you be using an arg here, since you pass one in `initiateGrid`?*/) {
$('#' + this.args[0]).jqGrid({
//All basic code for binding jqgrid (url,colnames...)
});
};
return MyGridData;
})();
// Usage
var salesDetailsGrid = new MyGridData([ 'SalesInquiryDetails',...(other required args) ]);
salesDetailsGrid.initiateGrid();
var salesInquiryGrid = new MyGridData.init([ 'SalesInquiryReference',...(other required args) ]);
salesInquiryGrid.initiateGrid();
Or with ES2015:
let MyGridData = MyGridData || (function() {
class MyGridData {
constructor(args) {
this.args = args;
}
initiateGrid() {
this.fillGridSchema(this.args[6]);
}
fillGridSchema(/*shouldn't you be using an arg here, since you pass one in `initiateGrid`?*/) {
$('#' + this.args[0]).jqGrid({
//All basic code for binding jqgrid (url,colnames...)
});
}
}
return MyGridData;
})();
// Usage
let salesDetailsGrid = new MyGridData([ 'SalesInquiryDetails',...(other required args) ]);
salesDetailsGrid.initiateGrid();
let salesInquiryGrid = new MyGridData.init([ 'SalesInquiryReference',...(other required args) ]);
salesInquiryGrid.initiateGrid();
But JavaScript is flexible, there are lots of other ways, such as factory functions.
Note: The code above is merely meant as an example, it's not meant to represent tested or thoroughly-reviewed code.

Javascript error: $(...).observe is not a function

I'm trying to use Stitch onEvent mixin in Tapestry 5.3.7.
Here's the OnEvent Javascript from there:
T5.extendInitializers({
onEvent: function (spec) {
var element = $(spec.id).observe(spec.event, function () {
var params = {};
if (spec.fieldIds) {
for (var i = 0; i < spec.fieldIds.length; ++i) {
var fieldId = spec.fieldIds[i];
var paramName = "onEvent." + fieldId;
var paramValue = $(fieldId).getValue();
params[paramName] = paramValue;
}
}
var zoneManager = Tapestry.findZoneManagerForZone(spec.zone);
zoneManager.updateFromURL(spec.url, params);
});
}
});
I use it in my TML like this:
<t:form t:id="filterTextForm">
<div style="float:right">
<input id="filterText" t:id="filterText" t:type="textfield"
t:value="filter" zone="configZone" t:autofocus="literal:true" onClick="this.select()" t:mixins="onEvent" event="keyup"/>
</div>
</t:form>
and my event method like this:
void onKeyupFromFilterText(String filter) {
this.filter = filter;
if (request.isXHR()) {
ajaxResponseRenderer.addRender(configZone).addRender(descZone);
}
}
When I have t:mixins="onEvent" event="keyup", none of the zones are updating on the page, no AJAX requests are generated.
When I remove it, everything works fine, except the part I'm trying to do, described in my question.
I'm using Tapestry 5.3.7.
observe() is a prototype function. I'm guessing that you're using tapestry-jquery which is a 3rd party library that removes prototype and replaces it with jquery.
You'll need to adapt the javascript to work with jquery (eg observe() needs to change to on())
You might find other bits of js broken too (eg I'm not sure if tapestry-jquery's ZoneManager is exactly the same as core tapestry).
tapestry-jquery comes with a builtin bind mixin which does a similar job to onevent. You might find it sufficient to use this mixin instead.

Adding a function to one jQuery/DOM element

I am authoring a plugin which instantiates a map. The map would then provide a function to move to another place on the earth.
The script makes the map just fine. However I can't "tack" the function on the element, to be used by another plugin in a callback.
Here's the approach I tried; in plugin:
(function($){
$.fn.mapDo(options){
map = new BlahMap(this.get(0));
this.moveTheMap = function(place){
map.moveItToThat(place);
}; // nope.
}
})(jQuery);
Then, in view:
$(map).mapDo();
$(otherElement).otherControl({
callback: function(place){
$(map).moveTheMap(place); // moveTheMap is not there on $(map)!
}
};
The Question
How do I add a function to the map jQuery or DOM element, if possible? If not, how can I provide that kind of functionality?
More importantly, am I going the right way here by separating the things that way? I'm a bit of a neophyte to Javascript, how are these tasks usually done while still keeping the components apart?
While that's the stab I took at it, more generally, I struggled with the concept of outputting things from a jQuery plugin while maintaining chainability. In this case, what I am trying to do is to output a callback from the plugin that will work on the called element later in the execution.
Plugins normally only add one method to the jQuery prototype, and the method calls to the plugin's instances are done with strings.
(function($) {
$.fn.mapDo = function(options) {
var args = [].slice.call(arguments, 1); //Get all the arguments starting from 2nd argument as an array
return this.each(function() {
var $this = $(this),
instance = $this.data("map-instance");
if (!instance) {
$this.data("map-instance", (instance = new BlahMap(this, options)));
}
if (typeof options == "string") {
instance[options].apply(instance, args);
}
});
};
})(jQuery);
$(elem).mapDo( "moveTheMap", place ); //This would also instantiate the plugin if it wasn't instantiated
Here's jsfiddle showing it in action:
http://jsfiddle.net/X8YA8/1/
You could store the map with .data method.
(function($){
$.fn.mapDo = funciont(options) {
this.data('map', new BlahMap(this.get(0)));
return this;
};
$.fn.moveTheMap = function(place) {
var map = this.data('map');
if (map) {
map.moveItToThat(place);
}
return this;
};
})(jQuery);

How to override dojo combox.js methods

I would like to override one method
onMouseUp:function(evt){
if(evt.target===this.domNode||!this._highlighted_option){
return;
}else{
if(evt.target==this.previousButton){
this.onPage(-1);
}else{
if(evt.target==this.nextButton){
this.onPage(1);
}else{
var tgt=evt.target;
while(!tgt.item){
tgt=tgt.parentNode;
}
in my JavaScript file.
How can I do that?
Literally, overwrite it using the same object and same method name.
var object = {
'method': function() {
// original script
}
};
// your script
object.method = function() {
// your script, original gets overwritten
};
EDIT
After a quick google and clicking the first result, I found a very simular thread which is probably more accurate for your... "problem": Dojo: how to use own onMove event (overwrite)

How do I create methods for an HTML element?

I'm trying to create a simple, small and basic javascript framework just for learning purposes.
But the thing is that i'm allready stuck at the very basics.
I'm trying to do something like this:
$('testdiv').testFunction();
And the code i've written for that:
var elementID;
var smallFramework = {
$:function(id) {
this.elementID = id;
},
testFunction:function() {
alert(this.elementID);
}
};
window.$ = smallFramework.$;
But in return I get:
$('testdiv) is undefined
Can anyone help me with this small and hopefully easy question?
To get the behavior you're expecting, you need the $ function to return an object with a method named testFunction.
Try:
var smallFramework = // an object for namespacing
{
$:function(id) // the core function - returns an object wrapping the id
{
return { // return an object literal
elementID: id, // holding the id passed in
testFunction: function() // and a simple method
{
alert(this.elementID);
}
};
}
};
Of course, there are many other ways to achieve the behavior you desire.
If you're trying to add methods to an HTML element you could do something along these lines.
$ = function( elementId ) {
var element = document.getElementById( elementId );
element.testFunction = function(){
alert( this.id );
return this; // for chaining
}
return element;
}
$('test').testFunction();
Try
smallFramework.$('testdiv');
instead. According to the code you posted, that's where your $ function ended up.
Or alternatively, it looks like you're trying to replicate something like jQuery. You might want to try something like this.
var $ = smallFramework = (function () {
var f =
{
find:function(id) {
f.elementID = id;
return f; //every function should return f, for chaining to work
},
testFunction:function() {
alert(f.elementID);
return f;
}
}
return f.find //the find function will be assigned to $.
//and also assigned to smallFramework.
//the find function returns f, so you get access to testFunction via chaining
// like $("blah").testFunction()
})() //note this function gets called immediately.
this code may look confusing to someone new to JavaScript because it depends heavily on the concept of closures. I suggest that if this doesn't make sense, spend some time at Douglas Crockford's JavaScript website. This is important because the code above will bite if you happen to use this in the find function because this won't be bound to f, as you may expect it to be when you use it from $ or smallFramework.

Categories

Resources