meteor-tabular icon indicating copy to clipboard operation
meteor-tabular copied to clipboard

Suggested way to create dynamic tabular table

Open lowi opened this issue 9 years ago • 2 comments

Here is how I solved my issue of generating a dynamic tabular:

Blaze html dynamicTabular.html

<template name="dynamicTabular">
         {{#if isTabularReady }}
               {{> tabular table=getTabular selector=selector class="table table-striped table-bordered table-condensed"}}
          {{else}}
                {{createTable}}
          {{/if}}
</template>

Client file: Blaze .js dynamicTabular.js

Template.dynamicTabular.onCreated(function () {
    this.tabular = new ReactiveDict();
  });

Template.dynamicTabular.helpers({
    isTabularReady: function() {
      var self = Template.instance();
      return self.tabular.get("tabular.isReady");
    },
    getTabular: function() {
      var self = Template.instance();
      return Tabular.tablesByName[self.tabular.get("tabular.name")];
    },
 createTable: function() {
  // here I am displaying only 1 column based on the data context of dynamicTabular
   var columns=[{data:this.data, title: this.title}];
   var selector = this.selector || {}; // use the selector passed to the data context of dynamicTabular
  var collectionName = this.collectionName; // name of the variable storing the new Mongo.Collection("")

  var tabularName = Random.id();
   var self = Template.instance();

Meteor.call("createTabular", tabularName, collectionName, columns, selector, function(err, results) {
          if (!err) {
              new Tabular.Table({
                  name: tabularName,
                  collection: eval(collectionName),
                  "lengthMenu": [[10, 25, 50, -1],[10, 25, 50, "All"]],
                  responsive: true,
                  autoWidth: true,
                  selector: function() {
                      return selector;
                  },
                  buttonContainer: '.col-sm-6:eq(0)',
                  columns: columns
              });

              self.tabular.set("tabular.name", tabularName);
              self.tabular.set("tabular.isReady", true);
          }
      });
},

Server side:

 Meteor.methods({
    "createTabular" : function(name, collectionName, columns, selector) {
        check(name, String);
        check(columns, Match.Any);
        check(selector, Match.Any);
        new Tabular.Table({
            name: name,
            collection: eval(collectionName),
            "lengthMenu": [[10, 25, 50, -1],[10, 25, 50, "All"]],
            responsive: true,
            autoWidth: true,
            selector: function() {
                return selector;
            },
            buttonContainer: '.col-sm-6:eq(0)',
            columns: columns
        });
    }
  })

Usage would be: {{> dynamicTabular data="_id" title="key" collectionName="Docs"}}

  • Should I delete the tabular on the server once the template is destroyed?

lowi avatar Dec 03 '16 11:12 lowi

Deleting on the server would help with memory. You have some pretty big security holes with this approach, though, so I would only use this approach if that Meteor method is locked down to only users you trust. At the very least, I would create a dictionary of all your collections by name and use that instead of eval since someone could very easily exploit that.

aldeed avatar Dec 06 '16 20:12 aldeed

I have added a call to delete the tabular on the server once the template is destroyed, but it doesn't feel robust as we have no guarantee of it being called (for example the user closing the browser).

I'll look into a self-cleaning mechanism on the server where the the TabularTable would self-delete when there is no more subscribers.

As for the eval, it was a proof of concept to pass the collection name.

lowi avatar Dec 07 '16 07:12 lowi