YUI 3 allows you to write
Y.all(".foo").removeClass("bar");
However it does not allow writing
Y.all(".foo").removeClass("bar").set("innerHTML", "baz");
It seems all the "operational" methods always terminate the call chain.
This means YUI 3 only provides half the power of chaining that jQuery provides.
Does anyone know why this is, and if there is a way around it?
It seems that because Y.all returns a list of things, after doing removeClass, an array of objects gets returned, not the Node object.
If, however, you use
Y.get("#foo").removeClass("bar").set("innerHTML", "baz");
everything works as you expect, because it's working on a single object.
Perhaps you should tell this to the YUI folks and see about reporting a bug. Maybe this is expected behavior, but I think what you want to do is way more powerful.
Oren,
Obviously you're aware of this already, but to complete this thread for those who stumble upon it later --
http://tech.groups.yahoo.com/group/ydn-javascript/message/45375
In short, this is a bug (opened by Oren) and it's being tracked here:
http://yuilibrary.com/projects/yui3/ticket/2525997
-Eric
Related
I have seen a lot of discussion regarding extending Element. As far as I can tell, these are the main issues:
It may conflict with other libraries,
It adds undocumented features to DOM routines,
It doesn’t work with legacy IE, and
It may conflict with future changes.
Given a project which references no other libraries, documents changes, and doesn’t give a damn for historical browsers:
Is there any technical reason not to extend the Element prototype. Here is an example of how this is useful:
Element.prototype.toggleAttribute=function(attribute,value) {
if(value===undefined) value=true;
if(this.hasAttribute(attribute)) this.removeAttribute(attribute);
else this.addAttribute(attribute,value);
};
I’ve seen too many comments about the evils of extending prototypes without offering a reasonable explanation.
Note 1: The above example is possibly too obvious, as toggleAttribute is the sort of method which might be added in the future. For discussion, imagine that it’s called manngoToggleAttribute.
Note 2: I have removed a test for whether the method already exists. Even if such a method already exists, it is more predictable to override it. In any case, I am assuming that the point here is that the method has not yet been defined, let alone implemented. That is the point here.
Note 3: I see that there is now a standard method called toggleAttribute which doesn’t behave exactly the same. With modification, the above would be a simple polyfill. This doesn’t change the point of the question.
Is it ok? Technically yes. Should you extend native APIs? As a rule of thumb no. Unfortunately the answer is more complex. If you are writing a large framework like Ember or Angular it may be a good idea to do so because your consumers will have Benifits if better API convenience. But if you're only doing this for yourself then the rule of thumb is no.
The reasoning is that doing so destabilizes the trust of that object. In other words by adding, changing, modifying a native object it no longer follows the well understood and documented behavior that anyone else (including your future self) will expect.
This style hides implementation that can go unnoticed. What is this new method?, Is it a secret browser thing?, what does it do?, Found a bug do I report this to Google or Microsoft now?. A bit exaggerated but the point is that the truth of an API has now changed and it is unexpected in this one off case. It makes maintainability need extra thought and understanding that would not be so if you just used your own function or wrapper object. It also makes changes harder.
Relevant post: Extending builtin natives. Evil or not?
Instead of trying to muck someone else's (or standard) code just use your own.
function toggleAttribute(el, attribute, value) {
var _value = (value == null ? true : value;
if (el.hasAttribute(attribute)) {
el.removeAttribute(attribute);
} else {
el.addAttribute(attribute, _value);
}
};
Now it is safe, composible, portable, and maintainable. Plus other developers (including your future self) won't scratch their heads confused where this magical method that is not documented in any standard or JS API came from.
Do not modify objects you don't own.
Imagine a future standard defines Element.prototype.toggleAttribute. Your code checks if it has a truthy value before assigning your function. So you could end up with the future native function, which may behave differently than what you expected.
Even more, just reading Element.prototype.toggleAttribute might call a getter, which could run some code with undesired sideways effects. For example, see what happens when you get Element.prototype.id.
You could skip the check and assign your function directly. But that could run a setter, with some undesired sideways effects, and your function wouldn't be assigned as the property.
You could use a property definition instead of a property assignment. That should be safer... unless Element.prototype has some special [[DefineOwnProperty]] internal method (e.g. is a proxy).
It might fail in lots of ways. Don't do this.
In my assessment: no
Massive overwriting Element.prototype slow down performance and can conflict with standardization, but a technical reason does not exist.
I'm using several Element.prototype custom methods.
so far so good until I observe a weird behaviour.
<!DOCTYPE html >
<html >
<body>
<script>
function doThis( ){
alert('window');
}
HTMLElement.prototype.doThis = function( ){
alert('HTMLElement.prototype');
}
</script>
<button onclick="doThis( )" >Do this</button>
</body>
</html>
when button is clicked, the prototype method is executed instead of the global one.
The browser seems to assume this.doThis() which is weird. To overcome, I have to use window.doThis() in the onclick.
It might be better if w3c can come with with diff syntax for calling native/custom methods e.g.
myElem.toggleAttribute() // call native method
myElem->toggleAttribute() // call custom method
Is there any technical reason not to extend the Element prototype.
Absolutely none!
pardon me:
ABSOLUTELY NONE!
In addition
the .__proto__, was practically an a illegal (Mozilla) prototype extension until yesterday. - Today, it's a Standard.
p.s.: You should avoid the use of if(!Element.prototype.toggleAttribute) syntax by any means, the if("toggleAttribute" in Element.prototype) will do.
I'm new to lo-dash, and wanted to know is it possible to use _.bind as $.bind and how can I accomplish this? I really want to get rid of jQuery and use something smaller...
What I need is to bind DOM events to functions
Those are two different mechanisms.
_.bind sets the this value of a function to the first parameter so that 'this' will always point to the same object in the function. I'd say it binds the scope of 'this' to the function, except that would be incorrect technically.
$.bind adds a jquery triggered event listener to a jquery wrapped element.
There are plenty of dom selection alternatives (such as zepto.js), but lodash/underscore libraries are really in addition to jquery, not in lieu of jquery.
That being said, this may not necessarily answer your question, except to say zeptoJs might be one such alternative. Again, Underscore/Lodash is not an alternative to but one or the other provides additional functionality (that in the long term will save file size.)
fwiw imho. 37k is not a valid arguments against jquery/lodash and other such tools. why?
1) If you serve your libraries from a cdn its not even a valid hit against the server.
2) These libraries help you write WAY SMALLER code.
In fact this claim sounds more like an excuse than a reason.
cheers.
So, I'm trying to improve my javascript skills and get into using objects more (and correctly), so please bear with me, here.
So, take this example: http://jsfiddle.net/rootyb/mhYbw/
Here, I have a separate method for each of the following:
Loading the ajax data
Using the loaded ajax data
Obviously, I have to wait until the load is completed before I use the data, so I'm accessing it as a callback.
As I have it now, it works. I don't like adding the initData callback directly into the loadData method, though. What if I want to load data and do something to it before I use it? What if I have more methods to run when processing the data? Chaining this way would get unreadable pretty quickly, IMO.
What's a better, more modular way of doing this?
I'd prefer something that doesn't rely on jQuery (if there even is a magical jQuery way), for the sake of learning.
(Also, I'm sure I'm doing some other things horribly in this example. Please feel free to point out other mistakes I'm making, too. I'm going through Douglas Crockford's Javascript - The Good Parts, and even for a rank amateur, it's made a lot of sense, but I still haven't wrapped my head around it all)
Thanks!
I don't see a lot that should be different. I made an updated version of the fiddle here.
A few points I have changed though:
Use the var keyword for local variables e.g., self.
Don't add a temporary state as an object's state e.g., ajaxData, since you are likely to use it only once.
Encapsulate as much as possible: Instead of calling loadData with the object ajaxURL, let the object decide from which URL it should load its data.
One last remark: Don't try to meet requirements you don't have yet, even if they might come up in the future (I'm referring to your "What if...?" questions). If you try, you will most likely find out that you either don't need that functionality, or the requirements are slightly different from what you expected them to be in the past. If you have a new requirement, you can always refactor your model to meet them. So, design for change, but not for potential change.
In an existing Backbone/jQuery/CoffeeScript app I am working on, it appears there is a function (Backbone.Collection.fetch()) called multiple times (sometimes number may vary). I think it might be a timing thing as I am doing alot of nested callbacks (like AJAX etc) and its becoming hard to debug. I should probably try to convert the code to use jQuery deferred but in the mean time, what can I do?
Just tried walking through the code in Chrome, but it appears the code is jumping here and there, maybe its processing different callbacks at the same time?
I am thinking maybe I add a console.log to every function + its arguments, but there must be a better way?
You can add a stack trace to that fetch() function, and see where it's being called from. There are a number of decent stack trace implementations for JS. I've had good success with
Eric Wendelin's version, but there are plenty of others.
With the stack trace, perhaps you can at least see what the most common paths are into that function, and that might help narrow down where to search. It might even make clear the underlying culprit.
I understand from this post, that it's an anti-pattern to modify Object's prototype in JavaScript. I was curious, however, if it's widely considered to be an antipattern to modify other 'built-in' prototypes.
For example: say we wanted to add a setPixel(x,y,color) function to CanvasRenderingContext2D - to abstract out the duty of getting the context's image data, setting a pixel to a certain color, and putting the image data back.
CanvasRenderingContext2D.prototype.setPixel = function(x, y, color){
var imgdata = this.createImageData(1,1);
imgdata.data[0] = color.r;
imgdata.data[1] = color.g;
imgdata.data[2] = color.b;
imgdata.data[3] = color.a;
this.putImageData(imgdata,x,y);
};
I haven't tested this code, but you get the idea. Is something like this against 'best practices' ?
I wouldn't do it as it makes it hard to track what is implemented where. It also introduces the risk of two people overriding the same behavior.
Generally, if you are adding a prototype to one of the base objects in JavaScript, you should have a good reason, and there is really no reason to modify Object, since you don't know how to predict what the end result will be of that modification.
I tend to add startsWith, trim and some other functions to String, for example, as these are helper functions, just as adding some functions to Array that exists for Firefox but not IE just makes sense (such as the filter function).
So, adding to the Canvas is fine, but, what if someone is using your library, and using excanvas. Will it cause a problem?
You either may want to explore that, or document that it doesn't work for excanvas, and if you have a small test to show that, please include it, so that if later there is a new version, and your problem disappears people can verify that.
UPDATE:
You will want to do this:
if (!CanvasRenderingContext2D.setPixel) {
...
}
That way, if someone did include one by that name you will not overwrite it, but you will need to handle it gracefully.
Definitely not; if the method is related to the object in this way then it is an elegant solution.
All of these "anti-pattern" suggestions are not to be blindly adopted. No matter what they say, sometimes the best answer is to bite the bullet and go against convention to get things working. This, of course, largely depends on your scenario.
I'm reminded of a situation where days were spent re-organizing code to make the appropriate fix "the right way", when a simple GO TO would have worked great and only taken a couple of minutes to implement. In the end, a bunch of bugs were created because code was changed that did not need to be changed. Am I a fan of GO TO statements? Hell no! But if using one prevents a months worth of headaches, then there is no question.
I don't see any problem with that as long as the functionality or naming does not override what is already there. I know of some that modify the string prototype for Trim functions.
http://www.somacon.com/p355.php
What is funny, C# now has what's called an Extension Method which effectively does the same thing.
Not as itself, but the Ajax library makers might have problems if they cannot rely on the builtin types and their properties. So you could break code that relies on certain behaviour.