PDA

View Full Version : Assistant for standard load() pattern?



SteveEisner
9 Feb 2007, 2:13 PM
Jack, now that I'm deep in the YUI / ext model of development, I've seen a certain pattern emerge that I think follows from your initial example source. It's been a bit hazardous to implement so I thought I'd suggest some possible improvements to make things easier for everyone.

Since the typical "enlightened" web app now starts with raw HTML and contributes JS behaviors, we all probably have the same loop: an "App.init" call which triggers on document ready. This uses getEl() and getEls() to hook up the various on-clicks, etc. to the existing HTML.

The problem occurs when you want to make an AJAX callback to retrieve HTML, rather than JS/XML data for existing DOM elements. In this case, the HTML you've pulled in did not exist at init() time, so it arrives with no behaviors and never gets hooked up.

To fix this I've overloaded your Element.load() function with one of my own, which on successful load calls a "subset-init" function. Inside the subset init function I use el.select('...') to search within the newly loaded element and hook up the standard behaviors. And then at document init time I call that same function with document.body, so the hookup code is shared. [I also introduced a queue to prevent load() from making too many simultaneous callbacks, but that's another discussion]

There are a couple issues I've encountered (in 0.33 btw)
1) el.select('#whatever') finds #whatever even if it's not under the element. In that case, if that's executed in subset-init then it's possible for multiple handlers to be added to the same element, which will often break things. I dunno, this might be fixed by DomQuery, since I'm using cssquery.js right now in 0.33.
2) el.select('.whatever') done in the subset-init regularly returns me a doubled list. In other words, it contains (elA,elB,elC,elA,elB,elC). So again, if I do el.select('.whatever').on('click',...) I will end up attaching the same function twice. I've solved this by wrapping up a function that first does removeAllListeners() and then on(), but it might be another cssquery bug. I'll try again with DomQuery. Or this might have something to do with it being so soon after a mass DOM insertion, etc.
3) It would be nice to add this subset-init function as a property to load() and update(), to avoid having to wrap those functions (though as I said, I've wrapped it with a queue for max load requests as well. I could send you the efficient queue implementation if you want)
4) Longer term, I could see a managed handler for behaviors in which you register a series of {CSS select + event + function } and the system will make sure that any new nodes that are added will be hooked up correctly. This might apply to other things like KeyMaps, etc.

Just thought I'd throw that out there!
Thanks again for an excellent library -
Steve

Animal
10 Feb 2007, 12:13 AM
My loaded code fragments arrive with the script needed to activate them embedded.

Only the page author knows what needs to happen to activate his page, so he just adds script elements which are executed with eval()

SteveEisner
12 Feb 2007, 8:53 AM
Sure, that works. But there's a better way that it can be done - requires a little work now but Jack could eliminate that work.

My point was that in many cases, there are shared behaviors that are general to the page, not specific to the section you're loading. Sure, you'll want to send some of that from the server, but why bother if it's already in your loaded client-side JS?

Example: if you want all links of class "description" to have an on-mouseover popup, then when you reload some portion of the HTML you want that subset of the DOM to automatically hook up to the same handler you ran when the page loaded.

In practice, through several mockups and real apps in yui-ext, I've found that the list of shared behaviors is actually larger than the section-specific ones. But it doesn't matter, these two concepts work fine together and if you don't need it, you can just keep sending stuff from the server.