Find elements which have jquery widgets initialized upon them - javascript

I am using the jQuery-File-Upload widget (although I believe this question can generalize to any jQuery widget). The API instructs the user to initialize the the widget using the fileupload method, thus:
$('#fileupload').fileupload();
My question is: Without knowing IDs, how can I find #fileupload (and any other elements which have had .fileupload() called upon them?

jQuery File Upload uses the jQuery UI widget factory under the hood, and that factory is known to register the widgets instances with the elements they extend using data().
Therefore, you can use filter() and write something like:
// Restrict ancestor if you can, $("*") is expensive.
var uploadified = $("#yourAncestor *").filter(function() {
return $(this).data("fileupload");
});
Update: From jQuery UI 1.9 onwards, the data() key becomes the widget's fully qualified name, with dots replaced by dashes. Therefore, the code above becomes:
var uploadified = $("#yourAncestor *").filter(function() {
return $(this).data("blueimp-fileupload");
});
Using the unqualified name is still supported in 1.9 but is deprecated, and support will be dropped in 1.10.

Related

purpose of data in jquery? (vs adding my own fields to Jquery objects)

This question is related to mine and explains what .data method is in Jquery.
Apart from the relation to HTML5 data-* element attributes (like <p class='foo_cl' data-bar='gee'>, for example) why would I code:
$('body').data("my_lab", {some:"object"}); // §1
instead of
$('body').my_lab = {some:"object"}; // §2
(I am mostly interested in the case where the Jquery selector gives one object, like for $('body') above)
The later (§2) seems more readable and shorter, and I guess would be more efficient, than the former (§1). Of course data is a Jquery selector (but I could use each to set the .my_lab field, etc...)
And I might even consider changing the DOM element with the ugly looking
$('body')[0].my_lab = {some:"object"}; // §3 is ugly
(which is perhaps undefined behavior, see this)
Of course, there is the potential issue of colliding the field name my_lab with some existing field in JQuery implementation; but I assume that using some common suffix (like my_) in field names should be enough.
FWIW, I am only interested in recent Jquery (e.g. Jquery 2.1.4) on recent Firefox (e.g. 38 or 42) on Linux.
In other words, why would adding my own fields in JQuery objects be frowned upon?
By doing
$('body').my_lab = {some:"object"};
You are setting value to a specified jQuery wrapper. You would not be able to reaccess the data with another selector :
$('body').my_lab = {some:"object"};
console.log($('body').my_lab); // will log undefined
This is why using data is basically more reliable
$('body').data('my_lab', {some:"object"});
console.log($('body').data("my_lab")); // will log {some: "object"}
For the 3rd option : $("body")[0].attr = { my : "object" } part :
The jQuery data method prevents potential memory leaks when manipulating the dom / removing elements from the page (by removing the binded data and stuff) and avoid attribute conflicts (like setting domElement existing attributes and other subtle things)
So basically, if you have jQuery in you app, you don't really have any good reason to reinvent the wheel by doing manual binding between dom element and javascript data.

Detect "hooked" DOM elements

So I have a set of jQuery plugins, really basic stuff, but I split the code into plugins because I don't like having a huge jQuery(document).ready() function where I store the entire application logic.
Each plugin has a "destructor", which is basically a function that I defined in the plugin prototype object. This function unbinds events used by the plugin, removes DOM elements that were added by the plugin etc.
Plugins are initialized like this:
$('.element').plugin();
Is there any way I can get all the elements that have my plugins attached to them, from another plugin which is supposed to replace the body HTML, so I can call the destructor function?
I was thinking to store each plugin instance inside a global array, then I can access that array from any plugin. But maybe there is a better way that doesn't use the global state?
I don't think there is a ready made method for it... but as a hack you can add a class to the target elements in your plugin and then use that class to get all elements with the widget initialized lke
$.fn.plugin = function(){
this.addClass('my-plugin-class');
}
then to initialize
$(element).plugin()
to get all elements with the plugin
$('.my-plugin-class')....
But if it is a jQuery UI widget then you can use the selector $(':ui-widgetname'), see this answer
Arun P Johny wrote the rigth idea -- just delete 'footprint' of your job by marking the affected DOM elements with some specific class name.
I want just add an idea. Plugins are the methods of the library and nothing more. If you need the destroyer for constructor -- just make another plugin for it:
$.fn.overture = function (){...};// construct
$.fn.crescendo = function (){...};// more construct
$.fn.quietFarewell = function (){...};// destructor for everything above
$(...).overture().crescendo().quietFarewell();

jQuery: Get original selector

I'm in the middle of writing a plugin and I'd like to be able to get the original selector that jQuery used to create the object.
So if you wanted to apply something like .siblings() you could get all the siblings of that type, whether it looks up siblings of a certain class or siblings of a certain element type.
jQuery('div') – 'div'
jQuery(jQuery('div')) – '[jQuery] object' // would require recursively finding the selector of this
jQuery('#elment') – '#element'
jQuery('.class') – '.class'
Just access the jQuery object's selector property:
console.log($("div").selector); // 'div'
console.log($("#foo").selector); // '#foo'
This no longer seems possible... '.selector' was removed in version 3 and jquery instead recommends passing in the selector twice.
https://api.jquery.com/selector/....
The .selector property was deprecated in jQuery 1.7 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version. The property was never a reliable indicator of the selector that could be used to obtain the set of elements currently contained in the jQuery set where it was a property, since subsequent traversal methods may have changed the set. Plugins that need to use a selector string within their plugin can require it as a parameter of the method. For example, a "foo" plugin could be written as $.fn.foo = function( selector, options ) { /* plugin code goes here */ };, and the person using the plugin would write $( "div.bar" ).foo( "div.bar", {dog: "bark"} ); with the "div.bar" selector repeated as the first argument of .foo().
As an extension to what Karim has put:
var t = jQuery('.clName');
t.each(function(){
jQuery(this).data('selector',t.selector);
});

Wrapping a DOM element inside a JavaScript object

I've noticed a common pattern in the JavaScript I've been writing and was wondering if there is already a pattern out there that defines something similar as best practice? Essentially, it's how to get a DOM element and wrap it inside / associate it with a JavaScript object. Take this example, where you need a filter in your web app. Your page looks like this:
<html>
<head></head>
<body>
<div id="filter"></div>
</body>
</html>
You'd then wrap the element like so:
var myFilter = new Filter({
elem: document.getElementById('filter'),
prop: 'stacks-test',
someCallback: function() {
// specify a callback
}
});
And the JavaScript (where spec is an object passed to the constructor):
var Filter = function(spec) {
this.elem = spec.elem;
this.prop = spec.prop;
this.callback = spec.someCallback;
this.bindEvents();
};
Filter.prototype.bindEvents = function() {
var self = this;
$(this.elem).click(function(e) {
self.updateFeed();
};
};
Filter.prototype.updateFeed = function() {
this.prop; // 'stacks-test'
this.callback();
// ...
// code to interact with other JavaScript objects
// who in turn, update the document
};
What is this kind of approach called, and what are the best practices and caveats?
You might be interested in Dojo's widget library, Dijit - if I'm understanding your question correctly, it essentially does what you're asking, and a whole lot more.
In Dijit, a widget essentially encapsulates a DOM node, its contents, any JavaScript that defines its behavior, and (imported separately) CSS to style its appearance.
Widgets have their own lifecycle, registry, and events (including many which simply map to DOM events on a node within the widget, e.g. myWidget.onClick could effectively call myWidget.domNode.onclick).
Widgets can (but don't have to) have their initial contents defined in a separate HTML template file, through which it's also possible to bind events on nodes within the template to widget methods, as well as set properties on the widget that reference particular nodes in the template.
I'm barely scratching the surface here. If you want to read more on this, you can start with these reference pages:
http://dojotoolkit.org/reference-guide/dijit/info.html
http://dojotoolkit.org/reference-guide/dijit/_Widget.html (the base that all widgets extend)
http://dojotoolkit.org/reference-guide/dijit/_Templated.html (RE the HTML templating)
http://dojotoolkit.org/reference-guide/quickstart/writingWidgets.html (useful information when starting to write your own widgets)
http://dojotoolkit.org/reference-guide/dijit/ (for a bunch more info)
All said, I don't know what you're ultimately aiming for, and maybe this is all a bit much for your purposes (considering I'm throwing an entire other library at you), but figured it might pique your interest at least.
Continuing from my comment on the question, jQuery is a potential tool for the job, as it already provides some of the foundations for what you're after. However, having said that, it does introduce complexities of its own, and further, not all "jQuery ways" are equal. I'll suggest one way of using jQuery as your "object model", but it may or may not suit your needs.
First things first. The philosophy of jQuery is that you start everything by selecting the element first, using $(), or equivalently jQuery(). All operations conceptually begin with this. This is a slightly different way of thinking compared to creating an object that wraps an element and keeping a reference to that wrapper, but essentially this is what jQuery does for you. A call to $('#some-id') grabs the element with id of "some-id" and wraps it in a jQuery object.
One way: Write "Filter" plugins.
Replace your constructor with a initFilter() jQuery method. You can do this by modifying the jQuery prototype and using the jQuery object as your wrapper. jQuery's prototype is referenced by jQuery.fn, so:
jQuery.fn.initFilter = function (prop, callback) {
// Save prop and callback
this.data('filter-prop', prop);
this.data('filter-callback', callback);
// Bind events (makes sense to do this during init)
this.click(function () {
$(this).updateFeed();
});
};
Then do a similar thing for updateFeed():
jQuery.fn.updateFeed = function () {
this.data('filter-prop');
this.data('filter-callback')();
});
And use it like this:
$('#filter').initFilter(prop, callback);
Note that updateFeed can simply be in-lined into the click handler to prevent unnecessary pollution of the jQuery namespace. However, one advantage of using jQuery like this is that you do not need to keep a reference to the object if you need to invoke some function on it later, since jQuery ties all references to actual elements. If you'd like to call updateFeed programmatically, then:
$('#filter').updateFeed();
will then be invoked on the correct object.
Some things to consider
There are certainly downsides to this method. One is that all properties, which we've saved against the element using .data(), are shared between all jQuery functions that act on that element. I've attempted to alleviate this by prefixing the property names with "filter-", but depending on the complexity of your object(s), this may not be suitable.
Further, this exact method may not be so suitable for objects that require a lot of manipulation (i.e. objects with many functions) since all of these functions become common to all jQuery objects. There are ways to encapsulate all this which I won't go into here, but jQuery-ui does this with their widgets, and I'm experimenting with yet another alternative in a library I'm creating.
However, pulling back a bit, the only reason I suggested using jQuery in the first place is that your Filter object appears to be heavily tied to the DOM. It binds events to the DOM, it modifies the DOM based on user interaction, basically it appears to live in the DOM, so use something DOM-based, i.e. jQuery.

What is the correct way to store data in the DOM

I have recently been using the title tag in various HTML elements to store data in JSON format in the DOM.
Is this a bad approach (I am assuming it is)? What is the correct way to accomplish this that works well with jQuery? By "works well" I mean
$("myButton").click(function (e) {
var myData;
eval("myData=" + $(this).attr("title"));
});
Works pretty well but again I am assuming there is a better way to do this no?
PS: BTW how does the title tag of HTML elements actually work? I cant seem to find where it actually ends up getting used?
PSS: Can I also get a jQuery based and Non jQuery response? (Sorry to be fussy)
eval("myData=" + $(this).attr("title"));
This is almost a legal reason to slap you! (j/k)
You should use your own namespace object to store data "globally". In that context, globally means only global in your application code and not using the global object (window in a browser).
var my_application = {};
$('myButton').click(function() {
my_application.myData = $(this).attr('title');
});
This is a very basic strategy of course. In your particular case, you can also use jQuery's .data() method to attach data to a DOM node.
$('myButton').click(function() {
$.data(this, 'myData', this.title);
});
Ref.: .data(), jQuery.data()
In your example, I'd suggest doing the following which does not expose you to the security risks of 'eval':
myData = JSON.decode($(this).attr("title"));
In general it's a valid approach to holding non-secure data. You have a number of other options too:
Use JQuery's .data() methods:
myData = $this.data("foo");
In HTML5 you now can use custom data attributes (Eg "") as an attribute on any element. http://html5doctor.com/html5-custom-data-attributes/
You could use Local Storage if you know it is available. http://dev.w3.org/html5/webstorage/
You could use Backbone.js on top of Jquery to give you a more abstracted way of handling your data as Models. http://documentcloud.github.com/backbone/
use jquery data()
The jQuery.data() method allows us to
attach data of any type to DOM
elements in a way that is safe from
circular references and therefore free
from memory leaks. jQuery ensures that
the data is removed when DOM elements
are removed via jQuery methods, and
when the user leaves the page. We can
set several distinct values for a
single element and retrieve them
later:
jQuery.data(document.body, 'foo', 52);
In the jQuery world it is usually said to be a best practice to use the metadata plugin as it is an official jQuery plugin and also supports HTML5 data attributes. For more info you could look at this http://docs.jquery.com/Plugins/Metadata/metadata

Categories