smartmetals / phoenix_datatables

Library to implement server-side API for the jQuery DataTables library with Elixir and Phoenix Framework
MIT License
14 stars 7 forks source link

How to use associated fields #14

Closed max4all closed 6 years ago

max4all commented 6 years ago

It all works beautifully. But I couldn't figure out how to use assoc fields.

I tried the following and various other combinations, it didn't work.

 $('[data-item-server]').dataTable({
      lengthChange: false,
      serverSide: true,
      ajax: 'api/items',
      columns: [
        { data: "id" },
        { data: "name" },
        { data: "area_id"}, // this works
        { data: "area.name" }, // this won't work
      ]
    });
  })
 def item_json(item) do
    %{ id: item.id,
      name: item.name,
            area: %{
        name: item.area.name
      }
    }
jeremyjh commented 6 years ago

Hey, thanks for trying out this library. There are tests that use this feature but this is a good reminder I need to incorporate it into the demo. Your 4th line should work, but only if your queryable has a join to a table called area.

In the tests, we use a request fixture that specifies a couple of columns like category.name, unit.description.

If you take a look at that and still have issues maybe you could post an example that reproduces the issue and we'll be happy to take a look further.

max4all commented 6 years ago

I read the documentation. Actually it explains everything there. I tried to modify the example repo, but I couldn't succeed so far.

jeremyjh commented 6 years ago

@max4all is there a specific error message you are getting ?

max4all commented 6 years ago

This is what I do:

table.js

    $('[data-datatable-server]').dataTable({
      lengthChange: false,
      serverSide: true,
      ajax: 'api/items',
      columns: [
        { data: "id" },
        { data: "category.name" }
      ]
    });

stock.ex

  def datatable_items(params) do
    query =
      (from item in Item,
      join: category in assoc(item, :category),
      select: %{id: item.id,  category_name: category.name})
    columns = [id: 0, category: [name: 1]]
    Repo.fetch_datatable(query, params, columns)
  end

_item_tableviex.ex

  def render("index.json", %{payload: payload}) do
    PhoenixDatatables.map_payload(payload, &item_json/1)
  end
  def item_json(item) do
    %{
      id: item.id,
      category_name: item.category.name
    }
  end

These are the errors I get:

localhost:4000/items

_gives:_  tn/7 error
_on the console:_ 500 error
jeremyjh commented 6 years ago

If your data specifies a path expression like category.name, that path has to exist in the document that you return in the response. The client library DataTables uses this convention for pulling nested data into a flattened table, and on the server side we use it for indexing into the joined tables.

So your item_json in this case needs to be:

def item_json(item) do
    %{
      id: item.id,
      category: %{
         name: item.category.name
      }
    }
  end

I have updated the example in a branch in this repo, the commit that makes the required changes might be helpful for you as well. This branch does work live though tests are not passing due to some data conditioning still needed.

We may change this a little bit so that you don't have to return a nested structure when you have joins in your query; I'm going to try out using the DataTables name: attribute as a way to specify the query path on the server-side separate from the data path on the client side, if that makes sense.

jeremyjh commented 6 years ago

@max4all I made the change I mentioned above - you can now use associated columns without nesting the response, using the "name" attribute. Also I merged the changes to the example to use associated table. This is published to Hex as 0.2.0 (technically, it is a breaking change as name can be used client side for other purposes). Please let me know if you have any more questions.

max4all commented 6 years ago

Thank you, it works fine.