Jean-François Beauchamp Jean-François Beauchamp - 5 months ago 19
JSON Question

Using Meteor, what is the proper way to make a JSON array reactive?

I am planning to use Meteor-Excel to load Excel sheets in a Meteor v1.3 app, and convert the sheet to JSON. What I would like to do is to tie the cell values to a grid of checkboxes. What is the best way to do that so that it is reactive? The UI result should be an html table of checkboxes.

Here is a sample Excel file converted to JSON using Meteor-Excel:

var myExcel = {
"Sheet1": [
{
"Rows": "Row1",
"C1": "TRUE",
"C2": "FALSE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row2",
"C1": "TRUE",
"C2": "FALSE",
"C3": "FALSE",
"C4": "FALSE"
},
{
"Rows": "Row3",
"C1": "TRUE",
"C2": "TRUE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row4",
"C1": "TRUE",
"C2": "FALSE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row5",
"C1": "TRUE",
"C2": "TRUE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row6",
"C1": "FALSE",
"C2": "TRUE",
"C3": "FALSE",
"C4": "TRUE"
},
{
"Rows": "Row7",
"C1": "FALSE",
"C2": "TRUE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row8",
"C1": "FALSE",
"C2": "FALSE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row9",
"C1": "TRUE",
"C2": "TRUE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row10",
"C1": "TRUE",
"C2": "TRUE",
"C3": "TRUE",
"C4": "TRUE"
},
{
"Rows": "Row11",
"C1": "TRUE",
"C2": "TRUE",
"C3": "FALSE",
"C4": "FALSE"
}
]
}


The templates could be something like this:

<template name="excel">
<table>
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
{{#each rows}}
{{> row}}
{{/each}}
</tbody>
</table>
</template>

<template name="row">
<tr>
<td><input type="checkbox" checked={{C1}}></td>
<td><input type="checkbox" checked={{C2}}></td>
<td><input type="checkbox" checked={{C3}}></td>
<td><input type="checkbox" checked={{C4}}></td>
</tr>
</template>


With a helper that returns the rows:

Template.excel.helpers({
'rows': function(){
return myExcel.Sheet1;
}
});


However, I am not sure what
checked
should be, and how each checkbox should be bound to the JSON in order to be reactive.

UPDATE:

In order to have my checkbox render correctly, here is what I used below.

Templates:

<template name="excel">
<table>
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
{{#each rowData in rows}}
{{> row data=rowData idx=@index}}
{{/each}}
</tbody>
</table>
</template>

<template name="row">
<tr>
<td><input type="checkbox" checked={{checked "C1"}} data-rowIndex="{{idx}}" data-column="C1"></td>
<td><input type="checkbox" checked={{checked "C2"}} data-rowIndex="{{idx}}" data-column="C2"></td>
<td><input type="checkbox" checked={{checked "C3"}} data-rowIndex="{{idx}}" data-column="C3"></td>
<td><input type="checkbox" checked={{checked "C4"}} data-rowIndex="{{idx}}" data-column="C4"></td>
</tr>
</template>


Code:

var myExcelDep = new Tracker.Dependency;

Template.excel.helpers({
'rows': function() {
myExcelDep.depend();
return myExcel.Sheet1;
}
});

Template.row.helpers({
'checked': function(column) {
return this.data[column] && this.data[column].toLowerCase() == "true" ? "checked" : false;
}
});

Template.excel.events({
'change input[type="checkbox"]': function(event) {
var x = event.target.checked;
var col = $(event.target).attr("data-column");
this.data[col] = x.toString();
myExcelDep.changed();
}
});

Answer

You can do this using a tracker dependency.

Declare a dependency in your template code:

var myExcelDep = new Tracker.dependency;

Template.excel.helpers({
    'rows': function(){
        myExcelDep.depend(); // this registers the dependency
        return myExcel.Sheet1;
    }
});

Then in your code that creates/modifies your JSON, update the dependency:

 ...
 myExcel.push(sheet2); // or any change operation
 myExcelDep.changed(); // this triggers invalidated functions to update
 ...
Comments