-
-
Save lubiluk/3099013 to your computer and use it in GitHub Desktop.
package code.view | |
import _root_.scala.xml.{ NodeSeq, Node, Elem, PCData, Text } | |
import _root_.net.liftweb.common._ | |
import _root_.net.liftweb.util._ | |
import _root_.net.liftweb.http._ | |
import _root_.net.liftweb.http.js._ | |
import JsCmds._ | |
import JE._ | |
import S._ | |
import SHtml._ | |
import Helpers._ | |
import _root_.net.liftweb.json.JsonDSL._ | |
import _root_.net.liftweb.json._ | |
import scala.util.parsing.json.JSONArray | |
object DataTable { | |
def apply( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
idOpt: Option[String], | |
jsonOptions: List[(String, String)], | |
attrs: (String, String)*) = new DataTable().render(columns, fun, idOpt, jsonOptions, attrs: _*) | |
def apply( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
idOpt: Option[String], | |
attrs: (String, String)*) = new DataTable().render(columns, fun, idOpt, attrs: _*) | |
def apply( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
id: String, | |
attrs: (String, String)*) = new DataTable().render(columns, fun, id, attrs: _*) | |
def apply( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
id: String, | |
jsonOptions: List[(String, String)], | |
attrs: (String, String)*) = new DataTable().render(columns, fun, id, jsonOptions, attrs: _*) | |
} | |
abstract class DataTableSource( | |
val totalRecords: Long, | |
val totalDisplayRecords: Long) { | |
def jsonData: JValue | |
} | |
/** | |
* Class for holding data to be return to DataTable | |
* | |
* Use this class to return data as simple JSON array of arrays | |
*/ | |
class DataTableArraySource( | |
totalRecords: Long, | |
totalDisplayRecords: Long, | |
val data: List[List[String]]) | |
extends DataTableSource(totalRecords, totalDisplayRecords) { | |
def jsonData = JArray(data.map(r => JArray(r.map(JString(_))))) | |
} | |
/** | |
* Class for holding data to be return to DataTable. | |
* | |
* Use this class to return data as JSON array of objects, so you can set DT_RowId and DT_RowClass | |
*/ | |
class DataTableObjectSource( | |
totalRecords: Long, | |
totalDisplayRecords: Long, | |
val data: List[List[(String, String)]]) | |
extends DataTableSource(totalRecords, totalDisplayRecords) { | |
def jsonData = JArray(data.map(r => JObject(r.map(rr => JField(rr._1, JString(rr._2)))))) | |
} | |
/** | |
* Class for holding params sent by DataTable | |
*/ | |
class DataTableParams( | |
val displayStart: Long, | |
val displayLength: Long, | |
val columns: Int, | |
val search: String, | |
val regex: Boolean, | |
val searchable: List[Boolean], | |
val searches: List[String], | |
val regexes: List[Boolean], | |
val sortables: List[Boolean], | |
val sortingCols: Int, | |
val sortCols: List[Int], | |
val sortDirs: List[String], | |
val dataProps: List[String]) | |
class DataTable { | |
/** | |
* Render a DataTable | |
* | |
* @param columns - Column names | |
* @param fun - function that will provide data | |
* @param id - Table id | |
* @param jsonOptions - additional options for DataTable configuration | |
* @param attrs - the attributes that can be added to the table | |
*/ | |
def render( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
id: String, | |
jsonOptions: List[(String, String)], | |
attrs: (String, String)*): Elem = { | |
val idOpt = Some(id) | |
render(columns, fun, idOpt, jsonOptions, attrs: _*) | |
} | |
/** | |
* Render a DataTable | |
* | |
* @param columns - Column names | |
* @param fun - function that will provide data | |
* @param id - Optional table id | |
* @param attrs - the attributes that can be added to the table | |
*/ | |
def render( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
id: String, | |
attrs: (String, String)*): Elem = { | |
val jsonOptions: List[(String, String)] = List() | |
val idOpt = Some(id) | |
render(columns, fun, idOpt, jsonOptions, attrs: _*) | |
} | |
/** | |
* Render a DataTable | |
* | |
* @param columns - Column names | |
* @param fun - function that will provide data | |
* @param idOpt - Optional table id | |
* @param attrs - the attributes that can be added to the table | |
*/ | |
def render( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
idOpt: Option[String], | |
attrs: (String, String)*): Elem = { | |
val jsonOptions: List[(String, String)] = List() | |
render(columns, fun, idOpt, jsonOptions, attrs: _*) | |
} | |
/** | |
* Render a DataTable | |
* | |
* @param columns - Column names | |
* @param fun - function that will provide data | |
* @param idOpt - Optional table id | |
* @param jsonOptions - additional options for DataTable configuration | |
* @param attrs - the attributes that can be added to the table | |
*/ | |
def render( | |
columns: List[String], | |
fun: (DataTableParams) => DataTableSource, | |
idOpt: Option[String], | |
jsonOptions: List[(String, String)], | |
attrs: (String, String)*): Elem = { | |
val f = (ignore: String) => { | |
val columns = S.param("iColumns").dmap(0)(_.toInt) | |
val a = (1 to columns).map(i => S.param("bSearchable_" + i).dmap(false)(_.toBoolean)).toList | |
val params = new DataTableParams( | |
S.param("iDisplayStart").dmap(0)(_.toInt), | |
S.param("iDisplayLength").dmap(0)(_.toInt), | |
columns, | |
S.param("sSearch").dmap("")(_.toString), | |
S.param("bRegex").dmap(false)(_.toBoolean), | |
(1 to columns).map(i => S.param("bSearchable_" + i).dmap(false)(_.toBoolean)).toList, | |
(1 to columns).map(i => S.param("sSearch_" + i).dmap("")(_.toString)).toList, | |
(1 to columns).map(i => S.param("bRegex_" + i).dmap(false)(_.toBoolean)).toList, | |
(1 to columns).map(i => S.param("bSortable_" + i).dmap(false)(_.toBoolean)).toList, | |
S.param("iSortingCols").dmap(0)(_.toInt), | |
(1 to columns).map(i => S.param("iSortCol_" + i).dmap(0)(_.toInt)).toList, | |
(1 to columns).map(i => S.param("sSortDir_" + i).dmap("")(_.toString)).toList, | |
(1 to columns).map(i => S.param("mDataProp_" + i).dmap("")(_.toString)).toList) | |
val source = fun(params) | |
val json = ("iTotalRecords" -> source.totalRecords) ~ | |
("iTotalDisplayRecords" -> source.totalDisplayRecords) ~ | |
("sEcho" -> S.param("sEcho").dmap(0)(_.toInt)) ~ | |
("aaData" -> source.jsonData) | |
JsonResponse(json) | |
} | |
fmapFunc(SFuncHolder(f)) { func => | |
val where: String = encodeURL(S.contextPath + "/" + LiftRules.ajaxPath + "?" + func + "=foo") | |
val id = idOpt getOrElse Helpers.nextFuncName | |
val jqOptions = ("bProcessing", "true") :: | |
("bServerSide", "true") :: | |
("sAjaxSource", where.encJs) :: | |
Nil ::: jsonOptions | |
val json = jqOptions.map(t => t._1 + ":" + t._2).mkString("{", ",", "}") | |
val datatableOptions = JsRaw(json) | |
val onLoad = JsRaw(""" | |
$(document).ready(function() { | |
$("#""" + id + """").dataTable(""" + datatableOptions.toJsCmd + """); | |
});""") | |
attrs.foldLeft( | |
<table id={ id }> | |
<head_merge> | |
<script type="text/javascript" src="/scripts/jquery.dataTables.js"></script> | |
{ Script(onLoad) } | |
</head_merge> | |
<thead> | |
<tr> | |
{ columns.map(c => <th>{ c }</th>) } | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
{ columns.map(_ => <td></td>) } | |
</tr> | |
</tbody> | |
</table>)(_ % _) | |
} | |
} | |
} |
Hi Andrea,
First thing - you didn't configure your data table to display 10 rows per page. You need to set DisplayLength parameter in order to do that. (But I guess 10 is default so it may stay unconfigured)
Second and more important thing is that I can see that your function "fun" doesn't care about what "params" it gets. It should look at the displayStart and displayLength values and return data rows accordingly.
I know I didn't documented this thoroughly... yet.
Cheers,
Hi,
I just tried your DataTable View - its amazing - thanks a lot.
I think I found a little bug - dataTable parameters column counts start with 0 not 1, so I needed to adjust your parameter parsing to
...
(0 to columns-1).map(i => S.param("sSortDir_" + i).dmap("")(_.toString)).toList,
...
cheers
stefan
Hi Pawel,
I'm trying to implement a datatable with lift using the server processing.
I took inspiration from your snippet but I can not get it to work properly.
My test view is as follows:
def table = {
val cols = "Types value" :: "Actions" :: Nil
}
In this example, my goal is to display the first 10 rows and then display the eleventh by clicking on the second page of the paginator.
The problem is that I see 11 rows in both the first and in the second page.
The combo box, the paginator and the description at the bottom left work properly but the datatable never changes. What's wrong?
Thanks in advance.
Greetings