Re: [webcomponents] Template element parser changes => Proposal for adding DocumentFragment.innerHTML

On Fri, May 11, 2012 at 12:18 AM, Ian Hickson <ian@hixie.ch> wrote:
> On Thu, 10 May 2012, Tab Atkins Jr. wrote:
>> On Thu, May 10, 2012 at 11:20 PM, Ian Hickson <ian@hixie.ch> wrote:
>> > On Thu, 10 May 2012, Tab Atkins Jr. wrote:
>> >> Still, requiring an explicit context declaration *at all* defeats
>> >> most of the purpose of the API.  Again, if we don't auto-detect SVG
>> >> (so that "<rect>" just parses as HTMLUnknownElement by default), we
>> >> haven't gained much, since authors will *still* have to wrap their
>> >> code in a regex-based detector if they expect to ever use SVG.  (An
>> >> optional context declaration that lets you determine which way the
>> >> tagname conflicts go is fine, of course.)
>> >
>> > Can you elaborate on the use case for parsing markup into a document
>> > fragment when you don't know where you'll be putting the document
>> > fragment or what kind of content is in it?
>>
>> That's pretty much exactly the description of the jQuery $("[markup goes
>> here]") functionality, which has been cited multiple times as the
>> justification for this functionality.  A previous thread about this
>> functionality was started by Yehuda Katz from jQuery about that exact
>> function, asking for this functionality.
>
> Yes, I understand that. But what's the use case?

I'll try to speak slowly and use small words.

The innerHTML API is convenient.  It lets you set the entire
descendant tree of an element, creating elements and giving them
attributes, in a single call, using the same syntax you'd use if you
were writing it in HTML (module some extra quote-escaping maybe).

That's just the contents, though.  If you create the element itself at
the same time, you can't.  To do that, you need to either use
document.createElement() and a bunch of el.setAttr() calls before
using .innerHTML on it, or figure out a container element that your
desired element can correctly be a child of, use
document.createElement() for *that*, then set innerHTML and pull out
the sole child from the container.  The first requires you to specify
the root of your fragment in a completely different and much less
convenient way from the contents.  The second requires you to know
from context what a correct container is for the root of your fragment
and specify it alongside the fragment, even though this is officially
redundant information (it's fully determined by the fragment itself,
modulo the few rare element collisions between languages).
Additionally, the string may have been constructed from multiple
sources within the program, requiring additional non-trivial effort to
keep the context information with the string and ensure it's still
correct.

The alternative, which jQuery does, is to take the latter approach,
but have the library figure out the root element for you, so you don't
have to learn, remember, and specify the name of the context every
time you want to make a fragment.  However, this is hacky and slower
than it has any need to be.

I'll go ahead and anticipate your response of "they should just use
the Element.create() API" - while Element.create() is great, it solves
a different use-case.  Being able to construct DOM from raw HTML is
easy to read and write and understand, particularly when it's a static
fragment (or a concatenation of mostly static fragments), while
Element.create() requires a translation into a JS API with a much
different syntax. Element.create() is much more readable and writable
when you're making some DOM out of a *lot* of dynamic information.

In other words, this:

$("<div class=foo><img src="+foosrc+"></div>")

is a lot easier than:

Element.create("div", {class: "foo"}, [ Element.create("img", {src: foosrc}) ]);

So, that's the use-case for this API.

~TJ

Received on Thursday, 10 May 2012 22:45:39 UTC