Skip to content

cuttlesoft/mean-workshop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Scratch

This project was created for a workshop on web app development with the MEAN stack. It uses MongoDB, Express, AngularJS, and Node.js, as well as (...other packages...) to create a basic application with (...features...).

Walkthrough

  1. Getting Started
  2. Basic Server
  3. Basic HTML
  4. Basic Angular App
  5. Basic Model
  6. Basic Route
  7. Note Creation
  8. Restructure for Scalability
  9. Miscellaneous Improvements
  10. Presentation!

1. Getting Started

Create project directory and create README:

$ mkdir scratch
$ cd scratch
$ touch README.md

Initialize package.json and install Express:

$ npm init
$ npm install --save express

Note: For the "entry point" prompt during the npm init process, we are using server.js (we will create the file in step 2. The Server).

Initialize git repo and create .gitignore file:

$ git init
$ touch .gitignore

// .gitignore
node_modules
npm-debug.log

Note: Some .gitignore examples can be found here.

Initial commit:

$ git add .
$ git commit -m "Initial commit"

2. Basic Server

Create server.js with the basics:

// Basic Express app

var express = require('express');
var app = express();

// Basic configuration

var port = process.env.PORT || 3001;

// Basic route

app.get('/', function(req, res) {
  res.send('Hello, World!');
});

// Start app

app.listen(port, function() {
  console.log('Server running on port ' + port);
});

Start the server:

$ node server.js

Note: Using something like node-supervisor prevents having to stop and restart the server every time changes are made.

Go to http://localhost:3001 in the browser, and you should see "Hello, World!"

3. Basic HTML

Add route to server.js to serve index.html:

app.get('*', function(req, res) {
  res.sendfile('./public/index.html');
});

Create public/index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Scratch</title>
</head>
<body>
    Hello (again), world!
</body>
</html>

Go to http://localhost:3001/anything in the browser, and you should now see "Hello (again), World!"

Note: Unless the initial route created in server.js is removed, http://localhost:3001 will continue to show "Hello, World!" instead of the contents of index.html.

Note: At this point, we also added a Bootstrap theme from Bootswatch and a little bit of HTML, so we would have something nicer to look at as we build.

4. Basic Angular App

Create public/app/app.js:

angular
  .module('scratchApp', [])
  .controller('appController', appController);

function appController() {
  var vm = this;
  console.log('Why, hello (world)!');
}

Add ng-app and ng-controller to index.html:

<html lang="en" ng-app="scratchApp">
<head>...</head>
<body ng-controller="appController as app">
    ...
</body>
</html>

5. Basic Model

Install Mongoose:

$ npm install --save mongoose

Note: Mongoose is an object-document mapper (like an ORM but for a document database) that makes working with MongoDB a lot nicer/easier.

Configure database in server.js:

var databaseUrl = 'mongodb://localhost/scratch-dev';
mongoose.connect(databaseUrl);

Create notes model in server.js:

mongoose.model('Note', {
  title: String,
  content: String,
});

Ensure that MongoDB is running:

$ mongod

Note: You may have to sudo mongod; for more on managing MongoDB processes, see here.

6. Basic Route

Add route to get notes in server.js:

app.route('/api/notes')
  .get(function (req, res) {
    Note.find(function(err, notes) {
      if (err) res.send(err);
      res.json(notes);
    });
  });

Navigating to http://localhost:3001/api/notes should show [], which is the (currently empty) array of notes being returned.

7. Note Creation

Install body-parser to parse the body from POST requests:

$ npm install --save body-parser

Configure body-parser in server.js:

var bodyParser = require('body-parser');

// ...

app.use(bodyParser.urlencoded({'extended':'true'}));
app.use(bodyParser.json());
app.use(bodyParser.json({ type: 'application/vnd.api+json' }));

Add route for creating notes in server.js:

app
  .route('/api/notes')

  // ...

  .post(function (req, res) {
    var note = {
      title: req.body.title,
      content: req.body.content,
    };

    Note.create(note, function(err, note) {
      if (err) res.send(err);
      res.json(note);
    });
  });

Add function for submitting form and creating notes in app.js:

function appController($http) {
  // ...

  vm.createNote = createNote;

  // ...

  function createNote(note) {
    $http.post('/api/notes', note).then(function(res) {
      // Add new note to notes in the view
      var note = res.data;
      vm.notes.push(note);
    }, function(err) {
      console.log('Error creating note: ', err.statusText);
    });
  }
}

Add function for getting notes for display in app.js:

function appController($http) {
  // ...

  vm.getNotes = getNotes;

  // ...

  function getNotes() {
    $http.get('/api/notes').then(function(res) {
      vm.notes = res.data;
    }, function(err) {
      console.log('Error retrieving notes: ', err.statusText);
    });
  }
}

Add HTML form for creating notes in index.html:

<form>
    <label for="title">Title</label>
    <input type="text" id="title" ng-model="note.title" placeholder="Note Title">

    <label for="content">Content</label>
    <textarea id="content" ng-model="note.content" placeholder="Note content..."></textarea>

    <button type="submit" class="btn btn-success" ng-click="app.createNote(note)">Create Note</button>
</form>

Add HTML for displaying the (newly-creatable) notes in index.html:

<div class="panel panel-default" ng-repeat="note in app.notes">
    <div class="panel-heading">
        {{ note.title }}
    </div>
    <div class="panel-body">
        {{ note.content }}
    </div>
</div>

8. Restructure for Scalability

At this point, although the application works, all backend code is in server.js, all frontend code is in app.js, and all HTML is in index.html -- this will not be maintainable or scalable as any more is added to the application.

Frontend changes:

  • Create domain-specific directories (e.g., /public/app/notes)
  • Move domain-specific code to its respective directories (e.g., /public/app/notes/notes.controller.js)
  • Move HTTP calls from controller(s) into service(s)
  • Set up routes (with ui-router) and templates
  • Ensure that all frontend modules and templates are imported and utilized correctly

Backend changes:

  • Create a directory to organize API route behaviors (e.g., /app/api) and move existing function definitions into individual files (e.g., /app/api/notes.js)
  • Create a directory to organize models (e.g., /app/models) and move existing model definitions into individual files (e.g., /app/models/note.js)
  • Create a file for defining all of the application's routes (e.g., /app/routes.js)
  • Create a directory to organize app configuration (e.g., /config) and move existing configurations into individual files (e.g., /config/db.js)
  • Ensure that all modules are imported and utilized correctly

9. Miscellaneous Improvements

  • Note deletion
    • Add method-override package for PUT and DELETE requests (for updating and deleting objects, respectively)
    • API route to delete notes
    • Notes service function to make request
    • Notes controller function to call service
    • Button in view
  • Note creation
    • Add custom filter to reverse note order in list (order newest to oldest)
    • Clear form when note is created
    • Clear form with "Cancel" button

10. Presentation!

You can view the PDF for the workshop presentation here.

About

MEAN stack workshop demo project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published