Git Product home page Git Product logo

plates's Introduction

plates

Synopsis

Plates (short for templates) binds data to markup. Plates has NO special syntax. It works in the browser and in Node.js.

Motivation

  • DSLs (Domain Specific Languages) such as <%=foo%> or {{foo}} reduce portability.
  • DOM templating is SLOW.
  • Promote the separation of concerns principle by decoupling decision making from presentation.
  • Make both the code and markup more readable and maintainable by a wider audience.

Status

Build Status

Features

  • Automatically bind data to a tag's body by matching unique tag IDs to data keys.

  • Bind data to a tag's body based on any attribute's values.

  • Bind data to a tag's attribute based on any attribute's values.

  • TODO: Specify option to create attribute if it does not exist.

Installation

There are a few ways to use plates. Install the library using npm. You can add it to your package.json file as a dependency, or include the script in your HTML page.

Usage

Simple case

By default, plates will try to match the key in the data to an id in the tag, since both should be unique.

var Plates = require('plates');

var html = '<div id="test">Old Value</div>';
var data = { "test": "New Value" };

var output = Plates.bind(html, data);

Explicit instructions

A common use case is to apply the new value to each tag's body based on the class attribute.

var html = '<span class="name">User</span>...<span class="name">User</span>';

var data = { "username": "John Smith" };
var map = Plates.Map();

map.class('name').to('username');

console.log(Plates.bind(html, data, map));

Complex instructions

Another common case is to replace the value of an attribute if it is a match.

var html = '<a href="/"></a>';

var data = { "newurl": "http://www.nodejitsu.com" };
var map = Plates.Map();

map.where('href').is('/').insert('newurl');

console.log(Plates.bind(html, data, map));

Partial value replacement

var html = '<a href="/foo/bar"></a>';

var data = { "newurl": "bazz" };
var map = Plates.Map();

map.where('href').has(/bar/).insert('newurl'); // `has` can take a regular expression.

console.log(Plates.bind(html, data, map));

In even more complex cases, an arbitrary attribute can be specified. If a value is matched, a specific value can be used and then used as another attribute's value.

var html = '<img data-foo="bar" src=""></img>';

var data = { "imageurl": "http://www.nodejitsu.com" };
var map = Plates.Map();

map.where('data-foo').is('bar').use('imageurl').as('src');

console.log(Plates.bind(html, data, map));

Collections

Plates can also iterate through collections:

var html = '<div class="name"></div>';
var collection = [
  {'name': 'Louis CK'},
  {'name': 'Andy Kindler'},
  {'name': 'Greg Giraldo'}
];

console.log(Plates.bind(html, collection));

Partials

Plates also supports partials:

var partial = '<li class="partial"></li>';
var base = '<div><h1 class="foo"></h1><ul class="menu"></ul></div>';

var baseData = { foo: 'bar' };
var mapping = Plates.Map();

mapping.class('menu').append(partial);
console.log(Plates.bind(base, baseData, mapping));

API

Plates Static Methods

function Plates.bind(html, data, map)
@param html {String} A string of well-formed HTML.
@param data {Object} A JSON object.
@param map {Object} An instance of `Plates.Map()`.

@return {String} The result of merging the data and html.

Map Constructor

function Plates.Map(options)
@options {Object} An object literal that contains configuration options.
  - @option where {String} The default attribute to match on instead of ID.
  - @option as {String} The default attribute to replace into.
@return {Object} An object that represents a reusable map, has mapping methods.

Map Instance Methods

where()

function Map#where(attribute)
@param attribute {String} An attribute that may be found in a tag.

This method will initiate a clause. Once a clause has been established,
other member methods may be chained to each other in any order.

class(), className()

function Map#class(attribute)
@param attribute {String} A value that may be found in the `class` attribute of a tag.

is()

function Map#is(value)
@param value {String} The value of the attribute specified in the `where` clause.

has()

function Map#has(value)
@param value {String|RegExp} The value of the attribute specified in the `where` clause.

insert()

function Map#insert(attribute)
@param attribute {String} A string that represents a key. Data will be inserted into
the attribute that was specified in the `where` clause.

use()

function Map#use(key)
@param key {String|Function} A string that represents a key in the data object that was provided or a function which returns a string value to use.

If a function is provided, it will be passed data, value and tagbody parameters.

to()

function Map#to(key)
@param key {String|Function} A string that represents a key in the data object that was provided or a function which returns a string value to use.

If a function is provided, it will be passed data, value and tagbody parameters.

Same as `use` method.

as()

function Map#as(attribute)
@param attribute {String} A string that represents an attribute in the tag.

If there is no attribute by that name found, one may be created depending on the options
that were passed to the `Map` constructor.

remove()

function Map#remove()

Removes the matching elements from the template.

append(), partial()

function Map#append(html, data, map)
@param html {String} A string that represents the new template that needs to be
added.
@param data {Mixed} data for the partial, if it's a string it's a reference to a
key in the data structure that was supplied to the main template.
@param map {Plates.Map} data mapping for the partial.

If the supplied HTML string doesn't contain any HTML markup we assume that we
the given string is the location of the template. When you are using Plates on
the browser is assumes that you supplied it with an id selector and will fetch
the innerHTML from the element. If you are using Plates in Node.js it assumes
that you gave it a file path that is relative to the current working directory.

License

(The MIT License)

Copyright (c) 2011 Arnout Kazemier, Martijn Swaagman, & the Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

plates's People

Contributors

3rd-eden avatar andreasmadsen avatar coderarity avatar cryptix avatar danhumphrey avatar dscape avatar dtrejo avatar flowonyx avatar forbeslindesay avatar heapwolf avatar indexzero avatar indutny avatar jfhbrook avatar marak avatar mmalecki avatar msabramo avatar mwawrusch avatar nhunzaker avatar pgte avatar pksunkara avatar raynos avatar robashton avatar smith avatar southern avatar tauren avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plates's Issues

Example of arrays?

Seems like a pretty common use-case where you might want to bind an array to a table or list (like a .forEach scenario), but I don't see how that would work in Plates; is there such a concept?

Having troubles with the API,docs

I am using plate.js in the browser.

If I use it the way described in the readme (changing Plate to Plates) it does not work, so I ended up with the following:

var plate = new Plates('

  • ', {
    'name': 'frank'
    });
    console.log(plate.bind());

    (gist here: https://gist.github.com/7b32c71c681e7c7a048a)

    which blows on line 189 (within the reduce function, as it tried to access the treeMap[...] [d] where treeMap[...] is undefined

    Not sure if I am using this wrong or there is a bug, but I need help with this.

    Partials / Nested Templates

    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

    Settle on a mime type for the templates when embedded in html as a script

    It is common practice to embed templates in html as script like so :

    <script id="foo" type="text/x-plates-tmpl"> Here goes all your template text..... The plates team should decide on a mime type (text/x-plates-tmpl or text/x-plates comes to mind) and put that, including the example from issue 7) on the readme. Make it simple for casual users to start without having to think.

    Attribute substitution for iterative object

    I can't find documentation or a test for this anywhere.

    I am trying to substitute a value of an object in an array as the value of an attribute(href). Not sure if it's not supported or if I just can't find how to map it

    I've tried variations along the lines of:
    map.where('href').has('id').insert('items.id')

    for the html/json in this gist:
    https://gist.github.com/2467056

    Use dom on client side

    Writing a mini-parser for server-side usage was a huge win, but I suspect that a native dom would be faster on the client.

    Adding Plates 0.4.5 to npm

    Hi,

    Just wondering if it would be possible to get the latest version of Plates (with collection support) to be added to npm.

    Just as this will make things a lil easier for may when i am deploying my stuff to no.de via git push.

    Cheers!

    support css selectors

    instead of this:

    var html = '<span class="name">User</span>...<span class="name">User</span>'
    var data = { "username": "John Smith" }
    var map = Plates.Map()
    map.class('name').to('username')
    console.log(Plates.bind(html, data, map))
    

    i want to do this:

    var html = '<span class="name">User</span>...<span id="name">User</span>'
    var data = { ".username": "John Smith", "#username": "Bob Hope" }
    console.log(Plates.bind(html, data, map))
    

    problem with nested objects

    Hi there

    I like the concept of client side template rendering and started playing with your promising lib.
    Unfortunately I get the following behavior when using this code snippet:

    https://gist.github.com/2025054

    Any comment on this? Am I doing something wrong?

    Thx in advance. cheers
    Cรฉdric

    Failing test, appears legit

    when providing both data and markup for simple template
      โœ— should merge data to markup
        ยป expected "<div id='a.b'>ok</div>\n",
    got   "<div id='a.b'></div>\n" (==) // common.js:32
    

    This is after getting other tests of the same form running fine.

    Feature: Iteration

    A common feature in template engines is the ability to iterate through an array to generate multiple lines eg. multiple script tags based on an array with filenames.

    This is missing in plates.

    Class mapping fails for unquoted class attribute

    It seems to me class mapping fails for unquoted class attributes.

    html5 does not require quoted attributes. We're in html5 now.

    Here's a printout demonstrating the issue:

    function testPlates() {
        console.log(arguments.callee.toString())
        map.class('appName').to('title')
        var o = { title: 'Boss' }
        console.log('1', plates.bind('<div class=appName></div>', o, map))
        console.log('2', plates.bind('<div class="appName"></div>', o, map))
    }
    1 <div class=appName></div>
    2 <div class="appName">Boss</div>

    case 2 works as expected
    BUG: case 1 was expected to have Boss inserted into the tags body

    1 <div class=appName>Boss</div>

    Please help me simplify this use case.

    Here is an example from my code which works with the current version of plates. I am not happy with the complexity. How can this be simplified?

    A couple of notes: I tried to map the creator object using . notation, but that did not work, so I had to resort to creating a custom view object to avoid polluting the data object.
    I tried to use class names like data-bind-name and map them to name, that would be a less intrusive version than what we have now. The reason I cannot use a 1 to 1 match (class name to name data property) is because it gets unmaintainable and undebuggable given the amount of css present. With a common name prefix I can do a text search over data-bind and find all the instances.

    Another problem was the a tag that contains two elements to be mapped, hence the data-bind-href and data-bind.

    I am reallz open for any suggestion how this could be simplified. In a perfect world I want to have a clean html and the least amount of code.

     {
     "scottyId" : "23423445546456",
     "name" : "Frank",
     "creator" : {
     "avatarUrl30" : "http:// ...."
      }
    }
    <li>
    <p class='left'>
    <a data-bind-href='linkToScotty' data-bind='name'></a>
    </p>
    <img class='tiny_person right' data-bind='creator_avatarUrl30' >
    <div class='clearfix'></div>
    </li>
      _render_scotty_ref: function(scottyRef) {
        var html, mappedData, mapping;
        html = '... see above ...';
        mappedData = {
          name: scottyRef.name,
          creator_avatarUrl30: scottyRef.creator.avatarUrl30,
          linkToScotty: window.routingController.getDesignScottyPath(scottyRef.scottyId)
        };
        mapping = {
          'name': ['data-bind'],
          'creator_avatarUrl30': ['data-bind', 'src'],
          'linkToScotty': ['data-bind-href', 'href']
        };
        return Plates.bind(html, mappedData, mapping); 
      }

    Short update: This actually does work except for the linkToScotty binding, which is not replacing my href. Which is why I am doing this temporarily:

    var $res;
    $res = $(Plates.bind(html, mappedData, mapping));
    $res.find("[data-bind-href]").each(function(idx, item) {
      $(item).attr("href", $(item).attr("data-bind-href"));
    });
    return $res;

    Exclude attribute or element if data value is falsey

    Description

    I think there needs to be a way exclude tags and attributes from the generated HTML if the data value it is mapped to is false.

    For instance, if you want to include checked="checked" from a checkbox input based on if a data value done is true or false. This is currently not possible in Plates (if it is, please show me how!).

    In addition, it would be really nice to exclude an entire HTML tag and its children if a data value is false.

    Possible Solution

    I've changed this line:

    https://github.com/tauren/plates/blob/master/lib/plates.js#L122

    To this:

     return newdata ? key + '="' + (newdata || '') + '"' : '';
    

    And it excludes the checked attribute for my simple situation, but I'm concerned it would break other scenarios. Would appreciate any feedback.

    Note that I'm unable to push changes to my Plates fork right now (I'm behind a restrictive firewall), but I can push this change tonight and submit a pull request.

    Further Details

    Consider a typical Todo app. Next to each item in the Todo list is a checkmark to indicate that the item is done. The todo list data might look like this:

    var todos = [
      {content:'item one',done:false},
      {content:'item two',done:true)
    ];
    

    The template to render might look something like this:

     <script type="text/x-plates-tmpl" id="todo">
       <div class="todo">
         <div class="display">
           <input class="check" type="checkbox" />
           <div class="todo-content"></div>
           <span class="todo-destroy"></span>
         </div>
         <div class="edit">
           <input class="todo-input" type="text" value="" />
         </div>
       </div>
    </script>
    

    The code to render the template would be similar to this:

    var html = $('script#todo').text();
    
    var data = {
      content: 'Todo item',
      done: false
    };
    
    var map = Plates.Map();
    map.class('todo-content').to('content');
    map.class('check').use('done').as('checked');
    
    console.log(Plates.bind(html, data, map));
    

    First of all, the checked attribute doesn't get added if it isn't already in the template. This means the template currently needs to include <input class="check" type="checkbox" checked="checked" />. It looks like this pull request might fix this:
    #21

    Secondly, there is currently no way to set an attribute value to anything besides a value in the data. So if done is true, then checked="true" would be generated instead of the checked="checked" that I want. I would prefer to not add extra redundant data to my model simply for the templating solution to work.

    Lastly, and most importantly, I don't see a way to enable/disable an attribute based on a data value. If done is false, I don't want any checked attribute to appear.

    I posted some of this into a gist:
    https://gist.github.com/1784972

    No collections?

    With weld, you can do something like:

    <ul class="employees">
      <li><strong class="name">John Doe</strong>: <span class="title">Salaryman</span></li>
    </ul>
    {
      "employees": [
        { "name": "Josh", "title": "engineer" },
        { "name": "Paolo", "title": "CTO" }
      ]
    }

    and have it populate the whole list:

    <ul class="employees">
      <li><strong class="name">Josh</strong>: <span class="title">engineer</span></li>
      <li><strong class="name">Paolo</strong>: <span class="title">CTO</span></li>
    </ul>

    but it seems that Plates can't do this? For example, check out this gist:

    https://gist.github.com/1707961

    When you run this, the list gets stringified and instead of what you want to see, you get [object Object],[object Object] and such.

    It's certainly possible to get around this with multiple applications of plates, as in this gist:

    https://gist.github.com/1708001

    but it feels wrong.

    So, the way I see it, this was either an intentional decision that makes Plates' complexity manageable, or it's a bug, and I'm not sure which.

    clientside global namespace pollution

    ;var Plates = (typeof process !== 'undefined' && ~process.title.indexOf('node')) ? exports : {};
    

    This checks if running in node and if yes, uses exports else it just creates a new empty object on the global namespace called Plates.
    Well I don't want this global variable, and I'm using a custom require() function to use node code on the client side. Libraries are bundled into one file, including Plates, which does not export, as process is not defined.

    Maybe you could just check for exports and or require to be defined and if yes use it, I don't want to create a process shim.

    Issues Mapping with class attributes...

    I'm trying to insert a new class into the class attribute of a tag, but the Mapping behavior doesn't quite run as expected:

    I'm using:
    map.class('home').insert('selected');

    (with data: {selected:"selected"})

    and this happens: <div class="home"></div> becomes <div class="selected"></div>

    As soon as any other class is mixed in, it fails:
    <div class="something home"></div> is skipped

    Ideally, I'd expect an "insert" action to actually insert data, instead of replacing it:
    <div class="someclass home"></div> would become <div class="someclass home selected"></div>

    Any suggestions?

    On a side note, this works the same as above:
    map.where('class').is('home').insert('selected');

    Perhaps a 'has' conditional would be appropriate?
    map.where('class').has('home').insert('selected');

    Input type="password" matching model.password with no mapping

    Given the following template:

    <script type="text/x-plates-tmpl" id="testTmpl">
      <input type="text" id="x_username" placeholder="Enter username..."/>
      <br/>
      <input type="password" id="x_password" placeholder="Enter password..."/>
    </script>
    <div id="output"></div>โ€‹

    And the following code:

    var user = {
      name: 'Sally Smith',
      username: 'sally',
      password: 'mypass'
    };
    
    var html = $('script#testTmpl').text();
    var map = Plates.Map();
    $('#output').html(Plates.bind(html, user, map));

    โ€‹
    This doesn't render properly. The value mypass is rendered after the input. The template should be rendered exactly as is without any variable replacements.

    See in action here:
    http://jsfiddle.net/tauren/HRDaD/

    Multiple list binding problem

    I am trying to bind an array of names to the entries in list A, but not to list B.

    <div>
      <ul id="A">
        <li data-bind="names"></li>
      </ul>
      <ul id="B">
        <li></li>
      </ul>
    </div>
    var data = {names: ['woody allen', 'wu tang clan']};
    map.where('data-bind').is('names').to('names');
    plates.bind(html, data, map);

    Expected output:

    <div>
      <ul id="A">
        <li data-bind="names">woody allen</li>
        <li data-bind="names">wu tang clan</li>
      </ul>
      <ul id="B">
        <li></li>
      </ul>
    </div>

    Actual output:

    <div>
      <ul id="A">
        <li data-bind="names">woody allen</li>
      </ul> 
      <ul id="B">
        <li></li>
        <li data-bind="names">wu tang clan</li>
      </ul> 
      <ul id="B">
        <li></li>
      </ul>
      <ul id="B">
        <li></li>
      </ul>
    </div>

    If I remove list B, the data gets bound to list A properly. Any thoughts on what is happening?

    Thanks

    Does not overwrite "placeholder" values

    While writing a tool, I had the following template:

    <h2><span class="logo">DNS<small>lookup</small></span> HAS LOCATED THE SUSPECT'S IP ADDRESS.</h2>
    
    <h2><strong>IP Address For <span id="domain">domain</span>:</strong> <span id="ipaddress">127.0.0.1</span></h2>

    with the "plates" bind step looking like:

    res.end( (new Plate(templates['caught'], {
      "ipaddress": ip,
      "domain": domain
    })).bind() );

    The output looks like this:

    <h2><span class="logo">DNS<small>lookup</small></span> HAS LOCATED THE SUSPECT'S IP ADDRESS.</h2>
    <h2><strong>IP Address For <span id="domain">this.isadomain.comdomain</span>:</strong> <span id="ipaddress">192.168.0.1127.0.0.1</span></h2>

    In other words, it simply concats the new value to the beginning of the existing values instead of overwriting it.

    Trim all whitespace from tests

    Just a small request. Vows in the terminal is an absolute pain to troubleshoot when there's a ton of whitespace/newline characters in the output. Would it be too much trouble in the future to strip all all whitespace from these elements?

    Readme Needs updating

    Would love to do it myself, but I am way to short on time the next couple of days.

    Basically, it is Plates now, not Plate and you need to invoke it either

    tmpl = new Plates("<......")

    or

    tmpl = new Plates ("<......", { "name" : "Frank" } )

    or

    tmpl = new Plates ("<......", { "name2" : "Frank" }, {"name2" : "name"} ) // mapping might be the other way around

    and you can set data and html explicitly as well with data(...), html(..)

    to get the result you simply call tmpl.bind()

    To use it with jquery and embedded in html (for example to preprocess the html with haml, jade do something like this):

    %script{:id=>'customers_template', :type=>'text/x-plates-tmpl'}
    %ul{:'data-bind'=>'customers'}

    and load the template with $('#customers_template').text()

    Usage explanations, examples

    The usage of Plates.Map is explained well and easy to understand. But I'm actually still not sure what the standard behavior of plates is (simple usage).

    # Usage
    
    ## Simple case
    By default, `plates` will try to match the `data-key` in the data to an `ID` in the tag, since both should are uniqe.
    

    // typo at uniqe

    ```js
    var Plates = require('plates');
    
    var html = '<div id="test">Old Value</div>';
    var data = { "test": "New Value" };
    
    var output = Plates.bind(html, data); 
    ```
    

    Reading the tests, plates can do a lot more without the map. What exactly?
    I'm especially out to omit map.class("barfoo").to("foo"), as it occurs a lot and shows errors in my IDE.

    resolve . notation

    I stumbled upon the following scenario:

    { "name": "frank",
    "creator" : {
    userName : "user x",
    url: "http://...."
    }}

    And I would like to do the following:

  • ......

    resulting in

  • ...user x ....
  • whitespace after =

    This doesn't substitute names correctly because of the whitespace after class=.

    var plates = require('plates');
    
    var html = '<div class= "name"></div>';
    var collection = [
      {'name': 'Louis'}
      , {'name': 'Andy Kindler'}
      , {'name': 'Greg Giraldo'}
    ];
    console.log(plates.bind(html, collection));

    ...use('key').as('tag') not working when multiple mappings

    var plates = require('plates')

    var data = {
    first : 'john',
    last : 'smith'
    }

    var map = plates.Map();
    map.where('name').is('first').use('first').as('value');
    map.where('name').is('last').use('last').as('value');

    var html = '';

    console.log(plates.bind(html, data, map))

    OUTPUT:

    EXPECTED:

    Mixing conventions + config

    In most libraries where conventions are used, they're used as a default, on which further config can be placed.

    Either I'm missing something or this is not the case in Plates, which is mildly annoying because it means for cases like

    var model = {} // Some really cool model
    var map = Plates.Map()
                           .where('rel').is('self').use('id').as('href')
    var html = Plates.bind(template, model, map)
    

    Will result in only the rel being mapped

    Where as with the code previously

    var model = {} // Some really cool model
    var html = Plates.bind(template, model)
    

    This worked fine and all the data got mapped by class beautifully.

    I'm happy to make this change if it is agreed with.

    class is reserved

    Plates uses the reserved word class as a method of Plates.Map. This works but it causes linters to throw warnings. For instance, JSHint:

    Expected an identifier and instead saw 'class' (a reserved word). "this.mapping.class('first').to('firstName');"
    

    Perhaps it would be better to rename the method? For instance:

    Plates.Map.clazz
    Plates.Map.className
    

    There is an issue in JSHint already:

    jshint/jshint#232

    Feature-request: support data-bind-attr without verbose mapping

    The wiki docs sugest using data-bind="name" or data-bind-href="url" for clean templating, which I totally agree with ( https://github.com/flatiron/plates/wiki/Using-data-bind-for-Clean-Plating).

    However, right now it looks like to support that, you have to manually write your map for every data item -

    map.where('data-bind-href').is('url').use('url').as('href')

    It seems like either the default behavior should support the best practice, or there should be a simple way to hand the map a regex and a function such that data-bind-attr="key" will always bind attr="data[key]". If we could agree on the best approach I would be glad to take a shot at implementing.

    Support for IE7/IE8

    I just attempted to run my app that uses Plates in IE8 and it blew up. I noticed pull request #53 makes plates more compatible with ES3, so I thought Plates might work in IE8.

    Is there already support for IE7/IE8? If not, is it something that is planned? If there is support, what shims are required to make it work? My application needs to support IE7+, and I'm trying to determine how much effort will be involved to use Plates.

    I'm already using this style of accessing reserved words:

    this.mapping['class']('check').use('done').as('checked');
    

    Instead of this:

    this.mapping.class.('check').use('done').as('checked');
    

    Attribute Binding

    I agree 100% with this approach, here is a suggestion for binding attributes in a clean intuitive manner...

    1. Injecting attributes, you could use something like this:

    { 'url':'https://github.com/', title:'github' }

    add possibility to transform/map binded values

    How about adding support for calling functions on binded values ?

    I can think of having the "with" method as in:

    map.class('snippet').with(toUpper).to('val');

    or

    map.class('snippet').with(function(val) { val == null ? 'i'm not here' : val}).to('val');

    see bae1fae for an example implementation

    README's "Simple Example" is not working. Is Plates broke, or is this a bug?

    With a completely fresh project, running "npm install plates", and then running the example code of..

    var Plates = require('plates');
    
    var html = '<div id="test">Old Value</div>';
    var data = { "test": "New Value" };
    
    var output = Plates.bind(html, data);
    

    The following error is given:

    node.js:134
            throw e; // process.nextTick error, or 'error' event on first tick
            ^
    TypeError: Object #<Object> has no method 'bind'
        at Object.<anonymous> (/mnt/ws/users/leeolayvar/136705/test.js:6:21)
        at Module._compile (module.js:411:26)
        at Object..js (module.js:417:10)
        at Module.load (module.js:343:31)
        at Function._load (module.js:302:12)
        at Array.<anonymous> (module.js:430:10)
        at EventEmitter._tickCallback (node.js:126:26)
    

    Thoughts? Note that Plates also does not have the Map attribute either.

    Another nested object problem

    When dealing with a nested object, plates seems to lose track of something if the template uses higher-level data after dealing with the sub-object. I've created a test case, and a gist to illustrate: https://gist.github.com/2370943

    As you'll see, plates seems to be outputting the unprocessed template snippet, then the copy with substitutions made.

    Not a npm module

    When I run this code:

    npm install plates

    It give the error: plates' is not in the npm registry.

    Feature Request: Bind/Map to Tags

    I'd like to request the ability to bind and/or map onto tags themselves.

    A simple example would be to bind additional <link> or <script> tags into the body of the <head> element.

    Note that i am aware, in this example, that you could give <head> an id, or a class, but that just seems silly. I think it would be a perfectly reasonable use case to be able to insert data into the bodies of elements, especially for single element types such as head or body.

    Some additional thoughts..

    • Prefix, Suffix, or Replace insertion would be nice. So you could insert the data into the beginning or end of the element, or replace it's content all together.
    • Multiple Matches. When dealing with tags such as <head> or <body> you'll often run into only one, but if you try and bind data to <li>, you'll likely match many more. With that said, you should be able to resolve which match(s) you would like to bind the data to.. or all of them?

    Tags with two template remplacements fail.

    <input type="text" data-bind="name" data-bind-placeholder="placeholder"></input>

    Expected output ==>

    <input type="text" data-bind="name" data-bind-placeholder="placeholder" 
       value="Frank" placeholder="Some dude"></input>
    data = { "name" : "Frank", "placeholder" : "Some dude" };
    
    map = {"name" : ["data-bind", "value"] ,"placeholder" : ["data-bind-placeholder", "placeholder"] };

    It seems that this might have something to do with the attr regext somewhere around line 100.

    Feature request: .to(function (obj) { ... })

    It would be nice to provide some ViewModel-like mapping logic when doing an explicit map to .to. For example:

      var data = { list: [1, 2, 3, 4, 5] }
    
      var html = '<div class="length-of-list"></div>';
    
      var map = Plates.Map()
        .class('length-of-list').to(function (data) {
          return data.list.length;
        });
    
      console.log(Plates.bind(html, data, map));

    Outputs:

      '<div class="length-of-list">5</div>'

    This would save the extra step of having to create a separate object containing the length property.

    Add to existing attribute based on data value

    Plates needs a way to enhance an attribute based on a data value, not just replace it with the data value.

    For instance, in my Todo app, if a todo item is checked as done, I want to add a CSS class to the div, but I don't want to remove the existing class.

    HTML of an uncompleted item {content: 'My Todo Item', done: false}:

    <div class="todo-content">My Todo Item</div>
    

    HTML of a completed item {content: 'My Todo Item', done: true}:

    <div class="todo-content done">My Todo Item</div>
    

    I'd be happy to implement this and submit a pull request, but welcome any input or suggestions before doing so. Is there already a way to accomplish this?

    It seems like there needs to be a way to supply a Map with custom functions so we can better control the output. For instance:

    // Function to pass into Plates.Map.use()
    // It should be passed the existing attribute value and the data model
    function addClass(currentAttr, data) {
      return currentAttr.indexOf('done') === -1 ? currentAttr + ' done' : currentAttr;
    }
    
    var map = Plates.Map();
    map.class('todo-content').to('content');
    map.class('todo-content').use(addClass).as('class');
    

    The above will need more work since the use() method does not yet know which attribute it pertains to, since as('class') is chained after it. But I hope it gets the concept across.

    Bug parsing attributes with > character

    For example, binding a page with the following causes mangled html because the > character is interpreted as ending the tag:

    <span data-bind="visible: foobar > 1"></span>
    

    This is rather inconvenient in conjunction with knockout. Note that this

    Defensive semicolon

    Apologies in advance for nit-picking, but is there a specific scenario where the defensive semicolon at the beginning of plates.js is necessary?

    ;var Plates = (typeof process !== 'undefined' && typeof process.title !== 'undefined') ? exports : {};
    

    My understanding is a defensive defensive semicolon is needed before a line that starts with an open parenthesis, such as an immediately executed anonymous function:

    ;(function() {})(); 
    

    But I don't see why it would be needed before var. I'm asking because currently there is no way for plates.js to pass jshint without removing the semicolon. I requested a jshint option to be more lenient on defensive semicolons, but @antonkovalyov didn't see the reasoning either and it was understandably rejected:
    jshint/jshint#487

    If there is a good reason for it, let me know, and I'll reopen the jshint issue.

    jsdocs?

    There is jsdoc-like markup embedded inside the markdown file, but not there in the plates.js file.

    Why not?

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google โค๏ธ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.