GithubHelp home page GithubHelp logo

evancz / elm-sortable-table Goto Github PK

View Code? Open in Web Editor NEW
283.0 8.0 65.0 141 KB

Sortable tables for whatever data you want to display

Home Page: http://package.elm-lang.org/packages/evancz/elm-sortable-table/latest

License: BSD 3-Clause "New" or "Revised" License

Elm 100.00%

elm-sortable-table's Introduction

DEPRECATED

This package is not published in 0.19 and above. In an effort to prune my responsibilities, we suggested that community members fork it and take it in the direction that makes sense to them. Maybe that means adding more features. Maybe it means removing things to make it even simpler. Maybe it means rewriting it from scratch. Point is, please search for packages with the same or similar name, and look for an author you trust.



What follows is the README from before in case you are curious about the history.



Sortable Tables

Create sortable tables for data of any shape.

This library also lets you customize <caption>, <tbody>, <tr>, etc. for your particular needs. So it is pretty easy to do whatever crazy CSS trickery is needed to get the exact table you want.

Examples

  1. U.S. Presidents by Birth Place / Code
  2. Travel Planner for the Mission District in San Francisco / Code

Usage Rules

  • Always put Table.State in your model.
  • Never put Table.Config in your model.

One of the core rules of The Elm Architecture is never put functions in your Model or Msg types. It may cost a little bit of extra code to model everything as data, but the architecture and debugging benefits are worth it. Point is, a Table.Config value is really just a bunch of view functions, so it does not belong in your model. It goes in your view!

Furthermore, you do not want to be creating table configurations dynamically, partly because it is harder to optimize. If you need multiple table configurations, it is best to create multiple top-level definitions and switch between them in your view based on other data in your Model. If your use case is so complex that this is not possible, please open an issue explaining your situation!

About API Design

This library is one of the first “reusable view” packages that also manages some state, so I want to point out some design considerations that will be helpful in general.

The Elm Architecture

It may not be obvious at first glance, but this library follows The Elm Architecture:

  • Model — There is a model named Table.State.

  • init — You initialize the model with Table.initialSort.

  • view — You turn the current state into HTML with Table.view.

  • update — This is a little hidden, but it is there. When you create a Table.Config, you provide a function Table.State -> msg so that whoever is rendering the table has a chance to update the table state.

I took some minor liberties with update to make the API a bit simpler. It would be more legit if Table.Config took a Table.Msg -> msg argument and you needed to use Table.update : Table.Msg -> Table.State -> Table.State to deal with it. I decided not to go this route because Table.Msg and Table.State would both allocate the same amount of memory and one version the overall API a bit tougher. As we learn from how people use this, we may see that the explicit update function is actually a better way to go though!

Single Source of Truth

The data displayed in the table is given as an argument to view. To put that another way, the Table.State value only tracks the details specific to displaying a sorted table, not the actual data to appear in the table. This is the most important decision in this whole library. This choice means you can change your data without any risk of the table getting out of sync. You may be adding things, changing entries, or whatever else; the table will never “get stuck” and display out of date information.

To make this more clear, let’s imagine the alternate choice: instead of giving List data to view, we have it live in Table.State. Now say we want to update the dataset. We grab a copy of the data, make the changes we want, and put it back. But what if we forget to put it back? What if we hold on to that second copy in our Model? Which one is the real data now?

Point is, when creating an API like this, own as little state as possible. Having multiple copies of “the same” value in your Model is a sure way to create synchronization errors. Elm is built on the idea that there should be a single source of truth, but if you design your API poorly, you can force your users to make duplicates and open themselves up to bugs for no reason. Do not do that to them!

Simple By Default

I designed this library to have a very smooth learning curve. As you read the docs, you start with the simplest functions. Predefined columns, and very little customization. This makes it easier for the reader to build a basic intuition for how things work.

The trick is that all these simple functions are defined in terms of crazier ones that allow for more customization. As the user NEEDS that complexity, they can read on and gradually use the parts that are relevant to them. This means the user never finds themselves in a situation where they have to learn a bunch of stuff that does not actually matter to them. At the same time, that stuff is there when they need it.

To turn this into advice about API design, helper functions can make a library simpler to learn and use. Ultimately, people may not use Table.floatColumn very often in real stuff, but that function is crucial for learning. So when you find yourself with a tough API, one way to ramp people up is to create specialized helper functions that let you get common functionality without confronting people with all the details.

elm-sortable-table's People

Contributors

dela3499 avatar derekdreery avatar evancz avatar matthiaswinkelmann avatar tim-bezhashvyly 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

elm-sortable-table's Issues

Unsafe column identification

, tableState = Table.initialSort "Year"

There is no column "Year" in this example. That is typo but I think as far as columns in config are not dynamic they may be enumerated in union type. Moreover union typed columns do i18n typesafe.

On the other hand this union type may model "column family" by accepting dynamyc arguments. Extending trip planner example:

type Mood -- column family index
  = Sad
  | Glad

type TripPlannerColumn
  = Name
  | Price
  | Rating
  | Time Mood -- column family

fixed column widths

HTML table columns are a pain, as we all know. The default is they expand to fill the content, regardless of width styling. This is often not what we want. The recommendations for fixing column widths that I could find (and here and there) recommend setting table-layout: fixed, and that

If you change this to fixed, the table and column widths are set by the widths of table and col elements or by the width of the first row of cells.

Emphasis mine. Here is the dilemma: the first row of cells is thead > tr > th, and customizing those cells is difficult in this library. (It's easy enough to set widths of the tbody row cells, but the browser ignores these.) Essentially, it is impossible to set fixed column widths using this library without overriding your config.customizations.thead function. And yet, it does seem like this is a basic feature that should be supported without quite so much pain.

My thought for an interface is

myConfig =
    Table.configWithWidths
        { toId = .id
        , toMsg = SetTableState
        , columns = 
            [ (myColumn1, "25%"), (myColumn2, "15%"), (myColumn3, "60%")
            ]
        }

where:

configWithWidths : 
    { toId : data -> String
    , toMsg : State -> msg
    , columns : List (Column data msg, String)
    } 
    -> Config data msg

and then threading that through a customizations.thead function that sets the width on the th elements. (Or instead of untyped widths, have unit types for px, %, em, etc. similar to elm-css.)

What do you think?

EDIT: I'd be happy to open a PR. I have it working externally.

Table rows are mis-ordered

I've put together a repo demonstrating the issue here with instructions in the README - let me know if this is unclear.

Note that it does take exactly the described clicks, in that order, to demonstrate the problem - but it's then completely reproducible for me.

I find it hard to see how this can be a bug in the elm-sortable-table code, but I guess this is the right place to start.

I'm using elm 0.17.1

Wrap row view?

I know I can use customizations for the rowAttrs, or for individual TD's, but I was curious how to wrap the view function that returns tr. While this gives a lot of power and potential for disaster to the user, it makes sense in some scenarios like using elm-dnd where I want to have drag/drop enabled on an entire row....the drag drop helpers seem to just wrap a view func, rather than allowing you to modify just the attrs.

Anybody know how to do this or why it'd be a bad idea?

TabBar

Hi!
I am a bit new to this Elm reusability ideology and I found myself cracking my head over a problem I have been working on, so could you please help?

My idea is to be able to have, like iPhone apps have this tab bar line at the bottom of the screen, a simple line used for in app navigation in Elm. Now, in my opinion the ideal outcome would be to be able to have two completely separate modules and batch them together into one with this module.

All in all, I basically have no complete idea about how to implement the model and configuration, but I came to some conclusions (which might be wrong):

  1. The view functions of tabs must be in configuration (this is taken directly from Evan's code which clearly states that no functionality should be in model) , but then how am I to define which view function is for which tab? I solved this by wrapping whole view into a tuple with first value of String (as id). <- This is 100% wrong, because then if we have a state which keeps an ID of a current tab, we can theoretically come out with impossible combination (like tab for which view doesn't exist) and compiler would not notice that.

  2. Because view functions would be passed in a list inside a configuration they would all have to have the same type. I thought of a solution where you put your tabs in a record and then say like:

[ Bar.view << .bar
, Foo.view << .foo 
] 
-- They all have the same type then.
  1. Then there's this idea of different messages type which I thought I could solve by creating "general" Msg type, but then there's nesting with Html.map around every view and I believe there's an easier way of achieving it.

In conclusion, I have very little idea about how to make this right, but I believe it's possible to make it.
My repo for this project is: Elm-TabBar

Here I have implemented some of the ideas from above, but this doesn't even display current tab, because I would have to filter our from views the correct view for current tab and I believed this is completely wrong.

Stable sort

The sorting should be stable, either w.r.t. the previous sort order, or the order of the list of row elements supplied.

For example, now, if I have a table with a name column and a score column and the score happens to be the same in most rows, sorting by score will change the order of those rows in a seemingly random way.

Dealing with Online Data

Hello,

Currently I want to use this table with Online data, as far as I know this library uses only local data, that means getting all the data from the Server/Storage and show it. My use case it's kinda different, I have a Service that returns data in a paginated way, so I'm not really sure how to implement this
Table using that, there's no update function that can react against the different actions and send this upstream, so I'm kinda confusing on how to deal with this...

My current approach is to expose certain attributes of the Table that can let the user know in which page it is.

Thanks!

Columns with HTML content

I don't a way to create a column with HTML content (e.g. link, image). Am I missing something or is it prohibited by design?

Missing tr inside thead

I tried the elm-sortable-table with Twitter Bootstrap, but my table header was not displaying well. So I have found that the <th> elements were not wrapped into <tr> before being wrapped themselves by a <thead>

So I looked at the MDN Docs and it says for <thead> that:

Permitted content:	Zero or more <tr> elements.

I think that if we want the elm-sortable-table to play well with all the css frameworks, wrapping the <th> with a <tr>would be a must.

eg using this

  <thead>
    <tr>
      <th>Table Header 1</th>
      <th>Table Header 2</th>
      <th>Table Header 3</th>
      <th>Table Header 4</th>
    </tr>
  </thead>

instead of

  <thead>
      <th>Table Header 1</th>
      <th>Table Header 2</th>
      <th>Table Header 3</th>
      <th>Table Header 4</th>
   </thead>

Thanks

Publish 1.0.1?

1.0.0 still has the wrong examples link in Elm Packages.

Upgrade for 0.19

Hello!

We are depending on this package in our project. Would it be possible to get a 0.19 version?

Custom Sorters

I ran into an issue where I have a list of Maybe Ints that I need to sort in a particular way: All Nothings should come at the top, and the rest should be sorted as normal.

It would be great if there was a variation of the sorters that used List.sortWith instead of List.sortBy so one could provide an (a -> a -> Order) to sort the table

Accessing the sorted rows

Hi,

I have a use case where I want the user to be able to select rows in bulk. This is almost identical to what happens in GMail where you can select several consecutive rows by holding down the shift key.

I have implemented this "select in bulk" and that works very well. The problem arises when the table is sorted by one of the columns. Because I keep track of the selected rows using the row indices into the table input list, whenever the ordering of rows differs from the original ordering of the list, by sorting on one of the columns, for example, bulk selection via holding down the shift key behaves very unexpecedly.

My question is -- would it possible to access the sorted table data, which currently is hidden from the library user? Or perhaps there is something I'm missing in the implementation of my "select in bulk" functionality, i.e perhaps using row indices is the wrong approach?

I've put together a short video demonstrating the behaviour here http://d.pr/v/MWXV.

add ability to show/hide columns

Being able to dynamically show/hide columns via a context sensitive menu would be great. However, being able to pass in a list of visible columns and maintain that in the model would be nice too. Seems like it would be pretty simple...

And once you have that list in the model, why drag and drop reordering of columns is not that far off :)

Allow reversed initial sort

Currently initial sort can be only ascending but in some cases it is useful to have it reverse (e.g. price, date).

Style table

How would you go on styling the table? The only way it seems it can work is styling table, thead, etc.

Would that be the way to go?

Add support for ThAttrs

I ran into an issue where I need to add a colspan=2 attribute to some of my headers for controlling the width of a given column, but there doesn't seem to be an easy way to do that.

In order to add a single attribute I have to repeat a lot of the code from Table.elm in my own wrapper module. Including simpleTheadHelp which controls the click listeners for sorting the table.

Having something like thAttrs would solve this problem it seems.

Storing the table state in the URL: Make Table.State non-opaque?

I want to store the information of how the table currently is sorted in the URL, so that when users share the page with eachother, they look at the items in the same order.

However, currently:

  • Table.State is opaque, so we cannot inspect it to find out how the table currently is sorted.
  • There is no real update that takes a msg and returns a state. As explained in the README, the library 'cheats':

I took some minor liberties with update to make the API a bit simpler. It would be more legit if Table.Config took a Table.Msg -> msg argument and you needed to use Table.update : Table.Msg -> Table.State -> Table.State to deal with it. I decided not to go this route because Table.Msg and Table.State would both allocate the same amount of memory and one version the overall API a bit tougher. As we learn from how people use this, we may see that the explicit update function is actually a better way to go though!

  • There is no function to turn a Table.State into a Maybe (String, Bool) (which are the column name and an 'isReversed' boolean).
  • There is no way to initialize the table with a reversed column; Table.initialSort only takes a String.

I think the best way to solve this is:

  1. Add a function to turn a Table.State into a Maybe (String, Bool).
  2. Add an alternative to Table.initialSort (maybe named Table.customizedInitialSort?) with a type signature of String -> Bool -> Table.State. (Reason to add an alternative is backwards-compatibility)

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.