Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongo #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
Binary file added models/.DS_Store
Binary file not shown.
15 changes: 15 additions & 0 deletions models/todo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;

// Provide the schema for the Todo model
var TodoSchema = new Schema({
task: String,
description: String,
// done: Boolean
});

// Define the model using the schema we provided
var Todo = mongoose.model('Todo', TodoSchema);

// We export the Todo model to use in other files
module.exports = Todo;
27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "todo-api",
"version": "1.0.0",
"description": "**Objective:** Use Express to make a RESTful API for a to do list. Build a client for your app that uses AJAX and Handlebars templating to `CREATE`, `READ`, `UPDATE`, and `DELETE` todos.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.14.1",
"express": "^4.13.3",
"hbs": "^4.0.0",
"mongoose": "^4.2.5"
},
"devDependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/stevennoble78/express-todo-app.git"
},
"bugs": {
"url": "https://github.com/stevennoble78/express-todo-app/issues"
},
"homepage": "https://github.com/stevennoble78/express-todo-app#readme"
}
Binary file added public/.DS_Store
Binary file not shown.
12 changes: 12 additions & 0 deletions public/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
body {
background-color: #AE6D11;
}

#appcontainer {
background-color: #86D5B7;
border-color: #0B754D;
}

.editTodo {
display: none;
}
113 changes: 113 additions & 0 deletions public/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// wait for DOM to load before running JS
$(document).ready (function () {

// check to make sure JS is loaded
console.log('JS is loaded!');

// Compile the template
var source = $('#template').html();
var template = Handlebars.compile(source);

// Set variables
var todoResults = [],
baseUrl = '/',
apiUrl = baseUrl + 'api/todos/',
$todolist = $('#todo-list'),
$newTodo = $('#newTodo');

// Use AJAX to get data and append it to the page
$.get(apiUrl, function(data) {
console.log(data.todos);
todoResults = data.todos;

// Render the data
var todoHTML = template({todos: todoResults});
$todolist.append(todoHTML);
});

// Refresh function
function refresh (data) {
console.log('refreshing');
$todolist.empty();
$('input.formdata').val('');
// Rerender the data
var todoHTML = template({todos: todoResults});
$todolist.append(todoHTML);
}

// Add todo function called by submit button handler
function addTodo(data) {
event.preventDefault();
var newTodo = $(this).serialize();
$.post(apiUrl, newTodo, function(data) {
todoResults.push(data);
refresh();
});
}

// Put todo function called by glyphicon pencil handler
function putTodo() {
event.preventDefault();
var id = $(this).attr('id');
$('#form' + id).toggle();
$('#form' + id).on('submit', function(event) {
event.preventDefault();
var updatedTodo = $(this).serialize();
$.ajax({
type: 'PUT',
url: apiUrl + id,
data: updatedTodo,
success: function (data) {
var index = todoResults.indexOf(updatedTodo);
for (var i=0; i<todoResults.length; i++) {
if (todoResults[i]._id === id) {
index = i;
}
}
todoResults.splice(index, 1, data);
refresh();
}
});
});
}

// Delete todo function called by glyphicon trash handler
function deleteTodo() {
console.log('deleting');
event.preventDefault();
var id = $(this).attr('id');
$.ajax({
type: 'DELETE',
url: apiUrl + id,
success: function (data) {
var index;
for (var i=0; i<todoResults.length; i++) {
if (todoResults[i]._id === id) {
index = i;
}
}
todoResults.splice(index, 1);
refresh();
console.log('deleted');
}
});
}

// Strikeout text when glyphicon is clicked
function strikeout() {
event.preventDefault();
var id = $(this).attr('id');
$('#task' + id).css('text-decoration', 'line-through');
}

// Click handler for Submit button to add a todo
$newTodo.on('submit', addTodo);

// Click handlers for glyphicons
$todolist.on('click', '.glyphicon-pencil', putTodo);

$todolist.on('click', '.glyphicon-trash', deleteTodo);

$todolist.on('click', '.glyphicon-ok', strikeout);

});
90 changes: 90 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SERVER SIDE JAVASCRIPT

var express = require('express');
var bodyParser = require('body-parser');
var hbs = require('hbs');
var mongoose = require('mongoose');
var app = express();

// Require the Todo model
var Todo = require('./models/todo');

// Set up static public file
app.use(express.static('public'));

// Set view engine to hbs
app.set('view engine', 'hbs');

// Set up body-parser and connect to the local database
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect('mongodb://localhost/todo-app');

// Set up route for index.html
app.get('/', function(req, res) {
res.render('index');
});

// Set up route for get
app.get('/api/todos', function(req, res) {
// find will either return err or allTodos
Todo.find(function(err, allTodos) {
// Return an object which includes the allTodos array
res.json({ todos: allTodos });
});
});

// Set up route for getting a single todo
app.get('/api/todos/:id', function(req, res) {
// Find url from id parameters
var todoId = req.params.id; // Doesn't need to be converted to an integer

// Find todo in db by id
Todo.findOne({ _id: todoId }, function(err, foundTodo) {
res.json(foundTodo);
});
});

// Set up route to post todos
app.post('/api/todos', function(req, res) {
// Create a new todo using form data
var newTodo = new Todo(req.body);

// Save new Todo in db
newTodo.save(function(err, savedTodo) {
res.json(savedTodo);
});

});

// Set up route for updates
app.put('/api/todos/:id', function(req, res) {
// Find url from id parameters
var todoId = req.params.id; // Doesn't need to be converted to an integer

// Find todo in db by id
Todo.findOne({ _id: todoId }, function(err, foundTodo) {
// Update the todo's attributes
foundTodo.task = req.body.task;
foundTodo.description = req.body.description;

// Save updated todo
foundTodo.save(function(err, savedTodo) {
res.json(foundTodo);
});
});
});

// Set up route for deletes
app.delete('/api/todos/:id', function(req, res) {
// Find url from id parameters
var todoId = req.params.id; // Doesn't need to be converted to an integer

// Find todo in db by id
Todo.findOneAndRemove({ _id: todoId }, function(err, deletedTodo) {
res.json(deletedTodo);
});
});

var server = app.listen(process.env.PORT || 5000, function() {
console.log('listening...');
});
78 changes: 78 additions & 0 deletions views/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- set viewport to device width to make site responsive -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- bootstrap css -->
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- custom styles -->
<link rel="stylesheet" type="text/css" href="main.css">
<title>To Do List</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3" id="appcontainer">
<h1 class="text-center">To Do List</h1>
<br>
<form id="newTodo">
<div class="form-group">
<input type="text" class="formdata form-control form-group" name="task" placeholder="Task">
<input type="text" class="formdata form-control form-group" name="description" placeholder="Description">
<input type="submit" class="btn btn-warning btn-block" value="Submit">
</div>
</form>
<div id="todo-list">
<div class="row">
<div class="col-md-4">
<h2>Task</h3>
</div>
<div class="col-md-8">
<h2>Description</h4>
</div>
</div>
<script type="text/x-handlebars-template" id="template">
\{{#each todos}}
<div class="row">
<div class="col-md-4">
<span id="task\{{_id}}"><h3>\{{task}}</h3></span>
</div>
<div class="col-md-8">
\{{#if description}}
<h4>\{{description}}</h4>
\{{else}}
<h4>No description given</h4>
\{{/if}}
<div class="btn-group">
<span class="glyphicon glyphicon-pencil btn btn-warning" id="\{{_id}}" aria-hidden="true"></span>
<span class="glyphicon glyphicon-trash btn btn-warning" id="\{{_id}}" aria-hidden="true"></span>
<span class="glyphicon glyphicon-ok btn btn-warning" id="\{{_id}}" aria-hidden="true"></span>
</div>
<form class="editTodo" id="form\{{_id}}">
<div class="form-group">
<input type="text" class="formdata form-control form-group" name="task" value="\{{task}}">
<input type="text" class="formdata form-control form-group" name="description" value="\{{description}}">
<input type="submit" class="btn btn-warning btn-block" value="Submit">
</div>
</form>
</div>
</div>
<hr>
\{{/each}}
</script>
</div>
</div>
</div>
</div>

<!-- jquery -->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<!-- bootstrap js -->
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- handlebars -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.3/handlebars.min.js"></script>
<!-- custom script -->
<script type="text/javascript" src="main.js"></script>
</body>
</html>