我想显示数据表中的值。我打开 chrome 开发工具并转到网络选项卡、XHR,问题是,响应是一个 HTML 文档
服务器端代码:
router.get('/agents', (req, res) => {
let dB = req.dB;
let sql = 'SELECT * FROM tbl_users WHERE role_id = 3';
dB.query(sql, (err, agents) => {
if (err) throw err;
const data = { agents };
console.log(data);
res.render('dashboard/agents', data);
});
});
客户端脚本:
$('#agent_table').DataTable( {
processing: true,
serverSide: true,
ajax: {
url: '/administrator/agents',
type: 'GET',
dataSrc: 'agents'
},
columns: [
{ data: 'user_id' },
{ data: 'checked' },
{ data: 'first_name' },
{ data: 'middle_name' },
{ data: 'role_id' },
]
} );
客户端htmlt:
<table id="agent_table" class="table table-striped table-bordered dt-responsive nowrap"
cellspacing="0" width="100%">
<thead>
<tr>
<th>User ID</th>
<th>
<div class="checkbox checkbox-success select_all">
<input class="styled" type="checkbox" id="check_all">
<label for="check_all" class="check_all_label">All</label>
</div>
</th>
<th>First Name</th>
<th>Middle Name</th>
<th>Last Name</th>
<th>Role</th>
</tr>
</thead>
</table>
控制台登录服务器
{ 代理:[ RowDataPacket { 用户 ID:6, 名字:'帕梅拉', middle_name: '珍珠', 姓氏:'萨贝斯', 电子邮件:'[电子邮件受保护]', 密码: '1bd07c9db7ae63c02f2ee75471727f58', 手机号码: '09503713607', 邀请代码: '', 生日: '2005 年 11 月 29 日', 性别女', 地址: '', 图像:空, 联络人: '', contact_person_number: '', 角色 ID:3, 经度: '', 纬度: '', 医疗信息:'', 已验证:1, 已删除:0, 创建时间:'0000-00-00 00:00:00', 更新时间:2018-05-30T20:42:43.000Z } ] }
我认为问题在于你对 res.render 的使用。因为根据明确的文档 res.render() 函数会编译您的模板,在其中插入本地变量,并从这两个内容中创建 html 输出并将其发送。所以试试这个。
res.json(data)
var url = req.protocol + '://' + req.get('host');
var draw = req.body.draw;
var row = req.body.start;
var count = 1+parseInt(row);
var rowperpage = req.body.length; // Rows display per page
//var columnIndex = req.query.order[0]['column']; // Column index
//console.log(req.body.search);
var dataArr = [];
adminTagModel.CountTagsAll(dataArr, function (totalRecordsValid)
{
var tagDataobj = {
row : row,
rowperpage : rowperpage
};
adminTagModel.showTagsAll(tagDataobj, function (totalValid)
{
for (var i = 0; i < totalValid.length; i++)
{
dataArr.push({ 'count' : count++ ,'tag_name' : totalValid[i].tag_name,'action' : "<a href='"
+url+"/admin/tagdetails/"+totalValid[i].t_id+"' target='_blank' ><i class='fa fa-eye' alt='View Detail'></i></a>"});
}
var response = {
"draw" : draw,
"iTotalRecords" : totalRecordsValid[0].allcount,
"iTotalDisplayRecords" : totalRecordsValid[0].allcount,
"aaData" : dataArr
};
res.send(response);
return response;
});
我最近开发了一个轻量级库来简化 Node.js 中 jQuery 数据表的服务器端处理。它提供对 MySQL 和 Sequelize 的支持:)
图书馆代码
class SSP {
static getData(request, userSqlQuery, columns) {
this.request = request.body;
this.userSqlQuery = userSqlQuery;
this.columns = columns;
this.replacements = {};
this.whereString = '';
this.orderData = this.order();
this.limitData = this.limit();
this.dbcolumns = this.pluck(this.columns, 'db');
this.selectColumns = (this.dbcolumns).map((e, i) => {
return "`" + e + "`";
}).join(',');
return this;
}
static async sequelize(connection) {
let finalRecord = {};
this.filter('sequelize');
let finalQuery = `SELECT SQL_CALC_FOUND_ROWS ${this.selectColumns} FROM (${this.userSqlQuery}) as temp ${this.whereString} ${this.orderData} ${this.limitData}`;
try {
const dbData = await connection.query(
finalQuery,
{
replacements: this.replacements,
type: connection.QueryTypes.SELECT
}
);
const resFilterLength = (await connection.query('SELECT FOUND_ROWS()', {
type: connection.QueryTypes.SELECT
}));
const recordsFiltered = resFilterLength[0]['FOUND_ROWS()'] ?? 0;
const resTotalLength = await connection.query(`SELECT COUNT(*) as datatable_ssp_count FROM (${this.userSqlQuery}) AS temp`, {
type: connection.QueryTypes.SELECT
});
const recordsTotal = resTotalLength[0]['datatable_ssp_count'] ?? 0;
finalRecord.draw = parseInt(this.request.draw);
finalRecord.recordsTotal = parseInt(recordsTotal);
finalRecord.recordsFiltered = parseInt(recordsFiltered);
const mappedData = await this.mapDbToDToColumn(this.columns, dbData);
finalRecord.data = mappedData;
return finalRecord;
} catch (error) {
console.error("Error in sequelize:", error);
return null;
}
}
static async mysql(connection) {
let finalRecord = {};
this.filter('mysql');
let finalQuery = `SELECT SQL_CALC_FOUND_ROWS ${this.selectColumns} FROM (${this.userSqlQuery}) as temp ${this.whereString} ${this.orderData} ${this.limitData}`;
try {
const [dbData, fields] = await connection.query(finalQuery, this.replacements);
const [resFilterLength, resFilterLengthfields] = await connection.query("SELECT FOUND_ROWS()");
const recordsFiltered = resFilterLength[0]['FOUND_ROWS()'] ?? 0;
const resTotalLength = await connection.query(`SELECT COUNT(*) as datatable_ssp_count FROM (${this.userSqlQuery}) AS temp`);
const recordsTotal = resTotalLength[0][0].datatable_ssp_count ?? 0;
finalRecord.draw = parseInt(this.request.draw);
finalRecord.recordsTotal = parseInt(recordsTotal);
finalRecord.recordsFiltered = parseInt(recordsFiltered);
const mappedData = await this.mapDbToDToColumn(this.columns, dbData);
finalRecord.data = mappedData;
return finalRecord;
} catch (error) {
console.error("Error in Mysql:", error);
return null;
}
}
static async mapDbToDToColumn(columns, data) {
var out = [];
for (var i = 0, ien = data.length; i < ien; i++) {
var row = {};
for (var j = 0, jen = columns.length; j < jen; j++) {
var column = columns[j];
if (typeof column.formatter === 'function') {
var formatterResult = column.formatter(data[i][column.db], data[i]) || null;
if (formatterResult instanceof Promise) {
if (column.dt !== undefined) {
row[column.dt] = await formatterResult || null;
} else {
row[column.db] = await formatterResult || null;
}
} else {
if (column.dt !== undefined) {
row[column.dt] = formatterResult;
} else {
row[column.db] = formatterResult;
}
}
} else {
if (column.dt !== undefined) {
row[column.dt] = data[i][columns[j].db];
} else {
row[column.db] = data[i][columns[j].db];
}
}
}
out.push(row);
}
return out;
}
static filter(mode) {
let request = this.request;
let columns = this.columns;
let globalSearch = [];
let columnSearch = [];
let dtColumns = columns.map(column => column.dt);
if (mode === 'mysql') {
this.replacements = [];
}
if (request.search && request.search.value !== '') {
let str = request.search.value;
for (let i = 0; i < request.columns.length; i++) {
let requestColumn = request.columns[i];
let columnIdx = dtColumns.indexOf(requestColumn.data);
columnIdx = (columnIdx <= -1) ? 0 : columnIdx;
let column = columns[columnIdx];
if (requestColumn.searchable === 'true' || requestColumn.searchable === true) {
if (mode === 'sequelize') {
let binding = `ssp_search_value_${i}`;
globalSearch.push("`" + column.db + "` LIKE :" + binding);
this.replacements[binding] = `%${str}%`;
} else if (mode === 'mysql') {
globalSearch.push("`" + column.db + "` LIKE ?");
(this.replacements).push(`%${str}%`);
}
}
}
}
// Individual column filtering
for (let i = 0; i < request.columns.length; i++) {
let requestColumn = request.columns[i];
let columnIdx = dtColumns.indexOf(requestColumn.data);
columnIdx = (columnIdx <= -1) ? 0 : columnIdx;
let column = columns[columnIdx];
let str = requestColumn.search.value;
if ((requestColumn.searchable === 'true' || requestColumn.searchable === true) && str !== '') {
if (mode === 'sequelize') {
let binding2 = `ssp_search_value2_${i}`;
columnSearch.push("`" + column.db + "` LIKE :" + binding2);
let dynamicBindings2 = [];
dynamicBindings2.push({
key: binding2,
value: `%${str}%`
})
} else if (mode === 'mysql') {
columnSearch.push("`" + column.db + "` LIKE ?");
this.replacements.push(`%${str}%`);
}
}
}
this.whereString = '';
if (globalSearch.length > 0) {
this.whereString = '(' + globalSearch.join(' OR ') + ')';
}
if (columnSearch.length > 0) {
this.whereString = this.whereString === '' ?
columnSearch.join(' AND ') :
this.whereString + ' AND ' + columnSearch.join(' AND ');
}
if (this.whereString !== '') {
this.whereString = 'WHERE ' + this.whereString;
}
}
static order() {
let columns = this.columns;
let order = '';
let request = this.request;
if (request.order && request.order.length > 0) {
let orderBy = [];
let dtColumns = columns.map(column => (column.dt ?? column.db));
for (let i = 0, ien = request.order.length; i < ien; i++) {
// Convert the column index into the column data property
let columnIdx = parseInt(request.order[i].column);
let requestColumn = request.columns[columnIdx];
columnIdx = dtColumns.indexOf(requestColumn.data);
let column = columns[columnIdx];
if (requestColumn.orderable === 'true' || requestColumn.orderable === true) {
let dir = request.order[i].dir === 'asc' ? 'ASC' : 'DESC';
orderBy.push('`' + column.db + '` ' + dir);
}
}
order = 'ORDER BY ' + orderBy.join(', ');
}
return order;
}
static limit() {
let start = this.request.start ?? 0;
let length = this.request.length ?? 0;
let limit = '';
if (start !== undefined && length != -1) {
limit = "LIMIT " + parseInt(start) + ", " + parseInt(length);
}
return limit;
}
static pluck(arrayOfObjects, key) {
return arrayOfObjects.map(obj => obj[key]);
}
}
export default SSP;
控制器中的使用
import { mysqlConn, sequelize } from '../config/database.js';
class UserController {
// Usage in Controller
async listdata(req, res) {
let column = [ //column to select database columns
{
'db': 'name', // column name in database
'dt': 'name', // column name in datatable
'formatter': function (data, rowData) { // (For data formatting )optional
return `${data} (${rowData.email})`; // example
}
},
{
'db': 'email',
'dt': 'email',
},
{
'db': 'id',
}
];
let resultSequelize = await (SSP.getData(req, 'select * from users', column)).sequelize(sequelizeConn); // sequelizeConn is sequelize connection instance
// OR
let resultMysql = await (SSP.getData(req, 'select * from users', column)).mysql(mysqlConn); // sequelizeConn is mysql connection instance
res.status(200).json(result);
}
}
查看文件
<div class="container">
<table id="usersTable" class="display" style="width:100%">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
$('#usersTable').DataTable({
"lengthMenu": [[5, 25, 50, -1], [5, 25, 50, "All"]],
processing: true,
serverSide: true,
ajax: {
url: '/list',
type: 'post',
},
columns: [
{ data: 'id' },
{ data: 'name' },
{ data: 'email' },
]
});
</script>