JSFiddle - React, Tailwind, and code Playground
by rich_harris
HTML
<script src="http://cdn.ractivejs.org/edge/ractive.js"></script>
<main></main>
<script id='template' type='text/ractive'>
<button class='addColumn' on-click='addColumn'>+</button>
<table>
<tr>
{{#each columns}}
<th><input value='{{name}}'/></th>
{{/each}}
</tr>
{{#each rows:r}}
<tr>
{{#each columns}}
<td><input value='{{rows[r][id]}}'/></td>
{{/each}}
</tr>
{{/each}}
</table>
<button class='addRow' on-click='addRow'>+</button>
<p>JSON:</p>
<pre>{{JSON.stringify(rows,null,' ')}}</pre>
</script>
CSS
body {
font-family: 'Helvetica Neue', arial, sans-serif;
font-weight: 200;
color: #353535;
}
main {
position: relative;
padding: 0 6em 0 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
}
table {
border-collapse: collapse;
}
th, td {
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
font-weight: bold;
}
td {
border-left: 1px solid #eee;
}
td:last-child {
border-right: 1px solid #eee;
}
input {
display: block;
width: 100%;
font-family: inherit;
font-size: inherit;
font-weight: inherit;
margin: 0;
border: none;
}
.addColumn {
position: absolute;
right: 6em;
width: 2.5em;
}
JavaScript
var uid = 0;
// sample data from http://learn.ractivejs.org/list-sections/1
var xmen = [
{ name: 'Nightcrawler', realname: 'Wagner, Kurt', power: 'Teleportation', info: 'http://www.superherodb.com/Nightcrawler/10-107/' },
{ name: 'Cyclops', realname: 'Summers, Scott', power: 'Optic blast', info: 'http://www.superherodb.com/Cyclops/10-50/' },
{ name: 'Rogue', realname: 'Marie, Anna', power: 'Absorbing powers', info: 'http://www.superherodb.com/Rogue/10-831/' },
{ name: 'Wolverine', realname: 'Howlett, James', power: 'Regeneration', info: 'http://www.superherodb.com/Wolverine/10-161/' }
];
var Table = Ractive.extend({
template: '#template',
import: function ( records ) {
var columns = [], columnIdByName = {};
// first, get columns
records.forEach( function ( record ) {
Object.keys( record ).forEach( function ( name ) {
var columnId;
if ( !columnIdByName[ name ] ) {
columnId = '_' + uid++;
columnIdByName[ name ] = columnId;
columns.push({
id: columnId,
name: name,
// TODO infer type, sensible default value
type: 'string',
defaultValue: function () { return null; }
});
}
});
});
// then, create rows using column IDs as property names
rows = records.map( function ( record ) {
var row = {};
Object.keys( record ).forEach( function ( name ) {
row[ columnIdByName[ name ] ] = record[ name ];
});
return row;
});
this.set({
columns: columns,
columnIdByName: columnIdByName,
...