In the Mootools docs, regarding Element, I cannot catch the semantic area of the document element, for which I cannot find any reference in the Mootools Api. Is it just DOM Api?
For example $ accepts three parameters, the first of them is element. How do I define an element?
Further, the docs offer some advice: document.getElementById(‘foo’), document.id(‘foo’), $(‘foo’). So I understand document is a pretty important part of Mootools, but I do not understand where it overlaps to the classic DOM API, how far it is extended and so on.
So, MooTools has the concept of Types. Types are hashes built on top of either custom objects or by extending prototypes of Natives (Array, Element, String, Function, Number, to name a few) or appending methods to Natives (Date, Object).
The Element Type (http://mootools.net/core/docs/1.5.1/Element/Element) is the abstraction around HTMLElement as well as sub types like HTMLInputElement, all part of the DOM interface.
document itself is inheriting from Element to a degree - prototype methods available on any HTMLElement will be available to call on document as well, though they may not always be applicable. For example, addEvent will work and makes sense but tween or show etc won't.
Let's assume you mean document.id
Extending natives is considered harmful because it can result in unwanted side effects. Additionally, not every browser exposes the HTMLElement prototype for modification equally. Whereas in evergreen browsers (read, not IE 8 and lower), HTMLElement is OK to change, in IE6-7 it was not (read-only) and in IE8, it only extends some types of elements whereas others have no link to the augmented prototype chain.
So, imagine you have this:
<div id="foo">foo</div>
and a corresponding object:
var foo = document.getElementById('foo');
Since the constructor of foo is Element and the prototype of foo is Element.prototype, if you called foo.addEvent it will look up the chain, reach the Element.prototype.addEvent method and call it.
But because of IE6,7,8, the above may not work well or at all - MooTools devs chose a radical way of beating this issue by doing something simple: shortening the scope of the property lookup chain in these browsers.
This is done by actually setting a reference on the foo object itself pointing to all the methods and properties on the Element.prototype object.
you can think of doing it this way:
foo.addEvent = Element.prototype.addEvent.bind(foo);
so even if foo does not have access to the proto chain, it will still be able to call the method.
This so called 'extending' takes place the first time MooTools passes an element object.
So, in our case if in IE, you'd do:
foo = $(foo); // or document.id(foo);
Upon passing the element, it gets decorated with the references of the methods that you can now call
here's a better example:
var foo = document.getElementById('foo'), bar;
console.log(foo.hasOwnProperty('addEvent')); // false in all browsers
try {
foo.addEvent('click', bar = function(){});
}
catch(e){
console.log(e);
foo = $(foo);
foo.addEvent('click', bar = function(){});
console.log(foo.hasOwnProperty('addEvent')); // true in IE6,7,8
}
// by now it's already extended, so we can safely call it.
foo.removeEvent('click', bar);
further more: not only does document.id (which $ will alias to) enable proto methods use, it also sets up a Slick.uuid to recognise the element, which is then used to enable Element Storage via the data API (Element.prototype.store/retrieve/eliminate). This way, the Storage object has a unique key that maps to exactly one element in the DOM so you can stick stuff on there - it's the same implementation as jQuery's .data API.
FINALLY, document.getElementById is just JS api that gets you an element object. that's untouched by MooTools.
TL;DR; document.id(mixed) prepares elements for use with MooTools in a cross browser way and sets up storage.
Passing an element extends and returns the element object. Passing a string finds an element by ID if possible, then extends result and returns object.
You can also use new Element() constructor to create an element on document.createElement - as well as any HTMLElement you may have gotten from any QSA or DOM API.
Related
I need to know how to make something like a jQuery function, not with the CSS selectors, just like this:
function getId( item ) {
return document.getElementById( item );
}
getId('elementID').firstFunction('property').secondFunction('property');
but I don't know how exactly do I send getId result to firstFunction to make something to the getId() element and then make the secondFunction work, I've been trying with prototype but I can't make it work.
You just need to ensure that all of your methods that you want to be able to chain accept the same context as they output, in your case a DOM element.
So, firstFunction and secondFunction should both expect this to be a DOM element and should return the DOM element as well. This means, however, they you will need to modify the built in DOM element object and add your own methods, which is generally a bad idea. This is why jQuery wraps everything in a wrapper object that contains the methods available as an API. Those methods all act on this (which must be of the same special object type) and return a (usually modified) object of the same type.
Check out a lighter-weight example here: http://buildingwebapps.blogspot.com/2012/01/creating-lightweight-dom-javascript.html and some additional reading here: http://kendsnyder.com/posts/element-wrappers-in-javascript
What's the difference between:
$(this.el).html
and
this.$el.html
Reading a few backbone examples and some do it one way and other another way.
$(this.el) wraps an element with jQuery (or Zepto). So, if your view HTML was this:
<div id="myViewElement"></div>
...and this.el referenced that div, then $(this.el) would be the equivalent of retrieving it directly via jQuery: $('#myViewElement').
this.$el is a cached reference to the jQuery (or Zepto) object, so a copy of what you would get from calling $(this.el). The intent is to save you the need to call $(this.el), which may have some overhead and therefor performance concerns.
Please note: the two are NOT equivalent. this.el alone is a reference to a host object HTMLElement -- no libraries involved. This is the return of document.getElementById. $(this.el) creates a new instance of the jQuery/Zepto object. this.$el references a single instance of the former object. It is not "wrong" to use any of them, as long as you understand the costs of multiple calls to $(this.el).
In code:
this.ele = document.getElementById('myViewElement');
this.$ele = $('#myViewElement');
$('#myViewElement') == $(this.ele);
Also, it is worth mentioning that jQuery and Zepto have partial internal caches, so extra calls to $(this.el) might end up returning a cached result anyway, and that's why I say "may have performance concerns". It also may not.
Documentation
view.$el - http://backbonejs.org/#View-$el
$ in backbone - http://backbonejs.org/#View-dollar
jQuery base object - http://api.jquery.com/jQuery/
Zepto base object - http://zeptojs.com/#$()
The two are essentially* equivalent, with $el being a cached version of the jQuery or Zepto objects el, the reason why you see examples using $(this.el) is because it was only added in a later release of backbone.js (0.9.0).
*Technically as Chris Baker points out $(this.el) will (probably) create a new jQuery/Zepto object each time you call it while this.$el will reference the same one each time.
If $el exists on this and is a jQuery object, you shouldn't use $(this.el) because it would be initializing a new jQuery object when one already exists.
They yield exactly the same thing; that is, a reference to a view's element. $el is simply a jquery wrapper for $(this.el). Look at this reference: http://documentcloud.github.com/backbone/#View-$el
I usually see this:
var markup = $(this).html();
$(this).html('<strong>whoo hoo</strong>');
I agree with Raminon. Your examples you've seen look wrong.
This code is typically seen within a jquery loop, such as each(), or an event handler. Inside the loop, the 'el' variable will point to the pure element, not a jQuery object. The same holds true for 'this' inside an event handler.
When you see the following: $(el) or $(this), the author is getting a jQuery reference to the dom object.
Here's an example I just used to convert numbers to roman numerials:
(Note, I always use jQuery instead of $ -- too many collisions with mootools...)
jQuery(document).ready(function(){
jQuery('.rom_num').each(function(idx,el){
var span = jQuery(el);
span.html(toRoman(span.text()));
});
});
Wrapping an element in $() appends the jQuery extensions to the object prototype. Once that's done it doesn't need to be done again, although there's no harm other than performance in doing it multiple times.
HI Guys, I have a question,
Im trying fo find the most efficient way in terms of performance to store and access an element in the javascript protoype library.
lets say I dynamically create a parent with an child element in a test class
testclass = Class.create({
newParent: null, //I will create a global reference to the parent element
method1: function(){
this.newParent = new Element('div',{'id':'newParent'});
var elm = new Element('div',
{
'id': 'elm1',
'identifier': 'elm1identifier'
}
);
newParent.insert(elm);
},
method2: function(){
??????????
}
})
In method 2, I want to be able to access the element elm1.
I have been thinking, and here are my different solution.
I can access the element using the utility method provided by prototype $()
method2: function(){
$('elm1');
}
I can make a global reference to the element.
elm1: null,
....
method2: function(){
this.elm1
}
3.I can pass the element in the method as a parameter but this option will not always be available
I create a unique identifier as an attribute and use the protoype .down function
this.newParent.down('[identifier=elm1identifier]');
So ofcourse i use a combination of these, but im curious, at out of all the methods, which is the most efficient in terms of performance.
I heard that the $() utility method searches the whole dom? Is this a significant difference? What if you have alot of elements.
Storing references to elements may also cause memory problems especially if you have a lot of javascript in a big web site.
using a unique and custom identifier is also nice, but you also add new attributes which might have an effect on the dom itself. But this advantage is that you specifiy where you want to search using the element.down() method in prototype.
Thanks for the help guys.
If you are creating an object that is supposed to represent a DOM element, it seems sensible to give it a property that references the element, say "element". Then in method1:
this.element = elm;
I think at this stage, micro-optimising for performance is pointless since the biggest improvement in performance would be to not use Prototype.js.
The $() method is firstly an alias for document.getElementById (which is blazingly fast in browsers and always has been) and secondly adds convenience methods to the element returned. If the browser doesn't implement a prototype based inheritance scheme, Prototpye.js adds about 50 methods directly to the element as properties, which is a pretty expensive operation.
I doubt that storing references to elements will cause significant memory issues unless you are storing tens of thousands and not using them (they are just references after all).
using a unique and custom identifier
is also nice, but you also add new
attributes which might have an effect
on the dom itself
Do not add custom attributes or properties to DOM elements. Prototype.js version 2.0 is going away from this model (at last), just don't do it. If you have an object that represents (or "wraps") an element, add the property to that.
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.
In this link: http://css-tricks.com/snippets/jquery/jquery-plugin-template/ it has a line of code that says
// Add a reverse reference to the DOM object
base.$el.data("yourPluginName", base);
what does the "reverse reference to the DOM object" mean?
Assuming that you know the jQuery data function:
It's storing a reference to the instance of the class in the data cache of jQuery, meaning that the stored instance can be used to access the initial base object if it in the current context is not available.
This way, the class instance can be used later. However, the use of the prototype keyword upon the initial class that the instance were created from will modify the instance.
EDIT:
Ooops, it seems that Anurag is right, and I was giving wrong information.
Sorry, the information I gave in initial answer was not completely correct. I've updated the answer, so it now tells the truth.
In the comments you're asking:
so you mean its storing the current state of "base" in the data cache but if we make changes to "base" later on then the one in the data wont be affected? so if for some reason we needed to get the original one again we can do data('yourPluginName') to retrieve it? can you give me an example of when this would be helpful?
It seems that none of the statements are correct.
As I did obviously not remember adequately, the thing stored in data is only a reference to the object:
var obj = {};
obj.hello = "Hello";
$("#someElement").data("object", obj);
obj.world = " world.";
alert(
obj.hello +
$("#someElement").data("object").world
); // alerts "Hello world."
BTW, JavaScript variables with names like this base-thing (but, more often seen as that or similar) are typically used to represent the current context, accessed through the this keyword, which on many occasions is more easy to store in another variable due to scoping/context changes, that will make the current context and therefore this, change.
Also due to issues with context, the stored value in data could be used to access the specific object instance from another context (that is, when this represents something else), instead of the version of the base object that was continually used after a copy of it was stored.
I hope this answered you questions :D
The technique and the problem it solves is general and not specific to jQuery plugins. There may be cases where a Javascript object corresponds to a DOM element, and wraps logic specific to that DOM element. This object might be interested in listening to events such as clicks that happen within that DOM element. The information we get in those callbacks is the element that triggered it, and not the associated object. You could use jQuery's data API or any type of map in general to retrieve the corresponding object, and do something with it.