美好的一天,hoomans!我非常需要你的帮助!
我的问题:有没有办法(在NodeJS / ExpressJS中)动态改变一个元素,例如在POST请求时添加新的li,就像点击提交按钮后一样(不使用jsdom)? < / p>
我正在开发一个非常简单的应用程序,它应该允许客户(学生)通过简单的动态和实时功能跟踪他/她的每个班级的课程,监控他/她的成绩等。我正在使用Node.js EXPRESS,mySQL和AngularJS。
我创建了一个功能,学生可以搜索课程,然后实时收到结果列表,这基本上意味着我想根据请求动态添加 li 元素,而无需重新加载页面或重定向客户到另一页。
过程是:(1)学生在课程名称中输入,(2)在请求时传递文本字段的值(帖子),(3)使用该值作为数据库搜索的关键,(4)然后通过填充 ul 元素。
数据库的工作原理。它能够使用在文本字段中输入的值从数据库中检索数据。但是,当我添加代码以动态添加 li 元素时,每次发出请求时都会收到运行时错误。此代码可在 routes / grades.js 中找到。
我得到的错误是:
抛出错误; //重新抛出非MySQL错误 ^TypeError:req.body.getElementById不是函数
这是由此代码块引起的
var ul = req.body.getElementById(&#34; search&#34;);
var li = req.body.createElement(&#34; li&#34;);
li.appendChild(req.body.createTextNode(reqObj [&#34;的className&#34;]));
我相信 createElement 和 createTextNode 也会导致相同的错误消息。
我认为这可以通过 jsdom 解决,但是当我尝试通过npm安装它时,我只收到很多错误,所以我放弃了。此外,我相信有一个更简单的解决方案,我还不知道。
以下是我上面提到的功能的主要文件。
视图/ grades.ejs
<!DOCTYPE html>
<html ng-app="ClassSaber">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="javascripts/app.js" type="text/javascript"></script>
</head>
<body ng-controller="classController">
<% include template/header2.ejs %>
<div class="lessons" id="homebranding_top">
<section>
<h1>Grades</h1>
<hr>
</section>
<section>
<p>
Keeping track of your progress eh? That's great! Search your class and we'll show your grade.
</p>
</section>
<form>
<section id="class_search">
<input type="text" id="search" ng-model="data.className" placeholder="Enter your class here...">
<input type="submit" value="Search" ng-click="classFun()">
<ul id="class_list">
<li ng-repeat="item in list | filter: data.className">
{{item.Class_Name}}
</li>
</ul>
</section>
</form>
</div>
</body>
</html>
routes / grades.js
var express = require('express');
var router = express.Router();
var path = require('path');
/* GET lessons page. */
router.get('/grades', function(req, res, next) {
res.render('grades', { title: 'Class Saber | Grades' });
});
module.exports = router;
//search class in the database
router.post('/grades', function(req, res, next){
try{
var reqObj = req.body;
console.log("Request Object: " + reqObj["className"]);
req.getConnection(function(err, conn){
if(err){
console.error('SQL Connection error: ', err);
return next(err);
}
else{
var insertSql = "SELECT Class_Name FROM classes WHERE Class_Name LIKE ?";
var insertValues = [
'%' + reqObj["className"] + '%'
];
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode(reqObj["className"]));
});
}
});
}
catch(ex){
console.err("Internal error: " + ex);
return next(ex);
}
});
公开/ Javascript角/ app.js
var app = angular.module('ClassSaber', []);
app.controller('classController', function($scope, $http){
$scope.data = {};
$scope.list = [
{Class_Name: 'Math 101'},
{Class_Name: 'Physics 101'},
{Class_Name: 'Major Elective: Quantum Mechanics'}
];
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
})
}
});
答案 0 :(得分:0)
req.body
包含请求的正文(您通过$http
调用传递的数据),而不是DOM的body
元素。您无法从服务器端环境(如nodejs)访问客户端元素(如DOM),反之亦然。如果您想对DOM进行更改,请返回必须使用您的响应更改的说明以及浏览器中的相应更改。
我不使用角度,所以我不能直接告诉你如何做到这一点。但总的来说,它会是这样的:
var query = conn.query(insertSql, insertValues, function(err, result) {
if (err) {
console.error('SQL error: ', err);
return next(err);
}
// response with a list of action to be applied
res.send([{
action : 'append-to-dom',
info : {
/* all informations you need for this e.g. reqObj["className"] */
}
}]);
});
在您的客户端代码中,您将检查您必须执行的操作:
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function(httpResponse) {
// check the content of your response if it contains actions
/*
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode( .. the data from your response ... ))
*/
})
如何构建响应取决于您并且取决于环境。 Angular可能已经有一个特定的模式如何做到这一点,但正如我所说,我不使用角度所以我不能告诉你。
答案 1 :(得分:0)
t.niese 给我的概念非常有用,我能解决问题。
以下是我根据建议的答案所做的更改:
在我的路线中
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var class_array = [];
for(var i=0; i<result.length; i++){
class_array.push(result[i]);
}
console.log(class_array.valueOf());
res.send([{
info: class_array.valueOf()
}])
});
以及我的客户端代码
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
var tbody = document.getElementById("class_list_data");
while(tbody.firstElementChild){
tbody.removeChild(tbody.firstChild);
}
for(var i=0; i<httpResponse.data.length; i++){
for(var j=0; j<httpResponse.data[i].info.length; j++){
var tr = document.createElement("tr");
var td = document.createElement("td");
td.appendChild(document.createTextNode(httpResponse.data[i].info[j].Class_Name.toString()));
tr.appendChild(td);
tbody.appendChild(tr);
}
}
})
}
另外,我对模板进行了一些修改。我使用表格。
代替列表<div id="homebranding_middle">
<table id="class_list">
<thead>
<th>CLASS DESCRIPTION</th>
<th>SCHEDULE</th>
<th>CLASSROOM ASSIGNMENT</th>
<th>INSTRUCTOR</th>
</thead>
<tbody id="class_list_data">
<tr id="class_list_row" ng-repeat="item in list | filter: {Class_Name: data.className}">
<td><a href="">{{item.Class_Name}}</a></td>
<td>{{item.Class_Code}}</td>
<td>{{item.Class_Room}}</td>
<td>{{item.Class_Instructor}}</td>
<dynamic></dynamic>
</tr>
</tbody>
</table>
</div>
总而言之,我的 / grade 页面现在可以实际执行某些操作。我得到状态代码200,并且可以播放来自DB的所有检索数据。
非常感谢 t.niese !干杯!