带有 REST API 的可编辑 jQuery Grid 推荐

Posted

技术标签:

【中文标题】带有 REST API 的可编辑 jQuery Grid 推荐【英文标题】:Editable jQuery Grid Recommendations with REST API 【发布时间】:2012-05-30 18:04:56 【问题描述】:

首先,我已经阅读了问题“jQuery Grid Recommendations”,但它没有回答我的问题。

我有一个小的REST API with MongoDB Backend 只是:

获得所有装备:

GET /equipements HTTP/1.1
_id:key1, name:Test Document 1, plateforme:prod, _id:key2, name:Test Document 2, plateforme:prod, ...

用钥匙获取装备:key1

GET /equipements/key1 HTTP/1.1
"_id": "key1", "name": "Test Document 1", "plateforme": "prod"

添加新设备

PUT /equipements HTTP/1.1  "_id": "key8", "name": "Test Document 3", "plateforme": "prod"
HTTP/1.0 200 OK

现在,我需要找到一种简单的方法来让 lambda 用户添加/查看/删除设备。所以我认为带有类似 UI 的 jQuery 的 Web 界面是最好的。我tried 和Sencha Rest Proxy 但我不知道javascript,我无法适应这个例子。

如何为我的 REST 后端修复我的 javascript?

与/或

您能否推荐一个更简单的 Sencha Rest Proxy 替代方案?(适用于我的 REST 后端)

答案: jqGrid

与/或

你会推荐我什么 jQuery Grid?(适用于我的 REST 后端)

答案: jqGrid

最后一个问题:为什么我的单元格不能通过双击进行编辑?

附录

服务器端(编辑:添加方法 POST)

#!/usr/bin/python
import json
import bottle
from bottle import static_file, route, run, request, abort, response
import simplejson
import pymongo
from pymongo import Connection
import datetime



class MongoEncoder(simplejson.JSONEncoder):
    def default(self, obj):
                # convert all iterables to lists
        if hasattr(obj, '__iter__'):
            return list(obj)
        # convert cursors to lists
        elif isinstance(obj, pymongo.cursor.Cursor):
            return list(obj)
        # convert ObjectId to string
        elif isinstance(obj, pymongo.objectid.ObjectId):
            return unicode(obj)
        # dereference DBRef
        elif isinstance(obj, pymongo.dbref.DBRef):
            return db.dereference(obj)
        # convert dates to strings
        elif isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) or isinstance(obj, datetime.time):
            return unicode(obj)
        return simplejson.JSONEncoder.default(self, obj)



connection = Connection('localhost', 27017)
db = connection.mydatabase

@route('/static/<filename:path>')
def send_static(filename):
    return static_file(filename, root='/home/igs/restlite/static')

@route('/')
def send_static():
    return static_file('index.html',root='/home/igs/restlite/static/')

@route('/equipements', method='PUT')
def put_equipement():
    data = request.body.readline()
    if not data:
        abort(400, 'No data received')
    entity = json.loads(data)
    if not entity.has_key('_id'):
        abort(400,'No _id specified')
    try:
        db['equipements'].save(entity)
    except ValidationError as ve:
        abort(400, str(ve))

@route('/equipements', method='POST')
def post_equipement():
    data = request.forms

    if not data:
        abort(400, 'No data received')
    entity = 
    for k,v  in data.items():
        entity[k]=v

    if not entity.has_key('_id'):
        abort(400,'No _id specified')
    try:
        db['equipements'].save(entity)
    except ValidationError as ve:
        abort(400, str(ve))


@route('/equipements/:id', methodd='GET')
def get_equipement(id):
    entity = db['equipements'].find_one('_id':id)
    if not entity:
        abort(404, 'No equipement with id %s' % id)
    return entity

@route('/equipements', methodd='GET')
def get_equipements():
    entity = db['equipements'].find()
    if not entity:
        abort(404, 'No equipement')
    response.content_type = 'application/json'
    entries = [entry for entry in entity]
    return MongoEncoder().encode(entries)

run(host='0.0.0.0', port=80)

编辑:JQGrid:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Rest Proxy Example</title>
    <link rel="stylesheet" type="text/css" href="/static/css/ui.jqgrid.css" />
    <link rel="stylesheet" type="text/css" href="/static/css/jquery-ui-1.8.20.custom.css" />

    <script type="text/javascript" src="/static/js/jquery.js"></script>
    <script type="text/javascript" src="/static/js/jquery.jqGrid.min.js"></script>
    <script type="text/javascript" src="/static/js/grid.locale-fr.js"></script>
    <script type="text/javascript">
        jQuery(document).ready(function()
            var lastsel;

jQuery("#list2").jqGrid(
    url:'equipements',
    datatype: "json",
    colNames:['Id','Name', 'Plateforme'],
    colModel:[
        name:'_id',index:'_id', width:50, editable:true,
        name:'name',index:'_id', width:300, editable:true,
        name:'plateforme',index:'total', width:200,align:"right", editable:true,
    ],
    rowNum:30,
    rowList:[10,20,30],
    pager:'pager2',
    sortname: '_id',
    viewrecords: true,
    width: 600,
    height: "100%",
    sortorder: "desc",
    onSelectRow: function(_id)
        if(_id && _id!==lastsel)
            jQuery('#liste2').jqGrid('restoreRow',lastsel);
            jQuery('#liste2').jqGrid('editRow',_id,true);
            lastsel=_id;
        
    ,
    jsonReader: 
        repeatitems: false,
        id: "_id",
        root: function (obj)  return obj; ,
        records: function (obj)  return obj.length; ,
        page: function (obj)  return 1; ,
        total: function (obj)  return 1; 
    ,
    editurl:'equipements',
    caption:"Equipements"
);
jQuery("#list2").jqGrid('navGrid','#pager2',edit:true,add:true,del:true);
);
    </script>
</head>
<body>
    <table id="list2"></table>
    <div id="pager2"></div>
    <br />

</body>
</html>

【问题讨论】:

"我不知道 javascript" - 如果您尝试为 REST 客户端制作前端,那将不得不改变。花时间学习 JavaScript;它最终会得到回报,而且它不是一门很难的语言。 仅供内部团队使用,编写Web前端不是我的工作。有一天,我会学习javascript。但是现在,我有很多更重要的东西。 【参考方案1】:

您可以使用 jqGrid 与您的 RESTfull 服务进行通信。 jqGrid 支持树形编辑模式:单元格编辑、内联编辑和表单编辑。此外,内联编辑可以以不同的方式初始化。例如,可以在onSelectRowondblClickRow 回调中调用editRow 方法,或者使用navGrid 在navigator 工具栏中添加“删除”按钮,使用inlineNav 添加“添加”和“编辑”按钮.另一种方法是使用formatter: "actions" 在网格的一列中包含“编辑”按钮。您可以在the official jqGrid demo 中找到所有方法。更多技术实现细节可以在the answer找到。

我个人认为了解在 Web 前端使用 RESTfull 服务的另一个重要方面非常重要。问题是标准的 RESTfull API 没有任何用于数据排序、分页和过滤的标准接口。我试着解释下面的问题。在那之后,我希望 我的建议是明确的,即使用具有附加参数并提供排序、分页和过滤功能的附加方法来扩展当前的标准 RESTfull API。

如果您有大型数据集,这个问题很容易理解。例如,一次在网格中显示 10000 行数据是没有意义的。如果没有scollingpaging 数据,用户将无法在屏幕上看到数据。此外,出于同样的原因,实现数据的排序甚至过滤也是有意义的。因此,在开始时只显示一页数据并为用户提供一些数据分页界面更为实用。在 jqGrid 的标准 pager 中看起来像

用户可以转到“下一个”、“最后一个”、“上一个”或“第一个”页面或选择页面大小:

此外,用户可以通过直接输入新页面并按Enter来指定所需的页面:

同理,用户可以点击任意一列的表头,按列对网格数据进行排序:

另一个非常重要的用户界面元素(从用户的角度来看很重要)可能是一些过滤界面,例如 here 或搜索界面,例如 here。

我给你一个来自 jqGrid 的例子,但我发现这个问题很常见。 我想强调的是,RESTfull 服务没有为您提供对数据进行排序、分页和过滤的标准接口

在使用 jqGrid 的情况下,RESTfull url 将默认获取 附加 参数。它是:pagerows 指定将从服务中询问的页码和页面大小、sidxsord 指定排序列和排序方向的参数以及 _search 和 @987654346 @(最后一个在the format)允许支持过滤。如果需要,可以使用 jqGrid 的prmNames 选项重命名参数。

我建议您阅读the answer 关于 URL 编码的问题。我认为 _search=false&amp;rows=20&amp;page=1&amp;sidx=&amp;sord=asc 部分不属于资源,因此最好将信息作为 parameters 而不是作为 URL 的一部分发送。

我在回答中主要想表达的是,纯经典 RESTfull API 的使用不足以实现良好的用户界面。您将不得不使用用于分页、排序和过滤的附加参数来扩展界面,否则您将无法创建高性能和用户友好的 Web GUI。

【讨论】:

感谢您这么长的回答。有点它没有回答我的问题:事实上,不可能将 jQGrid 与我的 REST 后端一起使用。 jQGrid 使用特定的 jsojn 格式: total: xxx, page: yyy, records: zzz, rows: [ name1:”Row01″,name2:”Row 11″,name3:”Row 12″,name4:”Row 13″,name5:”Row 14″, ... @Yohann:不! jqGrid 几乎可以读取任何 JSON 格式,您只需使用相应的jsonReader。您没有详细描述您当前的数据格式,但我认为以下jsonReader 将适用于您的情况:jsonReader: repeatitems: false, id: "_id", root: function (obj) return obj; , records: function (obj) return obj.length; , page: function (obj) return 1; , total: function (obj) return 1; @Yohann: 输入数据的标准格式看起来有点奇怪,但是如果你从服务器的字符串数组而不是 named 属性发送你可以减少数据的大小在服务器和客户端之间传输。此外,它要求用户指定每一行的唯一 id,因为id 将用作&lt;tr&gt;id - rowid。 谢谢!现在,我只需要修复一些 javascript 即可拥有可编辑的单元格! @Yohann:不客气!您应该选择最符合您要求的编辑模式。

以上是关于带有 REST API 的可编辑 jQuery Grid 推荐的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 Django REST 框架中的可浏览 API 上传文件?

用于银行交易中预期目的的带有自定义发票编号的 PayPal Rest API 付款

如何在 C# Rest API 中处理查询参数中的可选 ENUM - 无效和空值以及在 Swagger 中隐藏特定值

带有核心数据的可编辑表格视图

如何在带有 defaultValue 的可选字段上使用 jQuery Validator 自定义方法?

带有角度 JS 的可编辑文本就像普通链接一样