我试图通过制作众所周知的待办事项列表来自学MEAN堆栈。一切都很好,除了我的表单似乎一次发送多个POST请求。我通过一个包含待执行任务和标记的简单JSON发送。这些按照他们应该做的并出现在页面上。但与此同时,一个或多个(我似乎无法找到模式)*不需要的额外POST请求通过相同JSON的空版本发送,导致空白条目被发布到网站。
我通过Heroku在Node.js和MongoDB上使用Express。
app.js
var main = function(toDoObjects) {
"use strict";
var toDos = toDoObjects.map(function(todo) {
return todo.description;
});
console.log(toDos);
//Create an empty array of tabs
var tabs = [];
//Add the 'Newest' tab
tabs.push({
"name":"Newest",
"content":function(callback) {
$.get("todos.json", function(toDoObjects) {
var $content;
$content = $("<ul>");
for (var i = toDos.length - 1; i >= 0; i--) {
$content.append($("<li>").text(toDos[i]));
}
callback($content);
});
}
});
//Add the 'Oldest' tab
tabs.push({
"name":"Oldest",
"content":function(callback) {
$.get("todos.json", function(toDoObjects) {
var $content;
$content = $("<ul>");
toDos.forEach(function(todo) {
$content.append($("<li>").text(todo));
});
callback($content);
});
}
});
//Add the 'Tags' tab
tabs.push({
"name":"Tags",
"content":function(callback) {
$.get("todos.json", function(toDoObjects) {
var theTags, $content;
theTags = [];
$content = $("<div>");
toDoObjects.forEach(function(toDos) {
// Build array of unique tags
toDos.tags.forEach(function(tag) {
if (theTags.indexOf(tag) === -1)
theTags.push(tag);
});
});
//Map toDos onto tags
var newToDoList = theTags.map(function(theTag) {
var toDosWithTag = [];
toDoObjects.forEach( function(toDos) {
if (toDos.tags.indexOf(theTag) !== -1)
toDosWithTag.push(toDos.description);
});
return { "name" : theTag, "toDos" : toDosWithTag };
});
newToDoList.forEach(function(tag) {
var $tagName = $("<h3 class='tag-header'>").text(tag.name);
var $taggedTasks = $("<ul class='tags'>");
tag.toDos.forEach(function(description) {
var $li = $("<li>").text(description);
$taggedTasks.append($li);
});
$content.append($tagName);
$content.append($taggedTasks);
});
callback($content);
});
}
});
//Add the 'Add' tab
tabs.push({
"name":"Add",
"content":function(callback) {
// $.get("todos.json", function(toDoObjects) {
var $input,$inputLabel,$tagInput,$tagLabel,$button,$content;
$input = $("<input>").addClass("description"),
$inputLabel = $("<p>").text("Description: "),
$tagInput = $("<input>").addClass("tags"),
$tagLabel = $("<p>").text("Tags: "),
$button = $("<button>").text("+");
$content = $("<div>").append($inputLabel)
.append($input)
.append($tagLabel)
.append($tagInput)
.append($button);
$(".content").on("click", "button", function() {
var description = $input.val(),
tags = $tagInput.val().split(","),
newToDo = {"description": description, "tags": tags};
console.log(newToDo);
if ($(".description").val() !== "" && $(".tags").val() !== "" ) {
//example post to todos route
$.post("todos", newToDo, function(result) {
// this callback is called when the server responds
console.log(result);
toDos = result.map(function(todo) {
return todo.description;
});
console.log(toDos);
$input.val("");
$tagInput.val("");
});
}
});
$(".content").on("keypress", "input", function(event) {
if (event.keyCode === 13) {
var description = $input.val(),
tags = $tagInput.val().split(","),
newToDo = {"description": description, "tags": tags};
if ($(".description").val() !== "" && $(".tags").val() !== "" ) {
$.post("todos", newToDo, function(result) {
// this callback is called when the server responds
console.log(result);
toDos = result.map(function(todo) {
return todo.description;
});
console.log(toDos);
$input.val("");
$tagInput.val("");
});
}
}
});
callback($content);
// });
}
});
tabs.forEach(function(tab) {
var $aElement = $("<a>").attr("href",""),
$spanElement = $("<span>").text(tab.name);
$aElement.append($spanElement);
$spanElement.on("click", function() {
$(".tabs a span").removeClass("active"); //make all tabs inactive
$spanElement.addClass("active"); //make clicked tab active
$("main .content").empty(); //empty the content
//send callback
tab.content(function($content) {
$("main .content").append($content);
});
return false;
});
$("main .tabs").append($aElement);
});
$(".tabs a:first-child span").trigger("click");
};
$(document).ready(function() {
$.getJSON("toDos.json", function(toDoObjects) {
main(toDoObjects);
});
});
server.js
var express = require("express"),
http = require("http"),
//import the mongoose library
mongoose = require("mongoose"),
uriUtil = require("mongodb-uri"),
app = express();
app.use(express.static(__dirname + "/client"));
// Tell Express to parse incoming JSON objects
app.use(express.urlencoded());
// Set Mongoose options
var options = { server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
replset: { socketOptions: { keepAlive: 1, connectTimeoutMS : 30000 } } };
//MongoLab variables
var mongodbUri = 'mongodb://<REDACTED>';
var mongooseUri = uriUtil.formatMongoose(mongodbUri);
// Connect to the Amazeriffic data store in mongo
mongoose.connect(mongodbUri, options);
// Mongoose model for todos
var ToDoSchema = mongoose.Schema({
description: String,
tags: [ String ]
});
var ToDo = mongoose.model("ToDo", ToDoSchema);
// Now listen for requests -- env variable for Heroku port assignment
http.createServer(app).listen(process.env.PORT || 3000);
app.get("/todos.json", function(req, res) {
ToDo.find({}, function(err, toDos) {
res.json(toDos);
});
});
app.post("/todos", function(req, res) {
// The object is now stored in req.body
console.log(req.body);
var newToDo = new ToDo({"description":req.body.description,
"tags":req.body.tags});
newToDo.save(function(err, result) {
if (err !== null) {
console.log(err);
res.send("ERROR");
} else {
// additional request to ensure compatibility
// client expects entire list to be returned
ToDo.find({}, function(err, result) {
if (err !== null) {
//the element didn't get saved
res.send("ERROR");
}
res.json(result);
});
}
});
});
*编辑毕竟看起来像是一个模式。第一次单击会添加一个条目。第二次单击会添加一个条目加一个空白。第三次单击会添加一个条目加上两个空格,依此类推。很明显,我已经搞砸了某个地方的逻辑。