Snap: inner/outer loops with heist

2019-04-13 17:34发布

问题:

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"

回答1:

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