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 Express To Do #12

Open
wants to merge 18 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
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
});

var Todo = mongoose.model("Todo", TodoSchema);
//this should match variable name

module.exports = Todo;
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"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": "mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tkhuynh/express-todo-app.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/tkhuynh/express-todo-app/issues"
},
"homepage": "https://github.com/tkhuynh/express-todo-app#readme",
"dependencies": {
"body-parser": "^1.14.1",
"express": "^4.13.3",
"hbs": "^4.0.0",
"mongoose": "^4.2.5"
}
}
81 changes: 81 additions & 0 deletions public/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
$(function() {
var baseUrl = "/api/todos";
var allTodos = [];
var $toDoList = $("#todos-list");
var source = $("#todos-template").html();
var template = Handlebars.compile(source);
var render = function() {
$toDoList.empty();
var todosHtml = template({ todos: allTodos});
//use find to target child element in form
$("form").find("input[name='task'], textarea").val("");
$toDoList.append(todosHtml);
};
$.get(baseUrl, function(data) {
allTodos = data.todos;
render();
});
$("#create-todos").on("submit", function(event) {
event.preventDefault();
var newTodo = $(this).serialize();
$.post(baseUrl, newTodo, function(data) {
allTodos.push(data);
render();
});
});

$("#todos-list").on("click", ".edit-button", function() {
var ID = $(this).attr("id");
console.log(ID);
var todoToBeEdited = allTodos.filter(function(todo) {
return todo._id == ID;
})[0];
var todoToBeEditedIndex = allTodos.indexOf(todoToBeEdited);
var $editForm = $("#form" + ID);
$editForm.toggle();
$("#todos-list").on("submit", $editForm, function(event) {
event.preventDefault();
var editedTodo = $editForm.serialize();
console.log(editedTodo);
$.ajax({
type: "PUT",
url: baseUrl + "/" + ID,
data: editedTodo,
success: function(data) {
allTodos.splice(todoToBeEditedIndex, 1, data);
render();
console.log(allTodos);
}
});
});
});

$("#todos-list").on("click", ".delete-button", function () {
//if was del{{_id}} >> need to remove first 3 letters
var ID = $(this).attr("id").slice(3);
var todoToBeDeleted = allTodos.filter(function(todo) {
return todo._id == ID;
})[0];
var todoToBeDeletedIndex = allTodos.indexOf(todoToBeDeleted);
$.ajax({
type: "DELETE",
url: baseUrl + "/" + ID,
data: todoToBeDeleted,
success: function (data) {
allTodos.splice(todoToBeDeletedIndex, 1);
render();
}
});
});
$("#todos-list").on("change", ".check", function (event) {
var ID = $(this).attr("id").slice(7);
var doneTodo = "#row" + ID + " h4," + "#row" + ID + " .task-name";
var done = allTodos.filter(function(todo) {
return todo._id == ID;
})[0];
var editButton = "#row" + ID + " .edit-button";
$(doneTodo).toggleClass("done");
$(editButton).toggleClass("disabled");
console.log(done);
});
});
45 changes: 45 additions & 0 deletions public/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
body {
background-color: #F7DCB4;
}
h1 {
color: #663333;
font-size: 60px;
font-family: 'Noto Serif', serif;
margin-bottom: 15px;
clear: :both;
}
img {
float: left;
width: 60px;
}
.task-column {
border-right: 1px solid #EEEEEE
}
.done {
text-decoration: line-through;
}
h4, .task-name {
padding: 0px 5px 0px 5px;
font-size: 25px;
font-family: 'Indie Flower', cursive;
}
.edit-form {
display: none;
}
.button-holder {
margin-bottom: 30px;
display: inline;
float: right;
}

@media (max-width: 500px) {
h1 {
font-size: 45px;
}
img {
width: 45px;
}
h4 {
font-size: 15px:;
}
}
102 changes: 102 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
var express = require("express");
var bodyParser = require("body-parser");
var hbs = require("hbs");
var mongoose = require("mongoose");

var app = express();

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

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

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

var Todo = require("./models/todo"); //it's ok without .js


//setup routes

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

//set up todos api
app.get("/api/todos", function(req, res) {
//Mongo
//find all todos in db
Todo.find(function(err, allTodos) {
res.json({
todos: allTodos
});
});
});

//get a todo by its Id
app.get("/api/todos/:id", function(req, res) {
//Mongo
//get id from url
var todoId = req.params.id;

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

//create new one
app.post("/api/todos", function(req, res) {
//Mongo
// create new todo with form data (`req.body`)
var newTodo = new Todo(req.body);

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

/// update todo
// update todo
app.put('/api/todos/:id', function(req, res) {
// 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) {
// update the todos's attributes
foundTodo.task = req.body.task;
foundTodo.description = req.body.description;

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

// delete todo
app.delete('/api/todos/:id', function(req, res) {
// get todo id from url params (`req.params`)
var todoId = req.params.id;

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

//listen to port 3000
var server = app.listen(process.env.PORT || 3000, function() {
console.log("I'm listening");
});
99 changes: 99 additions & 0 deletions views/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">

<link href='https://fonts.googleapis.com/css?family=Indie+Flower' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Noto+Serif:700' rel='stylesheet' type='text/css'>

<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<div class="title-holder">
<img src="http://www.girlfridayproductions.com/wordpress/wp-content/themes/girlfriday/assets/img/icons/icon-pencilpaper.png">
<h1>To Do List</h1>
</div>
<div class="row">
<div class="col-sm-6">
<form id="create-todos">
<div class="form-group">
<input type="text" class="form-control" name="task" placeholder="Task">
</div>
<div class="form-group">
<textarea class="form-control" name="description" rows="3" placeholder="Description"></textarea>
</div>
<input type="submit" class="btn btn-warning">
</form>
</div>
<div class="col-sm-6">

</div>
</div>
<br>
<div id="todos-list">
<script id="todos-template" type="text/x-handlebars-template">
\{{#each todos}}
<div class="row" id="row\{{_id}}">
<div class="col-xs-5 task-column">
<input type="checkbox" class="check" id="checked\{{_id}}">
\{{#if task}}
<span class="task-name">\{{task}}</span>

\{{/if}}
</div>
<div class="col-xs-5">
\{{#if description}}
<h4>\{{description}}</h4>
\{{else}}
<h4><i>No description</i></h4>
\{{/if}}
<form role="form" class="edit-form" id="form\{{_id}}">
<div class="form-group">
<input type="text" class="form-control" name="task" placeholder="Task" value="\{{task}}">
</div>
<div class="form-group">
<input type="text" class="form-control" name="description" placeholder="Description" value="\{{description}}">
</div>
<div class="form-group">
<input type="submit" class="btn btn-warning" id="save" value ="Edit">
</div>
</form>
</div>
<div class="col-xs-2">
<button type="button" class="btn btn-default edit-button" aria-label="Left Align" id="\{{_id}}">
<span class="glyphicon glyphicon-edit glyphicon-align-left" aria-hidden="true">
</span>
</button>
<button type="button" class="btn btn-default delete-button" aria-label="Left Align" id="del\{{_id}}">
<span class="glyphicon glyphicon-remove-circle glyphicon-align-left" aria-hidden="true">
</span>
</button>
</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="script.js"></script> <!-- change file name -->
</body>
</html>