Giter VIP home page Giter VIP logo

ember-data-table's Introduction

Ember Data Table

Build Status npm version

Data table for Ember based on a JSONAPI compliant backend.

Have a look at ember-paper-data-table to get a data table styled with ember-paper.

Installation

If you're using Ember > v3.8

ember install ember-data-table

For Ember < v3.8, use version 1.x of the addon

ember install [email protected]

Getting started

Include the DataTableRouteMixin in the route which model you want to show in the data table. Configure the model name.

import Ember from 'ember';
import DataTableRouteMixin from 'ember-data-table/mixins/route';

export default Ember.Route.extend(DataTableRouteMixin, {
  modelName: 'blogpost'
});

Next, include the data table in your template:

{{data-table
  content=model
  fields="firstName lastName age created modified"
  isLoading=isLoadingModel
  filter=filter
  sort=sort
  page=page
  size=size
}}

Note: the filtering, sorting and pagination isn't done at the frontend. By including the DataTableRouteMixin in the route each change to the filter, sort, page and size params will result in a new request to the backend. The DataTableRouteMixin also sets an isLoadingModel flag while the route's model is being loaded.

Have a look at Customizing the data table to learn how you can customize the data table's header and body.

Data table component

Specification

The following parameters can be passed to the data-table component:

Parameter Required Default Description
content x a list of resources to be displayed in the table
fields names of the model fields to show as columns (seperated by whitespace)
isLoading false shows a spinner instead of the table content if true
filter current value of the text search
sort field by which the data is currently sorted
page number of the page that is currently displayed
size number of items shown on one page
enableSizes true flag to enable page size options dropdown
sizes [5, 10, 25, 50, 100] array of page size options (numbers)
link name of the route the first column will link to. The selected row will be passed as a parameter.
onClickRow action sent when a row is clicked. Takes the clicked item as a parameter.
autoSearch true whether filter value is updated automatically while typing (with a debounce) or user must click a search button explicitly to set the filter value.
noDataMessage No data message to be shown when there is no content
lineNumbers false display a line number per table row (default: false). Must be true or false.
searchDebounceTime 2000 debounce time of the search action of the data table. Must be integer.

By default the data table will make each column sortable. The search text box is only shown if the filter parameter is bound. Pagination is only shown if the pagination metadata is set on the model (see the Ember Data Table Serializer mixin).

Customizing the data table

The way the data is shown in the table can be customized by defining a content block instead of a fields parameter.

{{#data-table content=model filter=filter sort=sort page=page size=size onClickRow=(action "clickRow") as |t|}}
  {{#t.content as |c|}}
    {{#c.header}}
      {{th-sortable field='firstName' currentSorting=sort label='First name'}}
      {{th-sortable field='lastName' currentSorting=sort label='Last name'}}
      <th>Age</th>
      {{th-sortable field='created' currentSorting=sort label='Created'}}
      <th>Modified</th>
    {{/c.header}}
    {{#c.body as |row|}}
      <td>{{row.firstName}}</td>
      <td>{{row.lastName}}</td>
      <td>{{row.age}}</td>
      <td>{{moment-format row.created}}</td>
      <td>{{moment-format row.modified}}</td>
    {{/c.body}}
  {{/t.content}}
{{/data-table}}

Have a look at the helper components.

Adding actions to the data table

The user can add actions on top of the data table by providing a menu block.

{{#data-table content=model filter=filter sort=sort page=page size=size isLoading=isLoadingModel as |t|}}
  {{#t.menu as |menu|}}
    {{#menu.general}}
      {{#paper-button onClick=(action "export") accent=true noInk=true}}Export{{/paper-button}}
      {{#paper-button onClick=(action "print") accent=true noInk=true}}Print{{/paper-button}}          
    {{/menu.general}}
    {{#menu.selected as |selection datatable|}}
      {{#paper-button onClick=(action "delete" selection table) accent=true noInk=true}}Delete{{/paper-button}}
    {{/menu.selected}}
  {{/t.menu}}
  {{#t.content as |c|}}
    ...
  {{/t.content}}
{{/data-table}}

The menu block consists of a general and a selected block. The menu.general is shown by default. The menu.selected is shown when one or more rows in the data table are selected.

When applying an action on a selection, the currently selected rows can be provided to the action by the selection parameter. The user must reset the selection by calling clearSelection() on the data table. E.g.

actions:
  myAction(selection, datatable) {
    console.log("Hi, you reached my action for selection: " + JSON.stringify(selection));
    datatable.clearSelection();
  }    

Helper components

The following components may be helpful when customizing the data table:

Sortable header

The th-sortable component makes a column in the data table sortable. It displays a table header <th> element including an ascending/descending sorting icon in case the table is currently sorted by the given column.

{{th-sortable field='firstName' currentSorting=sort label='First name'}}

The following parameters are passed to the th-sortable component:

Parameter Required Description
field x name of the model field in the column
label x label to be shown in the column's table header
currentSorting x current sorting (field and order) of the data according to the JSONAPI specification

Note: the data table will update the currentSorting variable, but the user needs to handle the reloading of the data. The Ember Data Table Route mixin may be of use.

Mixins

The following mixins may be helpful to use with the data table:

Serializer

Upon installation, the DataTableSerializerMixin is automatically included in your application serializer to add parsing of the filter, sortig and pagination meta data from the links in the JSONAPI responses. The data is stored in Ember's model metadata.

To include the DataTableSerializerMixin in your application, add the mixin to your application serializer:

import DS from 'ember-data';
import DataTableSerializerMixin from 'ember-data-table/mixins/serializer';

export default DS.JSONAPISerializer.extend(DataTableSerializerMixin, {

});

E.g.

meta: {
  count: 42
},
links: {
  previous: '/posts?page[number]=1&page[size]=10'
  next: '/posts?page[number]=3&page[size]=10'
}

will be parsed to

meta: {
  count: 42,
  pagination: {
    previous: { number: 1, size: 10 },
    next: { number: 3, size: 10 }
  }
}

Route

The route providing data for the data-table component often looks similar. The model hook needs to query a list of resources of a specific model from the server. This list needs to be reloaded when the sorting, page or page size changes. The DataTableRouteMixin provides a default implementation of this behaviour. Just include the mixin in your route and specify the model to be queried as modelName.

import Ember from 'ember';
import DataTableRouteMixin from 'ember-data-table/mixins/route';

export default Ember.Route.extend(DataTableRouteMixin, {
  modelName: 'post'
});

The DataTableRouteMixin specifies the filter, page, sort and size variables as queryParams of the route with the refreshModel flag set to true. As such the data is reloaded when one of the variables changes. A user can add custom options to be passed in the query to the server by defining a mergeQueryOptions(parms) function in the route. The function must return an object with the options to be merged.

import Ember from 'ember';
import DataTableRouteMixin from 'ember-data-table/mixins/route';

export default Ember.Route.extend(DataTableRouteMixin, {
  modelName: 'post',
  mergeQueryOptions(params) {
    return { included: 'author' };
  }
});

Note: if the mergeQueryOptions returns a filter option on a specific field (e.g. title), the nested key needs to be provided as a string. Otherwise the filter param across all fields will be overwritten breaking the general search.

E.g.

mergeQueryOptions(params) {
    return {
        included: 'author',
        'filter[title]': params.title
    };
}

The DataTableRouteMixin also sets the isLoadingModel flag on the controller while the route's model is being loaded. Passing this flag to the data table's isLoading property will show a spinner while data is loaded.

Default Query Params

The DefaultQueryParams mixin provides sensible defaults for the page (default: 0), size (default: 25) and filter (default: '') query parameters. The mixin can be mixed in a controller that uses the page and filter query params.

import Ember from 'ember';
import DefaultQueryParamsMixin from 'ember-data-table/mixins/default-query-params';

export default Ember.Controller.extend(DefaultQueryParamsMixin, {
  ...
});

Note: if you want the search text field to be enabled on a data table, the filter parameter may not be undefined. Therefore you must initialize it on an empty query string (as done by the DefaultQueryParams mixin).

ember-data-table's People

Contributors

aatauil avatar cecemel avatar claire-lovisa avatar ember-tomster avatar erikap avatar ferkoni avatar joachimzeelmaekers avatar lordblendi avatar madnificent avatar mikidi avatar nvdk avatar ruckc avatar windvis avatar

Stargazers

 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

ember-data-table's Issues

tr role="button" on table row

<tr role="button" class="{{if (contains wrapper.item data-table.selection) "selected"}} {{if onClickRow "clickable"}}" onclick={{action (optional onClickRow) wrapper.item}}>

It is not helpful to put this ARIA role here.

You are not supposed to add role="button" to a table row, this doesn't help the accessibility. In my understanding of screen readers, the screen reader will now treat the whole row content as a single string and it will not be able to interpret the table correctly.

Size and other filtering not working

Not Changing display when size and other filtering action.

can i use this route?

import Route from '@ember/routing/route';
import DataTableRouteMixin from 'ember-data-table/mixins/route';

export default Route.extend(DataTableRouteMixin,{
model(){
return [
{
'id':'1',
'firstName':'sample',
'lastName':'sampl',
'age':'24',
'created':'now',
'modified':'later',
},
{
'id':'2',
'firstName':'sample',
'lastName':'sample',
'age':'24',
'created':'now',
'modified':'later',
},
{
'id':'3',
'firstName':'sample',
'lastName':'sample',
'age':'24',
'created':'now',
'modified':'later',
},
{
'id':'4',
'firstName':'sampler',
'lastName':'sample',
'age':'24',
'created':'now',
'modified':'later',
},
{
'id':'5',
'firstName':'sample',
'lastName':'sample',
'age':'24',
'created':'now',
'modified':'later',
},
];
}

});

Ember v4 support

This addon is still used in most projects so making it compatible with Ember 4 is probably a good idea. I know there are plans to give this addon a modern reimplementation but that will take a while (and will probably also change the API) so resolving the deprecations to unblock v4 updates is probably a quicker win for now.

url encoded page[number] and page[size]

According to jsonapi.org/format/

Note: The example query parameters above use unencoded [ and ] characters simply for readability. In practice, these characters must be percent-encoded, per the requirements in RFC 3986.

The page[number] and page[size] parameters should be url encoded. In serializer.js it assumes the page[number] and page[size] are not url encoded.

I believe the right answer would be to add an || param === 'page%5Bnumber%5D' or urldecode the parameter before comparing.

Source code for demo app

It would be helpful you could provide the source code for the demo app. I have seen the code samples, but I would be able to see the whole project and understand how everything ties together

The full `lodash` library is included

It seems like this addon imports lodash (through ember-lodash) to merge objects together.

The problem is that the full lodash library is included instead of only that specific function. This increases the bundle size by a lot.

Some build size comparisons:

Production build of a newly generated Ember app.

File sizes:
 - dist/assets/data-table-test-2433f9de99b639ee070d99e9db936375.js: 8.43 KB (1.71 KB gzipped)
 - dist/assets/data-table-test-d41d8cd98f00b204e9800998ecf8427e.css: 0 B
 - dist/assets/vendor-423cd95bd84c864cb098d7ad30d295c6.js: 698.86 KB (186.17 KB gzipped)
 - dist/assets/vendor-d41d8cd98f00b204e9800998ecf8427e.css: 0 B

Production build of the same app, after installing this addon

File sizes:
 - dist/assets/data-table-test-1bb3a0fc21b16df67fbd5fddc371dda2.js: 42.2 KB (3.7 KB gzipped)
 - dist/assets/data-table-test-d41d8cd98f00b204e9800998ecf8427e.css: 0 B
 - dist/assets/vendor-678fbf24ed0f76c2b3ba0b455641a2bb.js: 1.04 MB (243.89 KB gzipped)
 - dist/assets/vendor-d41d8cd98f00b204e9800998ecf8427e.css: 0 B

It's hard to determine from an app how the lodash dependency increases the bundle size, but bundlephobia can give us some insights.

Switching to ember-auto-import and importing only the specific function should treeshake the unused ones out. Alternatively we can simply not use lodash for this and write the merge util ourselves.

Add "pagination change" action handler

It seems the pagination component depends on 2-way binding to update the @page argument. This works when you load data in a route, since you can link this argument to a query param and let Ember refresh the model when the value changes.

However, when you fetch data in a component, using query params isn't really an option anymore. This leaves the following options:

  • use some sort of "Resource" implementation which reruns if the page tracked property changes. Resources aren't part of the framework yet so using an addon probably means it needs to change again once the official implementation is released.
  • use an observer which is highly discouraged

A better solution would be to add some sort of action argument which gets called when the pagination needs to be changed.

I think a @onPageChange arg which would receive the new page as the first argument might be enough for now?

I think it can also be done without a breaking change by keeping the 2-way-binding logic when an action handler isn't provided.

Make the table component translation friendly

It seems there are multiple cases of hardcoded strings inside the templates. It would be nice if these were configurable without having to fully override the respective templates.

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.