devpunks / snuggsi

snuggsi ツ - Easy Custom Elements in ~1kB
https://snuggsi.com
MIT License
395 stars 17 forks source link

nested templates #189

Open etm opened 5 years ago

etm commented 5 years ago

I think nested template support would be useful.

<template>
  <template name="config">
     <div id="{#}">
       Item {test}
       <template name="even">
         <span>(even {self})</span>
       </template>
       <template name="odd">
         <span>(odd {self})</span>
       </template>
     </div>
  </template>
</template>

with config defined as

get config() {
   return [ { test: "One", odd: true }, { test: "Two", even: true } ] 
}

could render

<div id="0">
  Item One <span>(odd true)</span>
</div>
<div id="1">
  Item Two <span>(even true)</span>
</div>

This would allow for conditional rendering and improve flexibility ;-)

etm commented 5 years ago

my proposal is to put it in the tokenize function of Template, as shown below (js version). Its the seven lines between "CALL TEMPLATE RECURSIVE START/END". It is tested, works well and is very helpful for many of my more complicated use-cases.

I would create a pull request but i couldn't get the bin/compile script to work (on an unmodified snuggsi), and i don't fully understand your ES coding conventions.

Please consider inclusion in the next release.

var Template = function (template) {

  ...

  function tokenize (context, index) {

    var
      clone = fragment.cloneNode (true)

    typeof context != 'object'
      && ( context  = { self: context })

    context ['#'] = index

    void (new TokenList (clone))
      .bind (context)

    /****** CALL TEMPLATE RECURSIVE START ******/
    for (var tmp of clone.querySelectorAll("template")) {
      var name = tmp.getAttribute('name')                                                                                                                                     
      if (context[name]) {
        var temp = Template(tmp)
        temp.bind(context[name])
      }
    }
    /****** CALL TEMPLATE RECURSIVE END ******/

    return clone
  }

...

}
etm commented 5 years ago

Of course

get config() {
   return [ { test: "One", odd: { bar: 1 } }, { test: "Two", even: { foo: 2 } } ];
}

works as well (as expected, principle of least surprise) and yields

<div id="0">
  Item One <span>(odd 1)</span>
</div>
<div id="1">
  Item Two <span>(even 2)</span>
</div>

based on the following slightly modified template

<template>
  <template name="config">
     <div id="{#}">
       Item {test}
       <template name="even">
         <span>(even {foo})</span>
       </template>
       <template name="odd">
         <span>(odd {bar})</span>
       </template>
     </div>
  </template>
</template>
snuggs commented 5 years ago

@etm interesting as we are having same conversation over at WHATWG. Glad you provided an example. Thanks!

brandondees commented 4 years ago

I'm not sure if there are any scary implications to this, but I think the concept could be useful.

snuggs commented 4 years ago

Add reference updates to template parsing from WHATWG DOM: