Wednesday, October 17, 2012
safety second - encoding URLs
Just a note to my future self: you need to be not so blasé about building and then encoding URLs. And you can't just use javascript's encodeURI()on the whole thing, things like & will all be escaped inside of it. Instead, use encodeURIComponent() on the separate bits of it.
Again, kind of no-brainer but I got a slightly singed by it this week.
Friday, October 12, 2012
safety first with "global" javascript variables
This might be a "well duh!" for some of my audience, and I admit my need for this indicates some underengineering in my company's javascript component structure, but sometimes it's useful to pass information into one of our embedded components from the enclosing page via a global variable. ("Gasp!")
For a long time we were making this harder than it needed to be, because if you plan to have the page set something like
var global_hideFooter = true;
and then later do something in a component function like
if(global_hideFooter) { //do something
}
it will break badly if called from another page that didn't set global_hideFooter one way or the other-- all the code in that block after the call to the non-existent variable will not be run.
However, if we realize that when you set a global in a browser (either by something like "var foo=" outside of any scope, or just start setting "foo =" anywhere) it gets implicitly included as a key/value on the "window" object. That means we can safely do
if(window.global_hideFooter) { //do something
}
and it won't break if a page doesn't set it (and handily, in this case an unset value would act like false in a boolean context... defaults to false is a pretty natural coding paradigm.)
For a long time we were making this harder than it needed to be, because if you plan to have the page set something like
var global_hideFooter = true;
and then later do something in a component function like
if(global_hideFooter) { //do something
}
it will break badly if called from another page that didn't set global_hideFooter one way or the other-- all the code in that block after the call to the non-existent variable will not be run.
However, if we realize that when you set a global in a browser (either by something like "var foo=" outside of any scope, or just start setting "foo =" anywhere) it gets implicitly included as a key/value on the "window" object. That means we can safely do
if(window.global_hideFooter) { //do something
}
and it won't break if a page doesn't set it (and handily, in this case an unset value would act like false in a boolean context... defaults to false is a pretty natural coding paradigm.)
Tuesday, October 9, 2012
jquery data
Like I've written about previously, Javascript scoping can be tough to wrap your head around, and in general I try to avoid situations where I have to use CreateDelegate in order to have the context I'd "expect", especially during a click or similar event.
Yesterday I realized I had been forgetting about a very powerful tool in the anti-CreateDelegate, let-DOM-objects-carry-the-context-they-need front: jQuery's ".data()" function. This little beauty lets a developer put key/value pairs "into" the DOM object for easy retrieval later.
Here's a version of some broken code I made yesterday:
for(var i = 0; i < data.length;i++){
var jqo = $(".templateWrapper .modelTile").clone(true);
var foo = data[i].value;
jqo.click(function(){
alert.text(foo);
});
$("#container").append(jqo);
}
The problem was because of the scoping, the text being alert()d was whatever the last value of foo had been, for all the tile objects.
I knew I could make use CreateDelegate object to carry the context, but that seems slightly less robust. Instead, I went back to use the .data() function:
for(var i = 0; i < data.length;i++){
var jqo = $(".templateWrapper .modelTile").clone(true);
jqo.data("val", data[i].value);
jqo.click(function(){
alert.text($(this).data("val"););
});
$("#container").append(jqo);
}
That worked and felt great! I'm not sure why I've been shy about using the .data() function; it's easier than CreateDelegate and less hacky than hidden form elements or rereading the content of visible DOM objects.
Yesterday I realized I had been forgetting about a very powerful tool in the anti-CreateDelegate, let-DOM-objects-carry-the-context-they-need front: jQuery's ".data()" function. This little beauty lets a developer put key/value pairs "into" the DOM object for easy retrieval later.
Here's a version of some broken code I made yesterday:
for(var i = 0; i < data.length;i++){
var jqo = $(".templateWrapper .modelTile").clone(true);
var foo = data[i].value;
jqo.click(function(){
alert.text(foo);
});
$("#container").append(jqo);
}
The problem was because of the scoping, the text being alert()d was whatever the last value of foo had been, for all the tile objects.
I knew I could make use CreateDelegate object to carry the context, but that seems slightly less robust. Instead, I went back to use the .data() function:
for(var i = 0; i < data.length;i++){
var jqo = $(".templateWrapper .modelTile").clone(true);
jqo.data("val", data[i].value);
jqo.click(function(){
alert.text($(this).data("val"););
});
$("#container").append(jqo);
}
That worked and felt great! I'm not sure why I've been shy about using the .data() function; it's easier than CreateDelegate and less hacky than hidden form elements or rereading the content of visible DOM objects.
Subscribe to:
Posts (Atom)