Code Monkey home page Code Monkey logo

meteor-tabular's Introduction

aldeed:tabular

A Meteor package that creates reactive DataTables in an efficient way, allowing you to display the contents of enormous collections without impacting app performance.

!!! MAINTAINERS WANTED !!!

Please open an issue if you like to help out with maintenance on this package.

Table of Contents

Table of Contents generated with DocToc

ATTENTION: Updating to 2.0

Version 2.0 API is backwards compatible other than the following changes:

  • Requires Meteor 1.3+
  • You must explicitly import the Tabular object into every file where you use it. (import Tabular from 'meteor/aldeed:tabular';)
  • You must configure the Bootstrap theme (or whatever theme you want) yourself. See Installing and Configuring a Theme

This version also includes a few fixes and a few new features.

Features

  • Fast: Uses an intelligent automatic data subscription so that table data is not loaded until it's needed.
  • Reactive: As your collection data changes, so does your table. You can also reactively update the query selector if you provide your own filter buttons outside of the table.
  • Customizable: Anything you can do with the DataTables library is supported, and you can provide your own publish function to build custom tables or tables than join data from two collections.
  • Hot Code Push Ready: Remains on the same data page after a hot code push.

Although this appears similar to the jquery-datatables Meteor package, there are actually many differences:

  • This package is updated to work with Meteor 1.3+.
  • This package has a much smaller codebase and includes less of the DataTables library.
  • This package allows you to specify a Blaze template as a cell's content.
  • This package handles the reactive table updates in a different way.
  • This package is designed to work with any DataTables theme

Installation

$ meteor add aldeed:tabular

Installing and Configuring a Theme

This example is for the Bootstrap theme. You can use another theme package. See https://datatables.net/download/npm

First:

$ npm install --save [email protected] datatables.net-bs

Note that we install [email protected]. This needs to match the current version of jQuery included with Meteor's jquery package. (See the version comment in https://github.com/meteor/meteor/blob/master/packages/non-core/jquery/package.js) Otherwise, due to the datatables.net package depending on jquery NPM package, it might automatically install the latest jquery version, which may conflict with Bootstrap or Meteor.

Then, somewhere in your client JavaScript:

import { $ } from 'meteor/jquery';
import dataTablesBootstrap from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';
dataTablesBootstrap(window, $);

Online Demo App

View a demonstration project on Meteorpad.

Another example app courtesy of @AnnotatedJS:

Example

Define your table in common code (code that runs in both NodeJS and browser):

import Tabular from 'meteor/aldeed:tabular';
import { Template } from 'meteor/templating';
import moment from 'moment';
import { Meteor } from 'meteor/meteor';
import { Books } from './collections/Books';

new Tabular.Table({
  name: "Books",
  collection: Books,
  columns: [
    {data: "title", title: "Title"},
    {data: "author", title: "Author"},
    {data: "copies", title: "Copies Available"},
    {
      data: "lastCheckedOut",
      title: "Last Checkout",
      render: function (val, type, doc) {
        if (val instanceof Date) {
          return moment(val).calendar();
        } else {
          return "Never";
        }
      }
    },
    {data: "summary", title: "Summary"},
    {
      tmpl: Meteor.isClient && Template.bookCheckOutCell
    }
  ]
});

And then reference in one of your templates where you want it to appear:

{{> tabular table=TabularTables.Books class="table table-striped table-bordered table-condensed"}}

The TabularTables.Books helper is automatically added, where "Books" is the name option from your table constructor.

Displaying Only Part of a Collection's Data Set

Add a Mongo-style selector to your tabular component for a table that displays only one part of a collection:

{{> tabular table=TabularTables.Books selector=selector class="table table-striped table-bordered table-condensed"}}
Template.myTemplate.helpers({
  selector() {
    return {author: "Agatha Christie"}; // this could be pulled from a Session var or something that is reactive
  }
});

If you want to limit what is published to the client for security reasons you can provide a selector in the constructor which will be used by the publications. Selectors provided this way will be combined with selectors provided to the template using an AND relationship. Both selectors may query on the same fields if necessary.

new Tabular.Table({
  // other properties...
  selector(userId) {
    return { documentOwner: userId };
  }
});

Passing Options to the DataTable

The DataTables documentation lists a huge variety of available table options and callbacks. You may add any of these to your Tabular.Table constructor options and they will be used as options when constructing the DataTable.

Example:

new Tabular.Table({
  // other properties...
  createdRow( row, data, dataIndex ) {
    // set row class based on row data
  }
});

Template Cells

You might have noticed this column definition in the example:

{
  tmpl: Meteor.isClient && Template.bookCheckOutCell
}

This is not part of the DataTables API. It's a special feature of this package. By passing a Blaze Template object, that template will be rendered in the table cell. You can include a button and/or use helpers and events.

In your template and helpers, this is set to the document for the current row by default. If you need more information in your template context, such as which column it is for a shared template, you can set tmplContext to a function which takes the row data as an argument and returns the context, like this:

{
  data: 'title',
  title: "Title",
  tmpl: Meteor.isClient && Template.sharedTemplate,
  tmplContext(rowData) {
    return {
      item: rowData,
      column: 'title'
    };
  }
}

Note: The Meteor.isClient && is there because tables must be defined in common code, which runs on the server and client. But the Template object is not defined in server code, so we need to prevent errors by setting tmpl only on the client.

The tmpl option can be used with or without the data option.

Here's an example of how you might do the bookCheckOutCell template:

HTML:

<template name="bookCheckOutCell">
  <button type="button" class="btn btn-xs check-out">Check Out</button>
</template>

Client JavaScript:

Template.bookCheckOutCell.events({
  'click .check-out': function () {
    addBookToCheckoutCart(this._id);
  }
});

Searching

If your table includes the global search/filter field, it will work and will update results in a manner that remains fast even with large collections. By default, all columns are searched if they can be. If you don't want a column to be searched, add the searchable: false option on that column.

When you enter multiple search terms separated by whitespace, they are searched with an OR condition, which matches default DataTables behavior.

If your table has a selector that already limits the results, the search happens within the selector results (i.e., your selector and the search selector are merged with an AND relationship).

Customizing Search Behavior

You can add a search object to your table options to change the default behavior. The defaults are:

{
  search: {
    caseInsensitive: true,
    smart: true,
    onEnterOnly: false,
  }
}

You can set caseInsensitive or smart to false if you prefer. See http://datatables.net/reference/option/search. The regex option is not yet supported.

onEnterOnly is custom to this package. Set it to true to run search only when the user presses ENTER in the search box, rather than on keyup. This is useful for large collections to avoid slow searching.

There are also two options to optimize searching for particular columns:

columns: [
    {
      data: '_id',
      title: 'ID',
      search: {
        isNumber: true,
        exact: true,
      },
    },
]

For each column, you can set search.isNumber to true to cast whatever is entered to a Number and search for that, and you can set search.exact to true to search only for an exact match of the search string. (This overrides the table-level caseInsensitive and smart options for this column only.)

Using Collection Helpers

The DataTables library supports calling functions on the row data by appending your data string with (). This can be used along with the dburles:collection-helpers package (or your own collection transform). For example:

Relevant part of your table definition:

columns: [
  {data: "fullName()", title: "Full Name"},
]

A collection helper you've defined in client or common code:

People.helpers({
  fullName: function () {
    return this.firstName + ' ' + this.lastName;
  }
});

Note that for this to work properly, you must ensure that the firstName and lastName fields are published. If they're included as the data for other columns, then there is no problem. If not, you can use the extraFields option or your own custom publish function.

Publishing Extra Fields

If your table's templates or helper functions require fields that are not included in the data, you can tell Tabular to publish these fields by including them in the extraFields array option:

TabularTables.People = new Tabular.Table({
  // other properties...
  extraFields: ['firstName', 'lastName']
});

Modifying the Selector

If your table requires the selector to be modified before it's published, you can modify it with the changeSelector method. This can be useful for modifying what will be returned in a search. It's called only on the server.

TabularTables.Posts = new Tabular.Table({
  // other properties...
  changeSelector(selector, userId) {
    // modify it here ...
    return selector;
  }
});

Saving state

Should you require the current state of pagination, sorting, search, etc to be saved you can use the default functionality of Datatables.

Add stateSave as a property when defining the Datatable.

TabularTables.Posts = new Tabular.Table({
  // other properties...
  stateSave: true
});

Add an ID parameter to the template include. This is used in localstorage by datatables to keep the state of your table. Without this state saving will not work.

{{> tabular table=TabularTables.Posts id="poststableid" selector=selector class="table table-striped table-bordered table-condensed"}}

Security

You can optionally provide an allow and/or allowFields function to control which clients can get the published data. These are used by the built-in publications on the server only.

TabularTables.Books = new Tabular.Table({
  // other properties...
  allow(userId) {
    return false; // don't allow this person to subscribe to the data
  },
  allowFields(userId, fields) {
    return false; // don't allow this person to subscribe to the data
  }
});

Note: Every time the table data changes, you can expect allow to be called 1 or 2 times and allowFields to be called 0 or 1 times. If the table uses your own custom publish function, then allow will be called 1 time and allowFields will never be called.

If you need to be sure that certain fields are never published or if different users can access different fields, use allowFields. Otherwise just use allow.

Caching the Documents

By default, a normal Meteor.subscribe is used for the current page's table data. This subscription is stopped and a new one replaces it whenever you switch pages. This means that if your table shows 10 results per page, your client collection will have 10 documents in it on page 1. When you switch to page 2, your client collection will still have only 10 documents in it, but they will be the next 10.

If you want to override this behavior such that documents displayed in the table remain cached on the client for some time, you can add the meteorhacks:subs-manager package to your app and set the sub option on your Tabular.Table. This can make the table a bit faster and reduce unnecessary subscription traffic, but may not be a good idea if the data is extremely sensitive.

TabularTables.Books = new Tabular.Table({
  // other properties...
  sub: new SubsManager()
});

Hooks

Currently there is only one hook provided: onUnload

Rendering a responsive table

Use these table options:

responsive: true,
autoWidth: false,

Active Datasets

If your table is showing a dataset that changes a lot, it could become unusable due to reactively updating too often. You can throttle how often a table updates with the following table option:

throttleRefresh: 5000

Set it to the number of milliseconds to wait between updates, even if the data is changing more frequently.

Using a Custom Publish Function

This package takes care of publication and subscription for you using two built-in publications. The first publication determines the list of document _ids that are needed by the table. This is a complex publication and there should be no need to override it. The second publication publishes the actual documents with those _ids.

The most common reason to override the second publication with your own custom one is to publish documents from related collections at the same time.

To tell Tabular to use your custom publish function, pass the publication name as the pub option. Your function:

  • MUST accept and check three arguments: tableName, ids, and fields
  • MUST publish all the documents where _id is in the ids array.
  • MUST do any necessary security checks
  • SHOULD publish only the fields listed in the fields object, if one is provided.
  • MAY also publish other data necessary for your table

Example

Suppose we want a table of feedback submitted by users, which is stored in an AppFeedback collection, but we also want to display the email address of the user in the table. We'll use a custom publish function along with the reywood:publish-composite package to do this. Also, we'll limit it to admins.

server/publish.js

Meteor.publishComposite("tabular_AppFeedback", function (tableName, ids, fields) {
  check(tableName, String);
  check(ids, Array);
  check(fields, Match.Optional(Object));

  this.unblock(); // requires meteorhacks:unblock package

  return {
    find: function () {
      this.unblock(); // requires meteorhacks:unblock package

      // check for admin role with alanning:roles package
      if (!Roles.userIsInRole(this.userId, 'admin')) {
        return [];
      }

      return AppFeedback.find({_id: {$in: ids}}, {fields: fields});
    },
    children: [
      {
        find: function(feedback) {
          this.unblock(); // requires meteorhacks:unblock package
          // Publish the related user
          return Meteor.users.find({_id: feedback.userId}, {limit: 1, fields: {emails: 1}, sort: {_id: 1}});
        }
      }
    ]
  };
});

common/helpers.js

// Define an email helper on AppFeedback documents using dburles:collection-helpers package.
// We'll reference this in our table columns with "email()"
AppFeedback.helpers({
  email() {
    var user = Meteor.users.findOne({_id: this.userId});
    return user && user.emails[0].address;
  }
});

common/tables.js

TabularTables.AppFeedback = new Tabular.Table({
  name: "AppFeedback",
  collection: AppFeedback,
  pub: "tabular_AppFeedback",
  allow(userId) {
    // check for admin role with alanning:roles package
    return Roles.userIsInRole(userId, 'admin');
  },
  order: [[0, "desc"]],
  columns: [
    {data: "date", title: "Date"},
    {data: "email()", title: "Email"},
    {data: "feedback", title: "Feedback"},
    {
      tmpl: Meteor.isClient && Template.appFeedbackCellDelete
    }
  ]
});

Tips

Some useful tips

Get the DataTable instance

var dt = $(theTableElement).DataTable();

Detect row clicks and get row data

Template.myTemplate.events({
  'click tbody > tr': function (event) {
    var dataTable = $(event.target).closest('table').DataTable();
    var rowData = dataTable.row(event.currentTarget).data();
    if (!rowData) return; // Won't be data if a placeholder row is clicked
    // Your click handler logic here
  }
});

Search in one column

var dt = $(theTableElement).DataTable();
var indexOfColumnToSearch = 0;
dt.column(indexOfColumnToSearch).search('search terms').draw();

Adjust column widths

By default, the DataTables library uses automatic column width calculations. If this makes some of your columns look squished, try setting the autoWidth: false option.

Turning Off Paging or Showing "All"

When using no paging or an "All" (-1) option in the page limit list, it is best to also add a hard limit in your table options like limit: 500, unless you know the collection will always be very small.

Customize the "Processing" Message

To customize the "Processing" message appearance, use CSS selector div.dataTables_wrapper div.dataTables_processing. To change or translate the text, see https://datatables.net/reference/option/language.processing

I18N Example

Before rendering the table on the client:

if (Meteor.isClient) {
	$.extend(true, $.fn.dataTable.defaults, {
		language: {
      "lengthMenu": i18n("tableDef.lengthMenu"),
      "zeroRecords": i18n("tableDef.zeroRecords"),
      "info": i18n("tableDef.info"),
      "infoEmpty": i18n("tableDef.infoEmpty"),
      "infoFiltered": i18n("tableDef.infoFiltered")
    }
	});
}

More options to translate can be found here: https://datatables.net/reference/option/language

Reactive Column Titles

You can set the titleFn column option to a function instead of supplying a string title option. This is reactively rerun as necessary.

Optimizing the Total Table Count

By default, a count of the entire available filtered dataset is done on the server. This can be slow for large datasets. You have two options that can help:

First, you can calculate total counts yourself and return them from a function provided as the alternativeCount option to your Tabular.Table:

alternativeCount: (selector) => 200,

Second, you can skip the count altogether. If you do this, we return a fake count that ensures the Next button will be available. But the fake count will not be the correct total count, so the paging info and the numbered page buttons will be misleading. To deal with this, you should use pagingType: 'simple' and either info: false or an infoCallback function that omits the total count:

skipCount: true,
pagingType: 'simple',
infoCallback: (settings, start, end) => `Showing ${start} to ${end}`,

Integrating DataTables Extensions

There are a wide variety of useful extensions for DataTables. To integrate them into Tabular, it is best to use the NPM packages.

Example: Adding Buttons

To add buttons for print, column visibility, file export, and more, you can use the DataTables buttons extension. Install the necessary packages in your app with NPM. For example, if you're using the Bootstrap theme, run:

$ npm install --save datatables.net-buttons datatables.net-buttons-bs

For package names for other themes, see https://datatables.net/download/npm

Once the packages are installed, you need to import them in one of your client JavaScript files:

import { $ } from 'meteor/jquery';

// Bootstrap Theme
import dataTablesBootstrap from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';

// Buttons Core
import dataTableButtons from 'datatables.net-buttons-bs';

// Import whichever buttons you are using
import columnVisibilityButton from 'datatables.net-buttons/js/buttons.colVis.js';
import html5ExportButtons from 'datatables.net-buttons/js/buttons.html5.js';
import flashExportButtons from 'datatables.net-buttons/js/buttons.flash.js';
import printButton from 'datatables.net-buttons/js/buttons.print.js';

// Then initialize everything you imported
dataTablesBootstrap(window, $);
dataTableButtons(window, $);
columnVisibilityButton(window, $);
html5ExportButtons(window, $);
flashExportButtons(window, $);
printButton(window, $);

Finally, for the Tabular tables that need them, add the buttons and buttonContainer options. The buttons option is part of DataTables and is documented here: https://datatables.net/extensions/buttons/ The buttonContainer option is part of aldeed:tabular and does the tricky task of appending the buttons to some element in the generated table. Set it to the CSS selector for the container.

Bootstrap example:

new Tabular.Table({
  // other properties...
  buttonContainer: '.col-sm-6:eq(0)',
  buttons: ['copy', 'excel', 'csv', 'colvis'],
});

If you are using the default DataTables theme, you can use the dom option instead of buttonContainer. See https://datatables.net/extensions/buttons/#Displaying-the-buttons

meteor-tabular's People

Contributors

adambrodzinski avatar aldeed avatar dokithonon avatar guilhermedecampo avatar hanchang avatar hockeyj85 avatar hwillson avatar ivan133 avatar jankapunkt avatar kyleking avatar leemarkwood avatar maxko87 avatar mpowaga avatar mrauhu avatar pascoual avatar ricaragao avatar serkandurusoy avatar space-alien avatar storytellercz avatar techplexengineer 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

meteor-tabular's Issues

v1.0.4 => pagination index not being reset!

similar to : #45

when viewing a table let's say you are on page 4 (Showing 31 to 40 of 51 entries) and clicking on a row triggers an event that changes the "selector" so your table no longer has 51 elements but < 10 and the pages navigation is now 1 page. the cursor stays at page 4 (Showing 31 to 4 of 4 entries) and the Table is sitting at "No matching records found" . if you then click manually on page 1 you see the intended view.

I am guessing that there are 2 possible ways to go around this. either auto select page 1 when the result set only has 1 page or reset page index when selector is changed. I think the latter may be more appropriate.

2 small issues

@aldeed Awesome work man, I discovered this package yesterday :)

I just noticed 2 small issues:

  1. Suppose we have 30 documents and we are showing 10 documents per page. Suppose we navigate to page 2 and then choose to show 100 documents per page, the documents from the first page will be missing and we will only see the rest 20 documents. (The pagination will also be showing one page, as if there were no other docs/pages to show). As a fix I suggest to always reset the cursor when the number of docs per page changes.

  2. If we set orderable:false on the _id field (data:"_id") the ordering icon appears when the table is loaded for the first time and then disappears when ordering any other column.

HTML content is not sortable

Hi There,

I have set up meteor-tabular and its working fine, but if i added the hyper linked content to a column and the sortable icon are removed from that column, could you please let me know how to add HTML content to column so that the sortable icon can work.

Thanks

Add Preloading Feature

Suggestion from #14:

Add an option such as preload: 30, which would attempt to preload data for the next pages up to 30 documents in advance.

Trouble getting examples working

I'm trying to get a stripped down version of the example working

In shared code:

Books = new Mongo.Collection("books");

TabularTables = {};

Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);

TabularTables.Books = new Tabular.Table({
  name: "BookList",
  collection: Books,
  columns: [
    {data: "title", title: "Title"},
    {data: "author", title: "Author"},
    {data: "copies", title: "Copies Available"},
  ]
});

And in the template

{{> tabular table=TabularTables.Books class="table table-striped table-bordered table-condensed"}}

But I get this error
"Error: Tabular.Table options must specify collection", but I have declared my collection in the same file. Any idea what could be going wrong?

Any ideas or clues on why the column size responsiveness of table columns would change between 0.2.3 and 1.0.0?

Any ideas or clues on why the column size responsiveness of table columns would change between 0.2.3 and 1.0.0?

It looks like with 1.0.0 the columns are trying to be equal sizes now in my app.

Only thing that has changed is the tabular package version in these two screenshots:

0.2.3: date not squished, and columns take up room depending on what they need:
tabular023

1.0.0 date is squished, and columns are taking up more room than they need
tablular100

Thank you for any insight on the matter.

iron-routes dynamic routes error

I am bothering you again. It's your fault you offered so many great tools :) Thanks, once more.
I'm stuck betwwen the JQuery of the dataTables and the Meteor part as follows:
I made a dynamic route with iron-router:

this.route("dashboardCollections", {
    path: "dashboard/:collectionPath",
    layoutTemplate: 'dashboard',
    data:function(){
         return {
        templName: "tabular",
        contextData:{
 "table":tablesByName[this.params.collectionPath.substr(0,1).toUpperCase()+this.params.collectionPath.substr(1)+"List"],
            "selector":{},
            "class":"table table-striped table-bordered table-condensed"
        }
        }
    }
    });

The path being: user, clients, brands which I get in the params and change into UserList, ClientLists and BrandsList which are exactly the names of the tabulaTables which I retrieve with tablesByName.
At this point my template looks exactly as the one in your example.

 {{> Template.dynamic template = templName data=contextData}}

What I don't understand, it's how does the dataTables keep the previous column data in the dataTables settings and doesn't update. With static route it works perfect. I'm just stubborn and I would really like to fix this dynamic routes style, which ,by the way might interest others as well.

For people requesting editable tabular forms, I put in the TabularTables.Whatever template the following code:

{
        title:"<div><a href='{{pathFor " + _INSERT_TEMPLATE_+"}}' class='btn btn-sm btn-block btn-primary'><i class='glyphicon glyphicon-log-in'></i>&nbsp;Insert</a></div>",
        tmpl: Meteor.isClient && Template.editables
    }

<template name="editables">
    <a href="_YOUR_UPDATE_TEMPLATE_ROUTE_" class="btn btn-sm btn-primary"><i class="glyphicon glyphicon-pencil"></i></a>
    <a href="_YOUR_DELETE_TEMPLATE_ROUTE_" class="btn btn-sm btn-primary"><i class="glyphicon glyphicon-remove"></i></a>
</template>

Maybe it helps someone.I know it's not SO but I couldn't stop.
Thanks again.

how to make selector dynamic

Hi,

Is there any example of making selector dynamic ?

Actually I am trying to change the select on change of dropdown .

Can anyone help me do this.

Thanks,
hare

Table on Meteor.user - search not working

Hi,

I have the following table:

if (!this.TabularTables) {
  this.TabularTables = {};
}

Meteor.isClient && Template.registerHelper("TabularTables", TabularTables);

TabularTables.Users = new Tabular.Table({
  name: "Users",
  collection: Meteor.users,
  columns: [
    {
      data: "createdAt",
      title: "CreatedAt"
    }, {
      data: "profile.firstName",
      title: "firstName"
    }, {
      data: "profile.lastName",
      title: "lastName"
    }
  ]
});

The table works awesomely fast, but as soon as I type something into the search field nothing is displayed any more.

Do you have any idea what the reason for this could be?

Cheers,
Gerwin

Publishing Too Restrictive, No Way to Override

I wanted to include my fields within the template, not as simple fields or using the renderer. For example, this way I could include a Product Info button right next to the product name, not within an adjacent cell. More importantly, I could make my template switch to an input form with a click event, making the table in-place editable (that would be hot!)

I can already do this (the input form at least, still working on the event code) if I add a duplicate column that brings the field I want into the collection, so it's clearly possible. However the publishing rules in the documentation only let you restrict further, it won't let you expand out to include more fields.

Ignores Allow function

Hey, this could be a really stupid issue - but I'm not really sure why it's not being called.

I'm trying to add a custom allow function and no matter what I put in allow it still doesn't get called. So what am I doing wrong?

Many thanks for your time, fantastic package as well. So thank you.

TabularTables.NutritionDatabase = new Tabular.Table({
  name: "NutritionDatabase",
  collection: Nutrition,
  columns: [
    {data: "name", title: "Name"},
    {data: "group", title: "Food group"},
    {data: "manufacturer", title: "Brand"},
    {tmpl: (Meteor.isClient && Template.nutrition_database_options), title: "Options", width: "50px"}
  ],
  allow: function(userId, fields) {
    return false;
  },
  order: [[0, "asc"]],
});

That is my table definition code and every time the table renders with items as normal. I've also tried to put in console.log()'s etc and they never print.

Selector reactive?

Hi ,
i dont achieve to modify the selector to add additional filters on the fly for ie;

selector: function () {
var filter = {};
var aFilters= ...
if (aFilters instanceof Array){
filter = { "myFilteredKey": { $in: aFilters} };
}
return filter;
}
It seems to work only on init.

What's wrong?

Thanks for help

how to create action field "update, remove, other link" field?

I would like to create action field update, remove, other link for multi tabular table.

// Tabular
{
     title: 'Action',
     tmpl: Meteor.isClient && Template.tabularAction
}

// Template
<template name="tabularAction">
    <div class="btn-group">
        <button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
            <i class="fa fa-bars"></i>
        </button>
        <ul class="dropdown-menu dropdown-menu-right" role="menu">
            <li><a href="{{pathFor 'company.update}}" class="update">Update</a></li>
            <li><a href="{{pathFor 'company.remove'}}" class="remove">Remove</a></li>
        </ul>
    </div>
</template>

I don't want create the duplicate templates for multi tabular, so i want to pass any data from tabular table like router name, other value....
pl help me.

v1.0.1 => pagination index not being reset!

After upgrade to v1.0.1 the pagination index is not being reset, I mean if I am looking at apples and switch to page 2 and then decide to display oranges I will also be looking at page 2.

The pagination index should be reset when another table is displayed.

Possibly Improving Speed for Sort/Pages/Search?

There is some kind of a "moment" loading if you change pages, sort or filter. After visiting all pages (So I get all subscription if I do console count) clicking quickly on next page you will see that delay or clicking on any sorting few times causes it to. And it happens with 20 or 500 records tables.

I have researched a little bit about datatables speed:

a) is it possible it's because of redraw of the rows? looking at: this stackoverflow question the draw() function defaults to true, setting it false can increase performance dramatically.

b) cached(client-side collection) are not being re-used? If I change to a page I just was in, reuse cached collection for the table can be really nice for performance, combined with "x" limit for first subscription can make first 5 pages load instantly. If you set limit for 100 and each page has 20 records.

The speed is not an issue right now, I just decided to post this as an improvement possibly for the future.

How to display filtered records?

Hi There,

I have a collection which contains 1000 records, i have a flag status(true/false) in the collection.

I need to display only the records which are having status flag true.
in sort:
Total records : 1000
active status: 700
inactive status : 300

How can I display only active records? It shows 1-50 of 1000. Could you please help me out..

Is possible to translate columns title?

Is there a way to translate title strings from table headers ?

I'm using tap-i18n, I have also tried to call a function like:

tap = function (str) {
    return (Meteor.isClient) ? TAPi18n.__(str)  : " ";
}
... and then use
{ data: "someField", title: tap('name') }

but nothing is translated, it returns "name".

Thanks

Question: Is this active?

Hi,

I'm looking for reliable table package for my project, And I wanted to know if this is active & safe to use? I wanted to use meteor-pages but it lacks search/filter options. meteor-tabular got this?

Thank you!

how to get value of other field in custome field?

I would like custome field value with other field value like this:

....
{data: "copies", title: "Copies Available"},
    {
      data: "lastCheckedOut",
      title: "Last Checkout",
      render: function (val, type, doc) {
        if (val instanceof Date) {
          return moment(val).calendar();
        } else {
          // how to get copies field value?
          return copies.value;
        }
      }
    },
....

1.0.1 = > search is now Case Sensitive

After the latest update the search has become case sensitive. I believe the default behaviour should be to be case incensitive or at least be configurable.

I am new for Meteor and Tabular (don't show table body)?

I am new for meteor and tabular.
I try test tabular, it show table header with search, show records select box but don't show data from database.
my code:

// My collection, i insert any doc like your example field
Books = new Mongo.Collection("books");

// My tabular
TabularTables = {};

Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);

TabularTables.Books = new Tabular.Table({
  name: "BookList",
  collection: Books,
  columns: [
    {data: "title", title: "Title"},
    {data: "author", title: "Author"},
    {data: "copies", title: "Copies Available"},
    {
      data: "lastCheckedOut",
      title: "Last Checkout",
      render: function (val, type, doc) {
        if (val instanceof Date) {
          return moment(val).calendar();
        } else {
          return "Never";
        }
      }
    },
    {data: "summary", title: "Summary"},
    {
      tmpl: Meteor.isClient && Template.bookCheckOutCell
    }
  ]
});

// My template
{{> tabular table=TabularTables.Books class="table table-striped table-bordered table-condensed"}}

Exception while invoking method 'tabular_getInfo' Error: Did not check() all arguments during call to 'tabular_getInfo'

I20150116-16:32:36.177(0)? Exception while invoking method 'tabular_getInfo' Error: Did not check() all arguments during call to 'tabular_getInfo'
I20150116-16:32:36.179(0)? at [object Object]..extend.throwUnlessAllArgumentsHaveBeenChecked (packages/check/match.js:357:1)
I20150116-16:32:36.179(0)? at Object.Match.failIfArgumentsAreNotAllChecked (packages/check/match.js:112:1)
I20150116-16:32:36.179(0)? at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1596:1)
I20150116-16:32:36.179(0)? at packages/ddp/livedata_server.js:648:1
I20150116-16:32:36.179(0)? at [object Object].
.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20150116-16:32:36.180(0)? at packages/ddp/livedata_server.js:647:1
I20150116-16:32:36.180(0)? at [object Object].
.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20150116-16:32:36.180(0)? at [object Object]._.extend.protocol_handlers.method (packages/ddp/livedata_server.js:646:1)
I20150116-16:32:36.180(0)? at packages/ddp/livedata_server.js:546:1

Hi there,
I am following the example, butI am getting this error, is there any way to fix?
By the way, how can I pass dynamic column array?
TabularTables = {};

TabularTables.Users = new Tabular.Table({
     name: "Users",
    collection: this.collection,
    columns: function (){
            var result= [];
            _.map(this.fields,function(field){

                var item = {data:field.name,title:field.name};
                result.push(item);
            });

            return result;
        }
});

It seems doesn't work.

Table data from array

Hello @aldeed

Do you consider adding an option to pass an array or/and a collection cursor instead of a collection to the table helper?

William

'tabular_getInfo': TypeError: Cannot read property 'ids' of undefined any ideas?

I'm just trying the demo and I'm getting the following error in the console Exception in delivering result of invoking 'tabular_getInfo': TypeError: Cannot read property 'ids' of undefined I'm not sure why that happen

{{> tabular table=TabularTables.products class="table table-striped table-bordered table-condensed"}}

TabularTables = {};

Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);

TabularTables.products = new Tabular.Table({
  name: "productstable",
  collection: userProducts,
  columns: [
    {data: "name", title: "name"},
    {data: "status", title: "status"},
    {data: "price", title: "pricee"}
  ]
});

After changing "Show xxx entries" and clicking next page in the pagination, the "Show xxx entries" resets to the default value.

Congrats on 1.0!!! Thank you so much, I'm very excited.

Very minor issue probably:
After changing "Show xxx entries" and clicking next page in the pagination, the "Show xxx entries" resets to the default value.

Just to check to make sure it wasn't my app I made a bare bones repo:
https://github.com/jasonxeno/tabular-issue

Change amount of entries to 100.
Go down and click next to view next page.
Entries resets to 10 and only 10 results appear.

How to access the DataTables API? Doesn't seems to work?

I'm trying to add this functionality and I need to access the DataTables API, The manual says:

A new DataTables API instance can be obtained for one or more tables in one of three different ways:

$( selector ).DataTable();
$( selector ).dataTable().api();
new $.fn.dataTable.Api( selector );

I have tried them all and they just don't work, I also tried some variations of TabularTable. But ehh I really don't know please help?

table2 = $('#DataTables_Table_0').DataTable();
Template.customersPage.events({
  'click .plusOne': function(){
       var tr = $(this).closest('tr');
        var row = table2.row( tr );
        if ( row.child.isShown() ) {
            console.log('alreadyopen');
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            console.log('openthisone');
            // Open this row
            row.child( format(row.data()) ).show();
            tr.addClass('shown');
        }
  }
})

Make fully reactive

Hi @aldeed!

I'm struggling with this issue a while now. I'm quite new to meteor, so maybe I misunderstood something. When I update some entry in DB, datable re-renders fine, but when I insert new entry to collection nothing is happening on client side until I perform manual action to trigger re-render of datatable.

I also used custom publish function to return whole collection (not specific ids), but encountered the same issue. I even downloaded your repo and tried to fix this, but with no luck so far. That's why I decided to ask for your advice.

I really need this to work soon for one simple commercial app, which I've recently updated to Meteor 1.0+ and that's why I searched for compatible datatables library and came across your's sollution. Before update I was using https://github.com/LumaPictures/meteor-jquery-datatables and it worked fine, but now it's not compatible with the newest version of Meteor.

Thanks!

problem with more then one of Tabular file?

I have 2 tabular file,

// Book.js
TabularTables = {};
Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);
TabularTables.Books = new Tabular.Table({
    name: "BookList",
    collection: Books,
    columns: [
        {data: "title", title: "Title"},
        {data: "author", title: "Author"},
        {data: "copies", title: "Copies Available"},
................

// Classes.js
TabularTables = {};
Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);
TabularTables.Classes = new Tabular.Table({
............

it don't show anything.

v1.0.4 => processing.dt fires weird

Here is a reproduction for the closed issue: #44

Using tabular v0.2.3 $(window).on('processing.dt') fires as it should (when we click next page). It fires once for processing=true then after some time (ex. 525.444ms) once again for processing=false. This is natural desired behaviour.

Console output for each next-page click using v0.2.3 => http://tabular-v0-2-3.meteor.com

Tue Jan 20 2015 12:08:42 GMT+0100 (CET) processing.dt=true
Tue Jan 20 2015 12:08:42 GMT+0100 (CET) processing.dt=false
processing.dt=true: 525.444ms

Using tabular v1.0.4 $(window).on('processing.dt') fires four times for each next-page click. First it fires true and false very quickly (ex. 7.543ms) and when processing finishes it fires true and false again. Thats why my loading spinner was not showing and I originally thought that the event was not firing at all, but after deeper inspection it seems it is firing too much in a weird way.

Console output for each next-page click using v1.0.4 => http://tabular-v1-0-4.meteor.com/

Tue Jan 20 2015 12:13:26 GMT+0100 (CET) processing.dt=true
Tue Jan 20 2015 12:13:26 GMT+0100 (CET) processing.dt=false
processing.dt=true: 7.543ms
Tue Jan 20 2015 12:13:27 GMT+0100 (CET) processing.dt=true
Tue Jan 20 2015 12:13:27 GMT+0100 (CET) processing.dt=false
processing.dt=true: 7.510ms

And here is my code: https://github.com/boustanihani/tabular-processing

Collection undefined error

I have the following table which works ok. Beeing an admin account I published the whole Meteor.users collection. I also have two databases in a file in the root /lib

Clients = new Meteor.Collection("client");
Brands = new Meteor.Collection("brand");

They are published for now like this in the /server/lib folder

Meteor.publish("pubClients", function(){
return Clients.find();
});
Meteor.publish("pubBrands", function(){
return Brands.find();
});
Meteor.publish("pubUsers", function(){
return Meteor.users.find();
});

And subscribed like this in the client/lib folder

Meteor.subscribe('pubClients');
Meteor.subscribe('pubBrands');
Meteor.subscribe('pubUsers');

I am using the following template to inject the html:
{{> tabular table=TabularTables.Users selector=selector class="table table-striped table-bordered table-condensed"}}

Now if I try to change the Meteor.user to any of the Clients or Brands collection or even inserting above this code a console.log(Clients) I get a: "Clients is not defined" error.
If I type in the console > Clients before running rerunning the app it works fine with Mongo.Collection etc.
If I run it I get the undefined message in the console too.
This is my code ( in fact your code :) ):

TabularTables = {};

Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);

TabularTables.Users = new Tabular.Table({
name: "UserList",
collection: Meteor.users,
pub:"pubUsers"
columns: [
{data: "username", title: "User name"},
{
data: "emails",
title: "Email",
render: function (val, type, doc) {
return val[0].main
}
},
{
data: "emails",
title: "verified",
render: function (val, type, doc) {
return val[0].verified?"โ˜‘":"โ˜";
}
},
{
data: "profile",
title: "Account",
render: function (val, type, doc) {
return val.accType;
}
},
{
data: "profile",
title: "Active",
render: function (val, type, doc) {
return val.active?"active":"pending";
}
},
{
data: "createdAt",
title: "Singned up",
render: function (val, type, doc) {
return moment(val).calendar();
}
},
{
tmpl: Meteor.isClient && Template.bookCheckOutCell
}
]
});

I am using this collection in other points of the app and it works fine. Since I installed the tabular package
things got out of hand somehow. I don't have the slights idea were to start from.
I am struggling now for two days to get it working, but there's so few information on the web about this package (and most Meteor related subjects) that I decided to post this issue.

Any ideas?

Thanks a lot.

Conditional formatting

Hi,
I am fairly new to meteor and this wonderful packet but. I am having trouble figuring out how I would be able to format a specific row on a condition. For example if a data field has certain value I would like to be able to set some style class to that particular row to make the text highlight as red "warning\error".

I am assuming this is somehow doable using the DataTables API but I was unable to figure out how it's done.

Thanks in advance.

my code looks something like this

Template.CreqSystemsView.rendered = function() {
  var self = this;
  table = self.$('CREQ').dataTable({
    fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
      if ($(nRow).find('td:eq(5)').text()=='N') {
        $(nRow).find('td:eq(5)').addClass('color');
      }
    }
  });
};

Support local / client-only collections and data arrays

Really great package - thanks so much for putting it together !

A question - would it be possible to use a client-side only collection as the data source ?

A first crack at it : by adding a clientOnly parameter, i got the datatable to display a client-side collection, and it sorts correctly. However since you do the search and pagination via subscriptions, I'm not getting that part to work.

https://github.com/petrometro/meteor-tabular/blob/master/client/tabular.js (cf. lines 140, 143, 251, 272)

Send data to publication

Along with the three fields I want to send one more field to publication how to do that?

TabularTables.registrations = new Tabular.Table({
  name: "Registrations",
  collection: Participants,
  pub: "tabular_Registrations",//want to send one more value 
  columns: [
    {data: "_id", title: "Title"},
    {data: "edition", title: "Edition"},
    {data: "email", title: "Email"},
]
});

My requirement is

I have 1000 docs in one collection each has ``edition` field and
I want to display only one edition records in table with autosubscribe(which this package provides)

I want to send that edition id to publish function

my publish function

Meteor.publish("editionDocs",function(tableName, ids, and fields){
  return Participants.find({"edition":editionId}),{........});
});

don't auto update when insert new doc?

I used two browser, one to view tabular data and one to insert data.
but when i insert new data, the tabular don't auto update (for update and remove action is ok).

When a document is added to a collection, the table is not updated until an action is performed.

First of all, this package is AMAZING, thank you so much!

I would like to replace reactive-tables in my apps with this package but I'm having an issue with reactivity:

When a document is added to a collection, the table is not updated until an action is performed.

Also when a document is changed to meet criteria for a selector, the table is not updated until an action is performed.

But when you do any action on the table, change amount of entries to show, search, change navigation pages, the table is updated correctly then .

Also the number of entries is not reactive.

I'm guessing there needs to be some kind of check on the server in your table publish function when the data in the collection changes, and then update the client if that data would change the current view?

Deleting documents or documents changing to not meet the criteria of a selector anymore seems to be working though, it looks fully reactive and works great.

Non-orderable first column appears orderable at first

When using default initial sorting, the first column appears orderable at first. Once you click to sort another column, the first column's arrow goes away.

This might be a DataTables bug. Need to investigate further.

Tabular Collection Ignore Find Arguments of Publish?

Hey,
This package is awesome have started creating my own table, And I was pleasantly surprised that I can use the full datatables API it's really awesome.

My issue I publish meteor collection this way (Server-side of course):

Meteor.publish('userProducts', function() {
  return userProducts.find({userId: this.userId}, {fields: {
    userId:1,
    name:1, 
    price:1, 
    status:1,
    marketPlace:1,
    updated_at:1
  }});
});

But it seems the find by userId: this.userId doesn't work because I get the full collection of all users (I'm trying to show only the current users products) the fields part works fine. Am I doing it wrong? Or this is a problem?

Event map support on tables?

Hi there,

This package is awesome. Just found it a few days ago and I've been playing around to see if it'll do everything I need it to.

The only issue I've hit is I can't seem to detect clicks on table rows. Here's the table definition:

TabularTables.Users = new Tabular.Table({
    name: "UserList",
    collection: Meteor.users,
    columns: [
        {data: "username", title: "Username"},
        {data: "emails[0].address", title: "Email"},
        {data: "profile.name", title: "Name"}
    ]
});

Here's the Template:

<template name="Users">
    {{> tabular table=TabularTables.Users class="table table-striped table-bordered table-condensed"}}
</template>

Then I have this JS to try to detect row clicks:

if (Meteor.isClient) {
    Template.Users.events({
        'click tr': function(event) {
            alert(event.currentTarget);
        }
    });
}

But it doesn't seem to get fired. How should I be checking for row clicks? Is this being overridden by DataTables somehow?

Enhancement: search string optionally or'ed by whitespace

In a plain old datatable the search string is or'ed by whitespace.
We can add an optional config parameter to automatically or whitespace in the search string.
It may make sense to set this to true by default to match datatable's default behavior.

i.e.:
search string -> regex
'firstname lastname' -> 'firstname|lastName'
'firstname ' -> 'firstname' (ignore trailing whitespace)

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.