flatiron / plates

Light-weight, logic-less, DSL-free, templates for all javascript environments!
MIT License
831 stars 69 forks source link

Partials / Nested Templates #4

Closed appinsanity closed 12 years ago

appinsanity commented 12 years ago

On the server side you still need JSDOM to implement partials, since partials are needed in most real-world cases, they should probably be part of the server side light weight DOM implementation.

I have been working on something very similar to plates for some time and have some suggestions on how this can be done without any special template syntax. I'm on #nodejitsu IRC if you want to discuss.

Thanks,

Mike

mwawrusch commented 12 years ago

Not sure if nested templates are the way to go as they might complicate things, but if you plan to add them consider the following syntax (using data-bind here because it makes it obvious):

< ul data-bind="rows">< li>

....

and a json similar to { "rows": [ {"name":"Frank"},{"name" : "jones"}}

Second idea: invoke a callback whenever you hit a data bindable attribute with the ability to write additional text into the output stream. This way one could fetch partials easy.

Keeping it simple and easily understandable needs to be the primary goal.

mwawrusch commented 12 years ago

Thought about this a bit more. Another idea could be to start with a html file that represents full page content with all states as a designer might deliver (some wishful thinking here). A second package, which basically uses plate's parser would parse that template and look for data-template="mysubtemplatename" tags and extract the sub templates for later use with plates

This way the template itself would be WYSIWIG but easily plateable and the sub templates could be handled programmatically. There would be a tiny overhead as the template needs to be parsed an additional time on startup (hence an extra package) but I think it would have minimal performance impact.

Edit: Actually I think there would be zero overhead. I really think this approach should be considered.

appinsanity commented 12 years ago

I like the idea of callbacks, will play with this in my test implementation.

In my test I have also been experimenting with a two stage render process where raw JS can manipulate the template(s) after the parse and before the bind. The idea of a callback might eliminate the need for this. I won't get into all the reasons right now, but I have given this problem much thought, partials is a tough area and to date I really don't like any of the solutions out there.

appinsanity commented 12 years ago

Some of what I am working on may be beyond the scope of plates so this is just food for thought, below is a mock of a json doc that allows flexible nesting/partials. This is by no means a "complete" solution I am working this from the outside in with real world and somewhat complex requirements. after this doc is parsed, and before any templates or data are loaded, the presenter, controller or whatever it's called, can alter the data below, for example, this drives a site wide page template, and when viewing a blog post you could remove the "links" template from the sidebar and update the page title.

Not saying this should be part of plates, it's just one example of handling nesting.

var html_data = 
{
    head: {
        title: 'Page Title'
    },
    body: {
        header: [
            { data:'banner.json', view:'banner.html' },
            { data:'menu.json', view:'menu.html' }
        ],
        content: [
            // which comes first the chicken or the egg, callbacks could be useful here
            { data:'/Blog/A-Blog-Post.json', view:'blogPost.html' }
        ],
        sidebar: [
            { data:'links.json', view:'link-list.html' },
            { data:'tags.json', view:'tag-cloud.html' }
        ],
        footer: [
            { data:'footer.json', view:'footer.html' },
        ],
    }
}
mwawrusch commented 12 years ago

I think something like this can be easily implemented outside of plates and then drive plates based on the json file. that combined with my proposed data-template syntax could be very strong but still supereasy to use.

appinsanity commented 12 years ago

mwawrush, great to brainstorm this with you, been working hard on this problem for many months now and when I saw flatiron I was like oh cool, the ninjas are on it...

<div data-bind="post">
    <h2 data-bind="title"></h2>
    <span data-bind="bodyHtml"></span>
    <p data-bind="fullName"></p>
</div>

<script>
var post = {
    title: 'Post Title',
    author : {
        firstName: 'First',
        lastName: 'Last'
    }
    body: [
        { view: 'paragraph.html', data: { text: 'Paragraph 1 Text' } },
        { view: 'paragraph.html', data: { text: 'Paragraph 2 Text' } },
        { view: 'paragraph.html', data: { text: 'Paragraph 3 Text' } }
    ]
}

// yes i'm mixing validation into the prototype but that would still be the responsibility 
// of the validation layer we are just sharing the prototype, several ways to implement
var TEXT { type:'text', max:255 }
var DATETIME { type:'date' }

// prototype for all posts loaded and cached by plates and the validation layer in flatiron
var post_prototype {

    title: TEXT,
    published: DATETIME,
    author: {
        firstName: TEXT,
        lastName: TEXT,
        fullName: { valueOf: function() { return this.firstName + ' ' + this.lastName; } }
    },
    body: HTML,

    // partials / nesting I kinda like this because there is no need to alter plates to support partials
    bodyHtml: { 
        valueOf: function() {  
            for (var item in this.body) {
                plates.render(item.view, item.data);
            }
        }
    }

    // no need for dot notation, this kinda smells but it keeps the data context intact
    // valueOf could also be injected during the prototype parse and cached so you only need to declare the function
    fullName: { valueOf: function() { return this.author.fullName; } }
}
</script>
heapwolf commented 12 years ago

@mwawrusch you had some really good ideas on this. Did you still want to add these ideas to the readme or wiki?

DavidSouther commented 12 years ago

Any progress on this? I've been doing it casually for a couple years, and am working on getting an actual templating engine around it. Preliminary tests on JSfiddle blow the pants off moustache etc and the code is gorgeous as hell.

See tests in https://github.com/DavidSouther/JEFRi/tree/master/js/templates for samples.

3rd-Eden commented 12 years ago

@DavidSouther I have been working on an API for using partials in Plates. I have added an append() method to the Plates.Map which allows you to use partials like this:

var map = Plates.Map();
var partial = Plates.Map();

partial.class('trolling').to('boink');
map.class('insert').append('<div class="trolling"></div>', { boink: 'moo' }, partial);

Plates.bind(html, data, map);

You can see the full progress at https://github.com/flatiron/plates/tree/manipulation

3rd-Eden commented 12 years ago

Landed in master, closing this.