Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
12 changes: 12 additions & 0 deletions models/todo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;

var TodoSchema = new Schema ({
task: String,
description: String,
done: Boolean
});

var Todo = mongoose.model('Todo', TodoSchema);

module.exports = Todo;
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "express-todo-app",
"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"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vframbach/express-todo-app.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/vframbach/express-todo-app/issues"
},
"homepage": "https://github.com/vframbach/express-todo-app#readme",
"dependencies": {
"body-parser": "^1.14.1",
"express": "^4.13.3",
"mongoose": "^4.2.5"
}
}
59 changes: 59 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!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">
<link href='https://fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet' type='text/css'>
<title>To Do List</title>
</head>
<body>
<div class="container">
<img src="http://www.freshtracks.co.uk/wp-content/uploads/2012/07/to-do-lists.jpg">
</div>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form class="form-group" id="create-todo">
<input type="text" name="task" class="form-control" value="Task name">
<input type="text" name="description" class="form-control" value="Description">
<input type="submit" value="Create task" class="btn btn-warning btn-block">
</form>
</div>
</div>
</div>
<div class="container" id="todos-list"></div>
<script id="todos-template" type="text/x-handlebars-template">
{{#each todos}}
<div class="row {{#if done}}done{{else}}not-done{{/if}}">
<div class="col-xs-3">
</div>
<div class="col-xs-1">
<h2>{{#if done}}<span class="glyphicon glyphicon-ok checkmark" aria-hidden="true"></span>{{/if}}</h2>
</div>
<div class="col-xs-5 well">
<h2>{{task}}</h2>
<div>{{description}}</div>
<button type="button" class="btn btn-default btn-xs edit" data-todo-id="{{_id}}" data-toggle="tooltip" data-placement="bottom" title="Edit"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-default btn-xs done" data-todo-id="{{_id}}" data-toggle="tooltip" data-placement="bottom" title="Complete"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>
<button type="button" class="btn btn-default btn-xs delete" data-todo-id="{{_id}}"data-toggle="tooltip" data-placement="bottom" title="Delete"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</div>
</div>
{{/each}}
</script>

<!-- 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>
15 changes: 15 additions & 0 deletions public/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
body {
background-color: #FDCA95;
font-family: 'Ubuntu', sans-serif;
}

.container {
text-align: center;
padding-bottom: 25px;
}

.checkmark {
font-size: 70px;
background-color: #f5f5f5;
}

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

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

var source = $("#todos-template").html();
var template = Handlebars.compile(source);

var todosCollection = [];
// GET all todos
function refreshList() {
$.get('/api/todos', function(data) {
var todoHtml = template({
todos: data.todos
});
$('#todos-list').html(todoHtml);
console.log(data.todos);
todosCollection = data.todos;
$('[data-toggle="tooltip"]').tooltip();

});
}
refreshList();

// create new todo
// -form to create todo
// -submit handler when form is submitted
// -read form data to create todo
// -use post to create todo based on form

$('#create-todo').on('submit', function(event) {
event.preventDefault();
console.log('submitting form!');
console.log($(this).serialize());

var newtodo = $(this).serialize();

$.ajax({
type: 'POST',
url: '/api/todos',
data: newtodo,
success: function(data) {
refreshList();
}
});

});
// create form that allows edit todo
$('#todos-list').on('click', '.edit', function() {
var todoId = $(this).data('todo-id');
console.log(todoId);
var todo = todosCollection.find(function(todo) {
return todo._id == todoId;
});
console.log(todo);
todo.task = prompt('New todo task:', todo.task);
todo.description = prompt('New description:', todo.description);
var todoHtml = template({
todos: todosCollection
});
$('#todos-list').html(todoHtml);
console.log(todoHtml);
$.ajax({
type: 'PUT',
url: '/api/todos/' + todoId,
data: todo,
success: function(data) {
console.log('Todo has been edited!');
}
});
//console.log(todoId);
});


$('#todos-list').on('click', '.done', function() {
var todoId = $(this).data('todo-id');
var todo = todosCollection.find(function(todo) {
return todo._id == todoId;
});
todo.done = !todo.done;
var todoHtml = template({
todos: todosCollection
});
$('#todos-list').html(todoHtml);
console.log(todoHtml);
$.ajax({
type: 'PUT',
url: '/api/todos/' + todoId,
data: todo,
success: function(data) {
console.log('Todo has been completed!');
}
});
//console.log(todoId);
});


$('#todos-list').on('click', '.delete', function() {
var todoId = $(this).data('todo-id');
$.ajax({
type: 'DELETE',
url: '/api/todos/' + todoId,
success: function(data) {
console.log('Todo has been deleted!');
refreshList();
}
});
console.log(todoId);
});



// 1. form to enter data (in html)
// 2. collect data from form in JS
// 3. AJAX POST request to server to create new todo
// 4. handle response from API (render new todo)
});
119 changes: 119 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// server.js
// SERVER SIDE JAVASCRIPT
var express = require('express');
var app = express();
var bodyParser = require('body-parser');

// mongo
//connect to mongodb
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todo-app');

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


app.use(bodyParser.urlencoded({
extended: true
}));

// set view engine to hbs (handlebars)

app.set('view engine', 'hbs');

//server static files from public folder

app.use(express.static(__dirname + '/public'));

// or
// app.use(express.static('public'));

// HOMEPAGE ROUTE

// app.get('/', function(req, res) {
// res.render('index');
// });

// API ROUTES

// just todo route
app.get('/api/todos/', function(req, res) {

// find all todos in db

Todo.find(function(err, allTodos) {
res.json({
todos: allTodos
});
});

});

// get one todo
app.get('/api/todos/:id', function(req, res) {

// MONGO
// get todo id from url params ('req.params')
var todoId = req.params.id;

// find todo in db by id

Todo.findOne({
_id: todoId
}, function(err, foundTodo) {
res.json(foundTodo);
});

});

// create new todo
app.post('/api/todos', function(req, res) {

var newTodo = new Todo(req.body);
newTodo.done = false;

newTodo.save(function(err, savedTodo) {
res.json(savedTodo);
});
});


// delete
app.delete('/api/todos/:id', function(req, res) {
var todoId = parseInt(req.params.id);

Todo.findOneAndRemove({
_id: todoId
}, function(err, deletedTodo) {
res.json(deletedTodo);
});
});


// update
app.put('/api/todos/:id', function(req, res) {
// get todo id from url params ('req.params')
var todoId = req.params.id;
console.log(req.body);

// find todo in db by id

Todo.findOne({
_id: todoId
}, function(err, todoToUpdate) {
console.log(err, todoToUpdate);

todoToUpdate.task = req.body.task;
todoToUpdate.description = req.body.description;
todoToUpdate.done = req.body.done;

//saves to db
todoToUpdate.save(function(err, savedTodo) {
res.json(savedTodo);
});
});
});

var server = app.listen(process.env.PORT || 3000, function() {
console.log('Example app listening at http://localhost:3000/');
});