title: Playframework datagrid template
body: <p>I have one question about <code>design</code> and basic <code>implementation</code> of server side data grid control(something like asp.net GridView).</p>
  
  <p>I have created dummy <code>DataGrid.scala.html</code> but I can be written in more sophisticated and functional (with functional programming) way.</p>
  
  <pre><code>    @(ID: String, List: Seq[model.admin.Partner.Partner], Columns: Seq[String])(content: Html= Html(""))
  @import model.admin.Partner.Partner
  &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
          @for(j &lt;- Columns) {
              &lt;td&gt;@j&lt;/td&gt;
          }
          &lt;/tr&gt;
      &lt;/thead&gt;
  
      @for(i &lt;- List) {
          &lt;tr&gt; @for(j &lt;- Columns) {
              &lt;td&gt; @code.classes.EntityFactory.getValue[Partner](i, j)&lt;/td&gt;
          }
          &lt;/tr&gt;
      }
  &lt;/table&gt;
  </code></pre>
  
  <p>Basically I have one loop for table headers and second double loop for getting value by Reflection.</p>
  
  <pre><code>object EntityFactory {
    def getValue[T](entity: T,fieldName: String)(implicit ev: scala.reflect.ClassTag[T]) = {
      entity.getClass.getMethods.find(_.getName == fieldName).get.invoke(entity)
    }
  }
  </code></pre>
  
  <p>In my view I use this Datagrid like this:</p>
  
  <pre><code>    @DataGrid(ID = "partners", List = Partners, Columns = Seq("ID","Name", "ShortName")){
  
                      }
  </code></pre>
  
  <p><strong>What I wish to have</strong></p>
  
  <p>I want have something like this:</p>
  
  <pre><code>@DataGrid(ID = "partners", List = Partners){
                          @LinkColumn(ID = "url", Propety = "ID",Url = controllers.admin.routes.PartnerController.read(""))
                          @LabelColumn(ID = "Name", Property="Name", CssClass="Some")
                          @LabelColumn(ID = "Email",Property="Email", CssClass="Some")
                          @DateDateColumn(ID = "ActiveFrom")
                      }
  </code></pre>
  
  <p>Here I created structure for this</p>
  
  <p><img src="https://i.stack.imgur.com/fKlkm.png" alt="enter image description here"></p>
  
  <p>In some columns I would like to do some trick to inject into <code>Url</code> route value from <code>Property</code>. Something like that:</p>
  
  <pre><code>    @(ID: String,entity: Partner, Property: String, Url: String)
  @import model.admin.Partner.Partner
      &lt;div&gt;
          here I want to inject code.classes.EntityFactory.getValue[Partner](entity,"ID")
          into @Url
      &lt;/div&gt;
  &lt;a href="@Url(code.classes.EntityFactory.getValue[Partner](entity,Property))"&gt;klik&lt;/a&gt;
  </code></pre>
  
  <p>Thanks for reading and help.</p>
  
  <hr>
  
  <h2>EDIT</h2>
  
  <p>After some time I finally found answer by myselve. This code is divided by two areas: <code>code</code> and <code>view</code>.</p>
  
  <p><strong>Code</strong></p>
  
  <p>Here are traits or classes which describe types of column.</p>
  
  <pre><code>trait Column {
    val ID: String
    val Label: Option[String]
    val Header: String
    val Property: String
    val AlternateProperty: Option[String]
    val Visible: Boolean
    val Enabled: Boolean
  }
  
  object Column {}
  case class LinkColumn(ID: String,
                        Label: Option[String] = None,
                        Header: String,
                        Property: String,
                        AlternateProperty: Option[String] = None,
                        Visible: Boolean = true,
                        Enabled: Boolean = true,
                        Url: Any =&gt; Call,
                        Type: String = LinkColumnType.Action
                         ) extends Column {}
  
  case class LabelColumn(ID: String,
                         Label: Option[String] = None,
                         Header: String,
                         Property: String,
                         AlternateProperty: Option[String] = None,
                         Visible: Boolean = true,
                         Enabled: Boolean = true) extends Column {}
  
  case class MergedActionColumn(ID: String,
                                Label: Option[String] = None,
                                Header: String,
                                Property: String,
                                AlternateProperty: Option[String] = None,
                                Visible: Boolean = true,
                                Enabled: Boolean = true,
                                Actions: Seq[LinkColumn]) extends Column {}
  object LinkColumnType extends Enumeration {
    type Type = Value
    val Link = ""
    val Action = "btn btn-success"
  }
  </code></pre>
  
  <p>And some helpers code.</p>
  
  <pre><code>object EntityFactory {
    def getField(entity: Any,fieldName: String) = {
      entity.getClass.getMethods.find(_.getName == fieldName).get.invoke(entity)
    }
  }
  </code></pre>
  
  <p><strong>Views</strong></p>
  
  <p><em>DataGrid.scala.html</em></p>
  
  <pre><code>@(ID: String, List: Seq[Any], CssClass: String = "",
          ShowCreateButton: Boolean = true)(Columns: Seq[Any])(implicit request: play.api.mvc.RequestHeader, lang: play.api.i18n.Lang)
  @import code.classes.{EntityFactory =&gt; ef}
  @import code.views.tags.DataGrid.{LabelColumn, LinkColumn, Column, MergedActionColumn}
  @import views.html.tags.controls.DataGrid.{LabelColumn =&gt; vLabelColumn, LinkColumn =&gt; vLinkColumn}
  @import code.views.tags.DataGrid.LinkColumnType
  @import code.Ext
  
      @if(ShowCreateButton){
          &lt;a class="btn btn-success" href="@controllers.admin.routes.PartnerController.create()"&gt;
              &lt;i class="icon-zoom-in icon-white"&gt;&lt;/i&gt;
              @Ext.te("common.add", lang.code)
          &lt;/a&gt;
      }
  &lt;table class="@CssClass"&gt;
      &lt;thead&gt;
          &lt;tr&gt;
          @for(j &lt;- Columns) {
              @j match {
                  case s: MergedActionColumn =&gt;{
                         &lt;td&gt;@s.Header&lt;/td&gt;
                  }
                  case s: Column =&gt; {
                      &lt;td&gt;@s.Header&lt;/td&gt;
                  }
                  case _ =&gt; {}
              }
          }
          &lt;/tr&gt;
      &lt;/thead&gt;
      @for(l &lt;- List) {
          &lt;tr&gt;
          @for(c &lt;- Columns) {
              @c match {
                  case s: LabelColumn =&gt; {
                      @vLabelColumn(ID = s.ID, Header = s.Header, Property = s.Property,
                          Visible = s.Visible)(entity = l)
                  }
                  case s: LinkColumn =&gt; {
                      @vLinkColumn(ID = s.ID, Label = s.Label, Header = s.Header, Property = s.Property,
                          AlternateProperty = s.AlternateProperty, Visible = s.Visible, Enabled = s.Enabled,
                          Url = s.Url, Type = LinkColumnType.Link
                      )(entity = l)
                  }
  
                  case s: MergedActionColumn =&gt; {
                     &lt;td&gt; &lt;table&gt; &lt;tr&gt;
                      @for(s &lt;- s.Actions) {
                          @vLinkColumn(ID = s.ID, Label = s.Label, Header = s.Header, Property = s.Property,
                              AlternateProperty = s.AlternateProperty, Visible = s.Visible, Enabled = s.Enabled,
                              Url = s.Url, Type = LinkColumnType.Action, CssClass = "no-border no-bg"
                          )(entity = l)
                      }
                      &lt;/tr&gt;
                      &lt;/table&gt;
                     &lt;/td&gt;
                  }
              }
          }
          &lt;/tr&gt;
      }
      &lt;/table&gt;
  </code></pre>
  
  <p><em>LinkColumn.scala.html</em></p>
  
  <pre><code>@(  ID: String,
      Label: Option[String] = None,
      Header: String,
      Property: String,
      AlternateProperty: Option[String] = None,
      Visible: Boolean = true,
      Enabled: Boolean = true,
      Url: String =&gt; Call,
      Type: String = code.views.tags.DataGrid.LinkColumnType.Action,
      CssClass: String = "")(implicit entity: Any)
  
      @import code.classes.{EntityFactory =&gt; ef}
  
      &lt;td class="@CssClass"&gt;
          &lt;a href="@Url(ef.getField(entity, Property).toString)" class="@Type"&gt;
              @Label.getOrElse(ef.getField(entity, AlternateProperty getOrElse Property).toString)
          &lt;/a&gt;
      &lt;/td&gt;
  </code></pre>
  
  <p><em>LabelColumn.scala.html</em></p>
  
  <pre><code>@(ID: String,
          Label: Option[String] = None,
          Header: String,
          Property: String,
          AlternateProperty: Option[String] = None,
          Visible: Boolean = true,
          Enabled: Boolean = true)(implicit entity: Any)
  @import code.classes.{EntityFactory =&gt; ef}
  &lt;td&gt;
      @ef.getField(entity, Property)
  &lt;/td&gt;
  </code></pre>
  
  <p><em>Usage of datagrid:</em></p>
  
  <pre><code>@DataGrid(ID = "facilities", List = Facilities, CssClass = "table table-striped table-bordered bootstrap-datatable datatable",
                      ShowCreateButton = true)(
                      Seq(
                          LabelColumn(ID = "ID", Header = "ID", Property = "ID"),
                          LabelColumn(ID = "Name", Header = "Nazwa", Property = "Name"),
                          MergedActionColumn(ID = "Actions", Header = "Actions", Property = "ID", Actions = Seq(
                              LinkColumn(ID = "Update", Header = "ID", Property = "ID", Url = pfc.update, Label = Some("Update")),
                              LinkColumn(ID = "Delete", Header = "ID", Property = "ID", Url = pc.delete, Label = Some("Delete")),
                              LinkColumn(ID = "Delete", Header = "ID", Property = "ID", Url = pc.read, Label = Some("View")),
                              LinkColumn(ID = "Delete", Header = "ID", Property = "ID", Url = pfc.index, Label = Some("Facilities"))
                          ))
                      )
                  )
  </code></pre>
  
  <p>Of course this is only base scaldfolding but it shows how to use playframework views like controls in asp.net or jsf.</p>