我正在教自己构建MEAN应用程序的细节。我从基本的todo应用程序开始,并对其进行了大量修改,以支持多个键值对,并使用bootstrap更新了UI。
目前托管在此处:http://surveymanager-30817.onmodulus.net/
我实现了ui-sortable,它本身就很完美。
我遇到的挑战,我似乎无法找到任何相关的文档或教程 - 是如何将更新的排序顺序传达给mongo所以当我刷新页面时,ng-repeat会在问题中重复提问我之前创建的订单。
这是HTML
<!-- index.html -->
<!doctype html>
<!-- ASSIGN OUR ANGULAR MODULE -->
<html ng-app="QuestionManager">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->
<title>Question Manager</title>
<!-- SCROLLS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/question-bootstrap.css" rel="stylesheet">
<style>
html { overflow-y:scroll; }
body { padding-top:30px; }
#todo-list { margin-bottom:30px; }
</style>
<!-- SPELLS -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
<script src="//code.jquery.com/ui/1.9.1/jquery-ui.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
<script src="js/sortable.js"></script>
<script src="core.js"></script>
</head>
<!-- SET THE CONTROLLER AND GET ALL TODOS -->
<body ng-controller="mainController">
<div class="container sm_head">
<div class="col-sm-6">
</div>
<div class="col-sm-6">
<h2 class="pull-right">Survey Manager</h2>
</div>
</div>
<div class="container">
<!-- Nav tabs -->
<ul id="navtabs" class="nav nav-tabs" role="tablist">
<li class="active"><a href="#manage" role="tab" data-toggle="tab">Manage</a></li>
<li><a href="#create" role="tab" data-toggle="tab">Create</a></li>
<li><a href="#render" role="tab" data-toggle="tab">Render Code</a></li>
<li><a href="#abouts" role="tab" data-toggle="tab">About</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="manage">
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">Manage Question Order<span class="badge pull-right">{{ questions.length }} Questions</span></div>
<!-- Table -->
<table class="table">
<thead>
<tr>
<th>Order</th>
<th>Question Name</th>
<th>Evergage Field</th>
<th>Username</th>
<th>Options</th>
</tr>
</thead>
<tbody ui-sortable="sortableOptions" ng-model="questions">
<tr ng-repeat="question in questions">
<td>{{ question.order }}</td>
<td>{{ question.meanName }}</td>
<td>{{ question.fieldName }}</td>
<td>@mdo</td>
<td>
<button type="button" class="btn btn-default btn-sm" ng-click="deleteQuestion(question._id)">
<span class="ques-list glyphicon glyphicon-remove"></span> delete </button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-8">
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>Question Details</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Question Name">Question Order</label>
<div class="col-md-8">
<input id="Question Order" name="Question Order" type="text" placeholder="Question Order" class="form-control input-md" ng-model="formData.order">
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Question Name">Question Name</label>
<div class="col-md-8">
<input id="Question Name" name="Question Name" type="text" placeholder="Write something meaningful" class="form-control input-md" ng-model="formData.meanName">
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Custom Field Name">Custom Field</label>
<div class="col-md-8">
<input id="Custom Field Name" name="Custom Field Name" type="text" placeholder="Format: User.Profile.xx.xx.xx ( 1 or 3 additional words)" class="form-control input-md" ng-model="formData.fieldName">
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="Create"></label>
<div class="col-md-4">
<button id="Create" name="Create" class="btn btn-primary" ng-click="createQuestion()">Create</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
<div class="tab-pane" id="create">
</div>
<div class="tab-pane" id="render">...</div>
<div class="tab-pane" id="about">...</div>
</div>
</div>
<script src="js/bootstrap.min.js"></script>
</body>
</html>
这是客户端:
// public/core.js
var QuestionManager = angular.module('QuestionManager', ['ui.sortable']);
function mainController($scope, $http) {
$scope.formData = {};
// when landing on the page, get all questions and show them
$http.get('/api/questions')
.success(function(data) {
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
// when submitting the add form, send the text to the node API
$scope.createQuestion = function() {
$http.post('/api/questions', $scope.formData)
.success(function(data) {
$scope.formData = {};
console.log('fuck you!');
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
// delete a question after checking it
$scope.deleteQuestion = function(id) {
$http.delete('/api/questions/' + id)
.success(function(data) {
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.$watch("questions", function(newVal, oldVal) {
console.log("oldval", oldVal);
console.log("newVal", newVal);
});
$scope.sortableOptions = {
update: function(e, ui) {
$http.put('/api/questions', $scope.questions)
console.log($scope.questions);
},
axis: 'y'
};
}
// Some Bootstrap Initializers
$('#navtabs>li a').click(function (e) {
e.preventDefault()
$(this).tab('show')
})
这是服务器端,我的随机测试和控制台日志从第44行开始
// server.js
var express = require('express');
var app = express(); // create our app w/ express
var mongoose = require('mongoose'); // mongoose for mongodb
var morgan = require('morgan'); // log requests to the console (express4)
var bodyParser = require('body-parser'); // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
mongoose.connect('mongodb://ewill3532:12qwaszx@proximus.modulusmongo.net:27017/pUxo2hir'); // connect to mongoDB database locally
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
var question = mongoose.model('question', {
order : String,
fieldName : String,
meanName : String
});
app.get('/api/questions', function(req, res) {
// use mongoose to get all questions in the database
question.find(function(err, questions) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
res.json(questions); // return all questions in JSON format
});
});
// create todo and send back all questions after creation
app.post('/api/questions', function(req, res) {
// create a todo, information comes from AJAX request from Angular
question.create({
order : req.body.order,
fieldName : req.body.fieldName,
meanName : req.body.meanName,
done : false
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the questions after you create another
question.find(function(err, questions) {
if (err)
res.send(err)
res.json(questions);
});
});
});
// delete a todo
app.delete('/api/questions/:todo_id', function(req, res) {
question.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the questions after you create another
question.find(function(err, questions) {
if (err)
res.send(err)
res.json(questions);
});
});
});
// let's just put this here so that it comes back as found
app.put('/api/questions', function(req, res) {
});
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
// listen (start app with node server.js) ======================================
app.listen(8080);
console.log("App listening on port 8080");
这里有任何帮助,或者有人可以给我指点一些好的文档或教程 - 无论哪种方式都非常有用!'
谢谢!