r.piesnikowski
r.piesnikowski

Reputation: 2951

Playframework datagrid template

I have one question about design and basic implementation of server side data grid control(something like asp.net GridView).

I have created dummy DataGrid.scala.html but I can be written in more sophisticated and functional (with functional programming) way.

    @(ID: String, List: Seq[model.admin.Partner.Partner], Columns: Seq[String])(content: Html= Html(""))
@import model.admin.Partner.Partner
<table>
    <thead>
        <tr>
        @for(j <- Columns) {
            <td>@j</td>
        }
        </tr>
    </thead>

    @for(i <- List) {
        <tr> @for(j <- Columns) {
            <td> @code.classes.EntityFactory.getValue[Partner](i, j)</td>
        }
        </tr>
    }
</table>

Basically I have one loop for table headers and second double loop for getting value by Reflection.

object EntityFactory {
  def getValue[T](entity: T,fieldName: String)(implicit ev: scala.reflect.ClassTag[T]) = {
    entity.getClass.getMethods.find(_.getName == fieldName).get.invoke(entity)
  }
}

In my view I use this Datagrid like this:

    @DataGrid(ID = "partners", List = Partners, Columns = Seq("ID","Name", "ShortName")){

                    }

What I wish to have

I want have something like this:

@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")
                    }

Here I created structure for this

enter image description here

In some columns I would like to do some trick to inject into Url route value from Property. Something like that:

    @(ID: String,entity: Partner, Property: String, Url: String)
@import model.admin.Partner.Partner
    <div>
        here I want to inject code.classes.EntityFactory.getValue[Partner](entity,"ID")
        into @Url
    </div>
<a href="@Url(code.classes.EntityFactory.getValue[Partner](entity,Property))">klik</a>

Thanks for reading and help.


EDIT

After some time I finally found answer by myselve. This code is divided by two areas: code and view.

Code

Here are traits or classes which describe types of column.

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 => 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"
}

And some helpers code.

object EntityFactory {
  def getField(entity: Any,fieldName: String) = {
    entity.getClass.getMethods.find(_.getName == fieldName).get.invoke(entity)
  }
}

Views

DataGrid.scala.html

@(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 => ef}
@import code.views.tags.DataGrid.{LabelColumn, LinkColumn, Column, MergedActionColumn}
@import views.html.tags.controls.DataGrid.{LabelColumn => vLabelColumn, LinkColumn => vLinkColumn}
@import code.views.tags.DataGrid.LinkColumnType
@import code.Ext

    @if(ShowCreateButton){
        <a class="btn btn-success" href="@controllers.admin.routes.PartnerController.create()">
            <i class="icon-zoom-in icon-white"></i>
            @Ext.te("common.add", lang.code)
        </a>
    }
<table class="@CssClass">
    <thead>
        <tr>
        @for(j <- Columns) {
            @j match {
                case s: MergedActionColumn =>{
                       <td>@s.Header</td>
                }
                case s: Column => {
                    <td>@s.Header</td>
                }
                case _ => {}
            }
        }
        </tr>
    </thead>
    @for(l <- List) {
        <tr>
        @for(c <- Columns) {
            @c match {
                case s: LabelColumn => {
                    @vLabelColumn(ID = s.ID, Header = s.Header, Property = s.Property,
                        Visible = s.Visible)(entity = l)
                }
                case s: LinkColumn => {
                    @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 => {
                   <td> <table> <tr>
                    @for(s <- 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)
                    }
                    </tr>
                    </table>
                   </td>
                }
            }
        }
        </tr>
    }
    </table>

LinkColumn.scala.html

@(  ID: String,
    Label: Option[String] = None,
    Header: String,
    Property: String,
    AlternateProperty: Option[String] = None,
    Visible: Boolean = true,
    Enabled: Boolean = true,
    Url: String => Call,
    Type: String = code.views.tags.DataGrid.LinkColumnType.Action,
    CssClass: String = "")(implicit entity: Any)

    @import code.classes.{EntityFactory => ef}

    <td class="@CssClass">
        <a href="@Url(ef.getField(entity, Property).toString)" class="@Type">
            @Label.getOrElse(ef.getField(entity, AlternateProperty getOrElse Property).toString)
        </a>
    </td>

LabelColumn.scala.html

@(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 => ef}
<td>
    @ef.getField(entity, Property)
</td>

Usage of datagrid:

@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"))
                        ))
                    )
                )

Of course this is only base scaldfolding but it shows how to use playframework views like controls in asp.net or jsf.

Upvotes: 2

Views: 1042

Answers (1)

1esha
1esha

Reputation: 1722

You may want to check existing form helpers and also (outdated) bootstrap support. Check corresponding html.scala files in play sources

It is good example of implementation non trivial components in play.

Upvotes: 0

Related Questions