2

I am not sure if I phrased the question in the title correctly but here is the situation.. I need to create a dynamic table with heist when table fields (schema) are only available at run time. So usually, when the schema is known at compile, I would do something like this:

<table>
  <row-splice>
    <tr>
      <td> <field1/> </td>
      <td> <field2/> </td>
      <td> <field3/> </td>
    </tr>
  </row-splice>
</table>

That is when I know the number of fields and their names at compile time. I understand how to process all that in the handler with 'runChildrenWith', 'mapSplices' and so on ...

Now I am in a situation when the number of fields and schema are available only at run time. So the heist template, as I understand it, would look like this:

<table>
  <row-splice>
    <tr>
      <field-splice>
      <td> <field/> </td>
      </field-splice>
    </tr>
  </row-splice>
</table>

I am really stuck with how to implement it within the handler. I assume I would need to do 'mapSplices' twice - one inside the other, correct? So, empirically speaking, that would be an inner and outer loop/map, right?

How would I do this within handler??

Thanks.

Update:

Forgot to mention that schema can be retrieved at run time from the DB and available as:

Table { tableName   :: Text
      , tableFields :: [Text]
      }

But it is not really needed as data comes from schema-less mongodb and converted to Map:

fromList [("FieldName1","Value1"),("FieldName2","Value2"),("FieldName3","Value3")]

Update2:

I tried suggested examples with no luck I just get all my data in a single column. All I need is a simple inner and outer loop to generate fields and rows dynamically. It cannot be simpler then this:

<% @rows.each do |row| %>
  <tr>
  <% row.each do |field| %>
    <td> <%= field %> </td> 
  <% end %>
  </tr>
<% end %>

Update3:

I finally cracked it after a long weekend rest ... Here is the example. it is mongodb specific and I literally just copied and pasted it. But if someone gets stuck with inner/outer loops it would be helpful, I suppose.

showTableH :: AppHandler ()
showTableH = do
  table <- liftIO $ fetchTable tname
  docs <- liftIO $ getColList tname
  let rowSplice doc = mapSplices (\f -> fieldSplice $ T.pack $ at f doc) (tableFields table)
    where fieldSplice field = runChildrenWithText [("field", field)]
  let listRowsSplice = mapSplices (\d -> runChildrenWith [("fields", rowSplice d)]) docs
  heistLocal (bindSplices [("rows", listRowsSplice)]) $ render "show-table"
r.sendecky
  • 9,933
  • 9
  • 34
  • 62

1 Answers1

2

I think the key here is using mapSplices along with runChildrenWith. I think it would look something like this:

rowSplice = do
    rows <- lift getRowsFromDB
    mapSplices (\row -> runChildrenWith [("field-splice", fieldSplice row)]) rows
fieldSplice rowId = do
    fields <- lift $ getFieldsFromDB rowId
    mapSplices (\f -> runChildrenWith [("field", fieldToText f)]) fields
mightybyte
  • 7,282
  • 3
  • 23
  • 39
  • Thank you very much, still does not work though .. I've played with it for a day - no luck. I obviously do something wrong. In your example, as I can see, there is only the internal "loop" generating fields within a single row. Now, the internal "loop" should run withing the outer loop which generates the rows within the table. I just don't know how to connect the two together. So internal 'mapSplices' should create a row and external 'mapSplices' should create a table. – r.sendecky Dec 07 '12 at 03:38
  • Ok, I rewrote the answer. Try that. – mightybyte Dec 07 '12 at 14:57
  • Thank you very much. I kind of cracked it as well... Even your first example helped me a lot, I got the idea of how to nest the 'runChildren' functions. Thanks once again. – r.sendecky Dec 10 '12 at 12:53