Node.js Tutorial

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏
Contents
Node.js Tutorial: A Beginner’s Guide
In this tutorial, I’ll teach you the basics of Node.js. Not only will you learn what Node is and what you can do with it, but you’ll see Node in action. We’ll build a simple application for a video rental store using Node, Express, Angular and MongoDB.
At a minimum, I’m assuming you have some web development experience. So you should know a bit of Javascript, HTML, and CSS, and have some familiarity with a web application framework such as ASP.NET MVC, PHP, Python or Rails. As far as Node, Express, Angular and MongoDB are concerned, I’m assuming you’re a beginner and that’s why you’re reading this tutorial. So, I’ll cover all these technologies from the ground up. If you do happen to have some experience with Angular and MongoDB, you can read this tutorial faster.
So, What Is Node?
Node is an open-source, cross-platform runtime environment for executing Javascript code. It’s built on the Google V8 Javascript engine, which is the execution engine for Google Chrome and is extremely fast. V8 compiles Javascript code to native machine code.
Before Node, Javascript was only executed in browsers. In 2009, Ryan Dahl used the open-source Google V8 Javascript engine to build Node as a runtime environment for Javascript outside a browser. This made it possible for Javascript developers to use Javascript on the server, mostly in building real-time Web APIs.
The Job Market
Node is gaining a lot of popularity these days and many big companies (such as IBM, Microsoft, Yahoo, LinkedIn, PayPal) have started adopting it.
As you can see from the following job trends on Indeed.com, demand for Node.js developers is increasing very fast.
Note that in terms of volume, Node developers are not as in demand as Ruby on Rails and many other frameworks, but I think that will change soon.
In 2013, as explained on their blog, PayPal moved from Java to Node.js. LinkedIn also moved from Rails to Node.
I personally think the future of web will be Node. These days we’re getting more and more connected and real-time systems and less need for the users to refresh their browsers and wait for seconds when switching from one page to another. With support from the open-source community, Node is and will be the preferred technology for building fast, connected and real-time applications.
I Love Node Because…
I’m one of the early adopters of ASP.NET MVC and been developing web applications using this framework for several years. One thing that has always put me off about ASP.NET MVC is the radical shift of the language, programming style and conventions from the server-side to the client-side code. While C# and Javascript are both C-like languages, programming with C# is fundamentally different from Javascript. That’s why a lot of ASP.NET web developers are often more skilled at one of these two languages but not both, and so they classify themselves as more of a “back-end” or “front-end” developer. The same applies to Ruby on Rails, PHP, Python, etc.
With Node, however, you use Javascript everywhere, on the server and on the client. This means cleaner and more consistent code base and fewer conversions and mappings. Also, one good Javascript developer can write both the server-side and the client-side code equally well.
When to Use Node?
Node is not a silver bullet. It’s designed for I/O-intensive operations and shines in building fast, scalable and real-time network applications. Examples of these applications are online games, collaboration tools, chat systems, etc. With Node, you can serve a great many clients with minimal system resources, and that’s why it’s designed for high scalability.
Node is also an excellent choice for building APIs on top of a document database like MongoDB. You store your documents as JSON objects in Mongo and expose them via a RESTful API. No need to convert between JSON and other types when reading or writing from your database. In this tutorial, we’ll build a Node application with this style of architecture.
Node, due to its architecture, should not be used for CPU-intensive operations. For this tutorial, since my focus is to show Node in action, I won’t get into architecture of Node and why it shouldn’t be used for CPU-intensive applications. That’s something that I’ll cover in my comprehensive Node course that I’ll publish on Udemy soon. If you’re interested, be sure to subscribe to my mailing list (details are at the end of this tutorial).
The MEAN Stack
There are many choices for building Node applications, but the MEAN stack has increased in popularity lately. MEAN stands for:
- MongoDB: the database engine we use to store the data.
- Express.js: the server-side framework for building web applications, similar to ASP.NET MVC or Rails.
- Angular: the front-end framework for building web applications
- Node.js: the Javascript runtime environment
With MEAN, you store your documents in a JSON-like format in MongoDB and expose them via a RESTful API that you build with Express and Node. You build a client with Angular to consume this API and render views to the user. This means that you use a single, unified language (Javascript) throughout your code, which results in more consistent and maintainable code. Plus, you spend less time dealing with conversions from JSON to other types. All of this results in better performance and increased developer productivity.
If you’ve never worked with MongoDB or Angular, don’t worry at all. I’ll teach you the basics of these technologies as part of this tutorial.
Okay, enough theory. I believe it’s time to get our hands dirty in the code and build an application using the MEAN stack.
Setting Up the Environment
Before we get started, there are a few tools you need to install in order to develop MEAN applications. Installing all these tools takes 15 – 20 minutes. Once you do it, you’ll have a proper environment for developing MEAN applications and you never have to go through these steps ever again.
So go ahead and install each tool in the order I’ve listed here. If you already have some of these tools (e.g., Sublime Text, MongoDb), you can skip that section.
Install Sublime Text
Sublime Text is a very lightweight and sophisticated code editor. You can use any editor to build node applications, but if you haven’t used Sublime, I recommend you to give it a try. To get Sublime, go to: https://sublimetext.com
Install Mongo
Go to https://mongodb.org and click Download MongoDB. Follow their documentation for installing Mongo. It’s very easy and unlike SQL Server, which takes half an hour or so, installing Mongo takes only a minute or two.
Once you install Mongo, there a few simple steps you need to follow to run it. You need to create a directory where Mongo will store database files. This directory should have write permissions for the current user. Then, you need to run MongoD (Mongo Daemon), which is a background process that handles data requests.
By default, MongoD expects the data directory to be /data/db in the root of your drive. I’d suggest that you keep the defaults for the purpose of this tutorial. But if you really have to change it, check out their complete instructions on their website on the download page.
Let’s stick to the defaults and run Mongo:
For Windows users:
Open Command Prompt as an administrator:
> md \data\db > cd “C:\Program Files\MongoDB\Server\3.0\bin” (or wherever you installed MongoDB) > mongod
Note that you can run MongoD as a Windows Service, so you don’t have to run it from the Command Prompt every time. The details are in the instructions on MongoDB website.
You may get a pop-up about MongoD listening for network connections. Give access to MongoD.
For Mac users:
Open Terminal:
$ sudo mkdir -p /data/dbmd $ whoami moshfeghhamedani $ sudo chown moshfeghhamedani /data/db $ mongod
You should see MongoD running in the Command Prompt or Terminal and waiting for connections.
If you encounter any issues running MongoD, it’s best to check MongoDB’s website for complete installation.
Install Node
Simply hit https://nodejs.org and click the Install button. Whether you’re using Windows or Mac, it’s very straightforward and you won’t have any problems.
As part of installing Node, you’ll get NPM (Node Package Manager) on your machine. NPM in Node is similar to Ruby Gems in Ruby and NuGet in .NET. We use NPM (or any package managers) to download and install open-source reusable packages / modules in our applications.
Install Express Generator
Express Generator is a Node module that we use to scaffold an application. To install Express Generator, open another Terminal on Mac or Command Prompt on Windows and run:
npm install -g express-generator
The -g switch here instructs NPM to install this package at the global level so it’ll be accessible to all your applications.
Scaffold a Project
We got all the tooling ready. Now let’s build an application skeleton using Express Generator. We’re going to call our video rental store application Vidzy. So, from the Command Prompt or Terminal, go to a folder on your disk where you create your projects, and run the following command:
express Vidzy
Express Generator will scaffold an application under a new folder called Vidzy.
Now, open the Vidzy folder in your favorite code editor. If you’re using Sublime, you can simply drag and drop this folder into Sublime.
Here is the generated app structure:
- bin
- www
- public
- images
- javascripts
- stylesheets
- routes
- index.js
- users.js
- views
- error.jade
- index.jade
- layout.jade
- app.js
- package.son
public is where we store public assets of our website, such as javascript files, stylesheets, images, etc.
routes includes a number of Javascript files, each defining routes and their handlers for a given module in your application. A route defines an endpoint in your application where you receive requests. We’ll take a look at routes soon.
views includes the view files for your application. Express supports many popular template engines such as Jade, Haml, EJS, Handlebars, etc. Jade is the default template engine.
app.js is the entry point to your application. It’s where your application is defined and configured.
package.json: every Node application has a package.json file, which includes application metadata and identifies application dependencies.
Let’s open package.json. Here you see a JSON object like the following:
{ "name": "Vidzy", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", "jade": "~1.11.0", "morgan": "~1.6.1", "serve-favicon": "~2.3.0" } }
As you see, here we specify the name and the version of our application as well as its dependencies. All of these dependencies are Node modules.
Install Dependencies
When you generate an application with Express Generator, these dependencies are not installed. They are only referenced in package.json. You need to separately install these dependencies.
To install the dependencies, go back into the Terminal or Command Prompt and run the following commands:
cd Vidzy npm install
This is going to take a little while to run. NPM will look at package.json to identify the dependencies. Then, it will download each of these dependencies from NPM directory and store them in a folder called node_modules. Let’s take a look at one of these modules.
Inside Vidzy folder, go to node_modules > express. Note that here we have another package.json, which identifies the dependencies for Express.js. Also, there is another node_modules folder, which is where these dependencies are stored. This is a common structure of Node applications. Every module or package has a package.json file and a node_modules folder.
Install Nodemon
When you start a Node application, a basic web server starts on port 3000 and accepts incoming requests. If you make any changes to your application code, these changes are not visible in your web server until you restart it. Doing so is a bit tedious as you have to kill the server and start it again from the command prompt. To solve this problem, we use Nodemon, which is yet another Node module that automatically restarts your web server whenever it detects any changes in your source files.
To install Nodemon:
npm install nodemon -g
Install Monk
Monk is a Node module for reading and writing documents in MongoDB.
To install monk:
npm install monk --save
The –save switch here instructs NPM to add this dependency in your package.json. The benefit of this is that if you push this application to a repository, and someone else checks it out (or it could be yourself at some other time), all dependencies of your application are referenced in package.json. Then, all you have to do is simply run npm install, and this will automatically install all the referenced modules. This is exactly what we did earlier once we generated our application skeleton.
Run the Application
Congratulations! We’ve installed all the required tools. Now, it’s time to run our sample application. From the Command Prompt or Terminal, run the following command inside the Vidzy folder:
nodemon
Nodemon will start your web server on port 3000. You may receive a pop-up warning you that Node is going to access incoming connections. Make sure to allow access.
Now, launch your browser and navigate to:
Here is your first express application.
Over the next few sections, we’ll build various features for our video rental store app.
Displaying All Videos in the Database
First, let’s start by implementing a simple feature: displaying all videos in the database on the home page. There are different ways to implement this. We can start from the front end and work all the way up to the back end, or vice versa. There is no right or wrong way but in this tutorial, I prefer to start from the back end for educational reasons.
We’re going to implement this feature in a few steps:
- We’ll create a database in Mongo and populate it with a few video documents.
- Then, we’ll create an API with Express to expose the videos in the database.
- Finally, we’ll use Angular to consume the API and display the list of videos.
If you don’t have any experience with any of these technologies, that’s perfectly fine. In this section, I’ll cover all of these from the basics. However, depending on your level of experience, there might be a bit of learning curve. Please be patient, and once we get to implement the next few features, everything will become easier as you re-apply these concepts.
Step 1: Populating the Database
How do we populate our MongoDB database with some documents? MongoDB has a shell that you can access using Terminal on Mac or Command Prompt on Windows. However, working with shell is not very user-friendly. So, to make our job easier, we’re going to use a free tool called RoboMongo. Head over to https://robomongo.org and download RoboMongo for your operating system.
Lunch RoboMongo. You’ll see a dialog box for connecting to a MongoDB server.
Click the Create link on the top.
Change the name of this connection from New Connection to localhost. Note the address of the connection. It points to localhost:27017. By default, MongoDB starts on port 27017.
If you click the Test button, you may get an error like “Authorization skipped by you”. Don’t worry about it. You’ll be able to connect to your local MongoDB regardless.
Save the connection settings. Back in the Connect dialog box, connect to localhost.
From the View menu, tick Explorer if it’s not already ticked. Now your RoboMongo should look like this:
In the Explorer pane, right-click on localhost and select Create Database. Name the database vidzy. Expand vidzy, right-click Collections and click Create Collection… A collection in MongoDB database is similar to a table in a relational database. Name this collection videos. The new collection should appear in the list.
Next, right-click the videos collection and select Insert Document. A document in MongoDB is kind of similar to a record in a relational database. However, a MongoDb document, unlike a relational record, can contain other documents. In Mongo, we use the JSON format to represent a document. Copy and paste the following code into the dialog to add a video document:
{ "title" : "Terminator Genisys", "genre" : "SciFi", "description" : "When John Connor, leader of the human resistance, sends Sgt. Kyle Reese back to 1984 to protect Sarah Connor and safeguard the future, an unexpected turn of events creates a fractured timeline." }
Note: Make sure to clear the content of the dialog first before pasting this document, as otherwise you’ll get an invalid JSON object.
Repeat this step and add two more documents to the videos collection:
{ "title" : "The Lord of the Rings", "genre" : "Fantasy", "description" : "A meek hobbit of the Shire and eight companions set out on a journey to Mount Doom to destroy the One Ring and the dark lord Sauron." }
{ "title" : "Apollo 13", "genre" : "Drama", "description" : "NASA must devise a strategy to return Apollo 13 to Earth safely after the spacecraft undergoes massive internal damage putting the lives of the three astronauts on board in jeopardy." }
Now, right-click the videos collection, and select View Documents. You should see three documents in the videos collection.
Note that each document has an ID that is automatically generated by MongoDB.
Done! Our database is ready. Now, let’s create an API using Express to expose these video documents.
Step 2: Creating an API with Express
In this step, you’re going to learn about Node module system, Express routes and getting data from MongoDB using Monk.
In your favorite code editor, open app.js in the root of the project folder. The first section includes a number of require calls. The require method is one of built-in methods in Node that we use to import modules defined in other files:
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser');
The second section imports our route module. A route module defines one or more related endpoints and their handlers. In the sample application generated by Express Generator, we have two route modules: index and users:
var routes = require('./routes/index'); var users = require('./routes/users');
Let’s take a look at one of these route modules. Open routes > index.js. You should see the following code:
var express = require('express'); var router = express.Router();
/* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); });
module.exports = router;
Let me break this down for you.
With the first line, we import Express into this module. When using the require method, depending on how the target module is implemented, the require method may return an object or a method. In this case, the express variable is an object. It exposes a method called Router, which we call on the second line, to get access to the router object in Express. We use a router to define endpoints for our application. These are the endpoints where we receive requests. Each endpoint will be associated with a route handler, which is responsible for handling a request that is received in that endpoint.
Now look at the next line for an example of a route configuration.
router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); });
Here, we use the get method on the router to define a route and its handler. The first argument is the endpoint; in this case, ‘/’ represents the root of the site or the home page. The second argument is the route handler.
In Express, all route handlers have the same signature. The first parameter is the request object, the second is the response, and the third references the next handler in the chain. Express uses middleware functions that are chained together. When building middleware with Express, sometimes you may want to call the next middleware function in the chain. You can use the next variable for that. But when working with routes, we hardly ever need to do this, so you can safely delete the next variable here.
Now, look at the body of this method. The res variable represents the response. The response object has a number of useful methods:
- render: to render a view
- send: to send plain text content to the client
- json: to send a json object to the client
- redirect: to redirect the client to a new address
Here, we render the index view, which is defined in views > index.jade.
This is the basic structure of a route. Now, we need to create a RESTful API for our videos. We’re going to expose our videos at an endpoint like /api/videos.
Create a new route module called videos.js under routes folder, and type the following code into it. Don’t worry, as I’ll explain it line by line.
var express = require('express'); var router = express.Router(); var monk = require('monk'); var db = monk('localhost:27017/vidzy'); router.get('/', function(req, res) { var collection = db.get('videos'); collection.find({}, function(err, videos){ if (err) throw err; res.json(videos); }); }); module.exports = router;
The first two lines are like before. We’re importing Express and getting the router object.
Next, we import Monk, which is a persistence module over MongoDB. There is another popular persistence module for working with Mongo called Mongoose.But in this tutorial, I preferred to use Monk as it’s easier than Mongoose.
Earlier I told you that depending on how a module is implemented, the requiremethod may return an object or a method. Here, when we import Monk, we receive a method, and not an object. So, the monk variable is a method that we call to get access to our database:
var db = monk('localhost:27017/vidzy');
Now, look at the implementation of our route handler.
function(req, res) { var collection = db.get('videos'); collection.find({}, function(err, videos){ if (err) throw err; res.json(videos); }); }
First we call the get method on the db object, passing the name of the collection (videos). It returns a collection object. This collection object provides a number of methods to work with documents in that collection.
- insert
- find
- findOne
- update
- remove
Here, we use the find method to get all videos in the collection. The first argument to this method is an object that determines the criteria for filtering. Since we want all videos, we pass an empty object as the argument. The second argument is a callback method that is executed when the result is returned from the database. This method follows the “error-first” callback pattern, which is the standard protocol for callback methods in Node. With this pattern, the first argument of a callback method should be an error object, and the second should be the result (if any). As you develop more applications with Node, you’re going to see more of this callback pattern.
Inside this callback, first we check if the err object is set. If there are no errors as part of getting the video documents, err will be null; otherwise it will be set. We throw the err here to stop the execution of the program and report an error to the user. If there are no errors, however, we simply return a JSON object by callingres.json method.
Finally, look at the last line of this module:
module.exports = router;
With this line, we specify the object (or method) that is returned when we require this module in another module. In this case, we’re returning the router object in Express. So, the purpose of this module is to get the router, register a few routes on it, and then return it.
There is one tiny step left. We built a module for configuring routes for our new API, but we haven’t used this module anywhere. Open up app.js again and look for the following code near the top:
var routes = require('./routes/index'); var users = require('./routes/users');
This is where we import our route modules into the application module. Add a new line to this section:
var videos = require('./routes/videos');
We’re importing our new module and storing it in a variable called videos. Next, we need to use it. Scroll down in app.js a little bit and find the following section:
app.use('/', routes); app.use('/users', users);
Add a new line to this section:
app.use('/api/videos', videos);
With this line we tell Express to use the videos module for any routes starting with/api/videos.
We’re done. Let’s quickly test our new API. Open up your browser, and navigate to http://localhost:3000/api/videos. You should see all videos represented as JSON.
I’m using the JSONView plugin in my Google Chrome to highlight JSON objects.
Over the next few steps, we’ll build the front end using Angular to display these videos.
Step 3: Adding Angular
In this step, you’re going to learn the basics of Angular. If you’re already familiar with Angular, you can skip through the explanations, but be sure to apply all code changes.
Angular is a popular front-end framework for building Single Page Applications (SPA). It provides routing, dependency injection, testability and clean separation of concerns by adhering to MVC architectural pattern. If all this sounds too geeky, don’t worry at all. You’re going to see most of these capabilities in this section.
First, we need to add Angular scripts to our application. Go to views > layout.jade and add these three script references at the end of the head section.
script(src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular-resource.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular-route.js')
Make sure they are at the same indentation level as previous lines since Jade (the default templating engine in Express) is very sensitive about white space. The Jade views generated by Express Generator use two white space characters for indenting. So, you need to follow the same and you cannot mix this with tabs in the same view. Otherwise, you’re going to get a runtime error.
What are these scripts? The first one is the main Angular framework, the second one (angular-resource) is used for consuming RESTful APIs, and the third one (angular-route) is used for routing. With routing we define what the user should see as they navigate through the application.
Next, create a new file called vidzy.js under public > javascripts. We’ll write all our Javascript code here.
Add a reference to vidzy.js in layout.jade just after Angular scripts:
script(src='/javascripts/vidzy.js')
Again, make sure that this line is at the same indentation level as other script references in the head section.
Now that we’ve got the necessary scripts in place, it’s time to add Angular to our application. Adding Angular involves two steps:
- First, we add the ng-app attribute to our HTML element. When the Angular script is loaded, it’ll look for this attribute in the DOM and if it finds it, it’ll hook itself into your application.
With layout.jade still open in your code editor, add ng-app to the html element near the top:
doctype html html(ng-app='Vidzy')
In Jade, we use parentheses for adding attributes to an HTML tag. When this line is rendered by Jade template engine, we’ll get an HTML element like the following:
<html ng-app=’Vidzy’>
The value we set for ng-app is the name of our application module that kicks off the application. Now we need to create this module.
Open vidzy.js and write this code:
var app = angular.module('Vidzy', []);
The angular object is available in the global space, so it’s everywhere. The module method can be used to define a new module or get a reference to an existing one. The first argument is the name of the module. This is the same name we used with ng-app above. The second argument is an array of dependencies. If you provide this argument, the module method will define a new module and return a reference to it. If you exclude it, it’ll attempt to get a reference to an existing module. Here, I’m passing an empty array to indicate that this module does not depend on any other modules.
That was all we had to do to hook Angular into our application. Next, we’re going to re-build our home page using Angular to display all videos in the database.
Step 4: Rebuilding the Home Page using Angular
The default application generated by Express Generator uses Jade as the view engine. These Jade views are parsed and rendered on the server, and HTML markup is returned to the client. This is how a lot of web frameworks work out of the box. But in this application, we’ll be using a different architectural style. Instead of returning HTML markup to the client, we’ll return plain JSON objects and let the client (Angular) render the view. Let me explain why.
Earlier, in the section about “When to use Node”, I mentioned that a common scenario that Node excelled at was building RESTful APIs over a document database. With this architectural style, we don’t have any overhead of data conversion. We store JSON objects in Mongo, expose them via a RESTful API and consume them directly on the client (in Angular). JSON is native to Javascript and MongoDB. So, by using it throughout the stack, we reduce the overhead of mapping or converting it to other types. By returning JSON objects from our API and rendering views on the client, we can improve performance and scalability because servers’ CPUs will not be wasted to render views for lots of concurrent users. Plus, we can reuse the same API to build another client, like an iPhone or Android app.
In this step, we’re going to retire our default home page that is built with a Jade view, and instead use an Angular view.
Create a new folder under public called partials. We will store all our views here. Create a new file under this folder called home.html. In this file, simply type:
<h1>Home Page</h1>
Now, we need to tell Angular to render this view when the user navigates to the home page. We use Angular routes for this.
In vidzy.js, change the declaration of app module as follows:
var app = angular.module('Vidzy', ['ngRoute']);
I added a reference to ngRoute module in the array of dependencies. ngRoute is one of the built-in Angular modules for configuring routes.
Write the following code after declaration of the app module:
app.config([<span class="hljs-string">'$routeProvider'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$routeProvider</span>)</span></span>{
<span class="hljs-variable">$routeProvider</span>
.when(<span class="hljs-string">'/'</span>, {
templateUrl: <span class="hljs-string">'partials/home.html'</span>
})
.otherwise({
redirectTo: <span class="hljs-string">'/'</span>
});
}]);
Let me break this down for you. We’re using the config method of the app module to provide configuration for our application. This code will be run as soon as Angular detects ng-app and tries to start up. The config method expects an array:
app.config([]);
This array can have zero or more dependencies, and a function for implementing configuration. Here, we have a dependency on $routeProvider, which is a service defined in the ngRoute module. That’s why we changed our app module declaration to depend on ngRoute. Our configuration function receives $routeProvider as a parameter.
app.config(['$routeProvider', function($routeProvider){ }]);
Inside our configuration function, we use the when method of $routeProvider to configure a route.
<span class="hljs-variable">$routeProvider</span>
.<span class="hljs-keyword">when</span>(<span class="hljs-string">'/'</span>, {
templateUrl: <span class="hljs-string">'partials/home.html'</span>
})
The first argument (‘/’) is the relative path. The second argument is an object that specifies the path to the view (via templateUrl). We can have multiple calls to the when method, each specifying a different route. Finally, we use the otherwise method to indicate that if user navigates to any other URLs, they should be redirected to the root (‘/’).
We’re almost there. We just need to make a few small changes to the Jade view for the home page. So, open views > index.jade and change the content of this file as follows:
extends layout block content div(ng-view)
I removed the existing content in this view (Welcome to Express) and instead added a div with the attribute ng-view. This attribute tells Angular where to render views. With this, the first time the user hits the home page, our Jade view will be rendered on the server and returned to the client. In a real-world application, this view will have the basic template for the site (e.g., navigation bars, logos, etc.). It will also have a content area (indicated by ng-view) for Angular to render views. As the user navigates through the application, Angular will replace the content area with a different Angular view. This prevents a full-page reload and results in better performance. That’s why we call these applications Single Page Applications: there is essentially one single page downloaded entirely from the server, and any subsequent pages were simply replacement of the content area.
Note: Again, I need to emphasize one more time that Jade is very sensitive about the white space character. You cannot mix space and tab for indentation in the same view. The default Jade views generated by Express Generator use two white space characters for indentation. So, make sure to add two white space characters before div(ng-view) or you may get a runtime parsing error.
Let’s do a quick test before implementing the final step. Back in your browser, navigate to http://localhost:3000. You should see our new home page built with Angular:
Step 5: Implementing the Controller
The home page is properly hooked in. Now we need to get the videos from the server and render them on the home page. In Angular, or any other MVC controllers, this is the responsibility of the controller. A view is purely responsible for presentation, while a controller is responsible for getting the data for the view, or handling the events raised from the view (e.g., clicks of buttons, etc.).
Let’s create a controller for our home view. Open vidzy.js and change the declaration of the app module as follows:
var app = angular.module('Vidzy', ['ngResource', 'ngRoute']);
Now we depend on two modules: ngResource, for consuming RESTful APIs and ngRoute for routing.
Next, type the following code at the end of the file to create a controller:
app.controller(<span class="hljs-string">'HomeCtrl'</span>, [<span class="hljs-string">'$scope'</span>, <span class="hljs-string">'$resource'</span>,
<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$scope</span>, <span class="hljs-variable">$resource</span>)</span></span>{
}]);
Let me break this down for you.
Here we’re using the controller method of the app module to define a new controller.
The first parameter is a string that specifies the name of this controller. By convention, we append Ctrl to our Angular controller names.
The second argument is an array. This array can include zero or more strings, each representing a dependency for this controller. Here, we’re specifying a dependency to $scope and $resource. Both of these are built-in Angular services, and that’s why they are prefixed with a $ sign. We’ll use $scope to pass data to the view and $resource to consume a RESTful API. The last object in this array of dependencies is a function that represents the body or implementation of the controller. In this example, our function gets two parameters called $scope and $resource. This is because we referenced $scope and $resource before declaring this function.
Let’s implement the body of this controller. Inside the controller function, type the following code:
app.controller(<span class="hljs-string">'HomeCtrl'</span>, [<span class="hljs-string">'$scope'</span>, <span class="hljs-string">'$resource'</span>,
<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$scope</span>, <span class="hljs-variable">$resource</span>)</span></span>{
<span class="hljs-keyword">var</span> Videos = <span class="hljs-variable">$resource</span>(<span class="hljs-string">'/api/videos'</span>);
Videos.query(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(videos)</span></span>{
<span class="hljs-variable">$scope</span>.videos = videos;
});
}]);
Here, we call the $resource method to get a resource object for the given API endpoint (/api/videos). This object will provide methods to work with our API. We use the query method to get all videos. The query method gets a callback method that will be executed when the query result is ready. This function will receive the videos we retrieved from the server. Finally, we store these videos in $scope so that we can access them in the view for rendering. Remember, $scope is the glue between views and controllers.
Now, we need to change the view to render the list of views. Open partials > home.html and write the following code:
<span class="hljs-tag"><<span class="hljs-title">ul</span>></span>
<span class="hljs-tag"><<span class="hljs-title">li</span> <span class="hljs-attribute">ng-repeat</span>=<span class="hljs-value">'video in videos'</span>></span><span class="hljs-tag"></<span class="hljs-title">li</span>></span>
<span class="hljs-tag"></<span class="hljs-title">ul</span>></span>
We’re using a UL and LI to render the list of videos. Our LI has an Angular-specific attribute called ng-repeat. These attributes in Angular are called directives and are used to add behavior to HTML elements. The value of ng-repeat is an expression similar to a foreach expression in Javascript. So, videos is essentially the property we set in the $scope earlier in the controller. video in videos represents one video at a time in this array. So, this LI element will be repeated for each video in the videos array. We use to write expressions. Here, we simply render the title of each video in our LI.
Finally, we need to register this controller as part of the route. Back in vidzy.js, change the route configuration as follows:
.<span class="hljs-keyword">when</span>(<span class="hljs-string">'/'</span>, {
templateUrl: <span class="hljs-string">'partials/home.html'</span>,
controller: <span class="hljs-string">'HomeCtrl'</span>
})
With this, we’re telling Angular that when the user navigates to the root of the site, display partials/home.html and attach HomeCtrl controller to it.
We’re done. Go back to the browser and refresh the home page. You should see the list of videos.
If you’re new to Angular and are a little confused, that’s perfectly fine. We’ll work with Angular controllers, views and routes more in the next few sections.
Let’s quickly recap. In this section we added the first feature to our application. We started by using RoboMongo to connect to MongoDB. We created a database and populated it with a few video documents. Then, we created an API using Express to expose the list of videos. Finally, we added Angular to our application and consumed our API to render the list of videos.
In the next section, we’ll add another feature to our application.
Adding a New Video
In this section, you’re going to learn more about creating API endpoints with Express, building forms using Angular, and storing documents in Mongo using Monk.
Similar to the last section, we’re going to implement this feature in a few steps from the back end to the front end. First, we’ll create an API endpoint for adding videos. We’ll use Express routes to create this endpoint and Monk to store a video document in Mongo. Then, we’ll create a new page with a form to add a video. We’re going to build this page using Angular.
Let’s get started.
Step 1: Creating an API Endpoint
Open routes > videos.js and add this new route after the existing one and before module.exports (remember, module.exports should be the last line of your module):
router.post(<span class="hljs-string">'/'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(req, res)</span></span>{
<span class="hljs-keyword">var</span> collection = db.get(<span class="hljs-string">'videos'</span>);
collection.insert({
title: req.body.title,
description: req.body.description
}, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(err, video)</span></span>{
<span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
res.json(video);
});
});
The code should be reasonably familiar. Let me go over the important parts. First, note the use of router.post method. In the last section, we used router.get method for handling an HTTP GET request. Here, we use HTTP POST, which is the REST convention for creating new objects.
In the route handler, first we get a reference to the videos collection and then use the insert method to add a new document to Mongo.
The first argument to this method is a JSON object with two properties: title and description. We read the values for these properties using req.body. This object represents the data that will be posted in the body of the request.
Finally, in the callback method for inserting a document, if we don’t get any errors, we use the json method of the response (res) to return a JSON representation of the new video document.
Step 2: Creating a Form
Okay, so the API is ready. Now we need a form for adding a video.
Create a new view file called video-form.html under public > partials. Type the following code inside this view:
<h1>Add a Video</h1> <form> <div> <label>Title</label> <input></input> </div> <div> <label>Description</label> <textarea></textarea> </div> <input type="button" value="Save"></input> </form>
Now, we need to tell Angular to present this view when the user navigates to /add-video. We need a new route for that.
Open vidzy.js and update the routing configuration code as follows:
app.config([<span class="hljs-string">'$routeProvider'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$routeProvider</span>)</span></span>{
<span class="hljs-variable">$routeProvider</span>
.when(<span class="hljs-string">'/'</span>, {
templateUrl: <span class="hljs-string">'partials/home.html'</span>,
controller: <span class="hljs-string">'HomeCtrl'</span>
})
.when(<span class="hljs-string">'/add-video'</span>, {
templateUrl: <span class="hljs-string">'partials/video-form.html'</span>
})
.otherwise({
redirectTo: <span class="hljs-string">'/'</span>
});
}]);
Note that I haven’t set the controller here, because we don’t have a controller yet. We’ll do that in the next step.
The view and route are ready. Finally, we need to add a link to /add-video in our home page. Open partials > home.html and add a new link above the UL:
<p> <a href="/#/add-video">Add a Video</a> </p>
Note that you should prefix the links in your Angular application with <b>/#</b>
.
This is used for compatibility with older browsers that don’t support single-page applications.
Let’s preview what we’ve done so far. Go back to your browser, and refresh the home page. You should see the link to add a video. Click the link and see the Add Video page.
I have to admit that this form looks really ugly and it is far from a real-world application. Let’s give it a nice, modern look.
Step 3: Adding Bootstrap
We’re going to use Bootstrap for adding a bit of style to our form. In case you’re not familiar with Bootstrap, it’s a front-end CSS framework for building modern and responsive web applications. In this step, we’re going to reference Bootstrap CSS file and decorate our form elements with a few Bootstrap classes.
Open views > layout.jade.
Add this line at the end of the head section:
link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css')
Make sure it has the same indent level as the lines above.
Now, back to partials > video-form.html. Add the following classes to the HTML elements:
<h1>Add a Video</h1> <form> <div class="form-group"> <label>Title</label> <input class="form-control"></input> </div> <div class="form-group"> <label>Description</label> <textarea class="form-control"></textarea> </div> <input type="button" class="btn btn-primary" value="Save"></input> </form>
These classes are standard Bootstrap classes for creating forms. For more information about how to create modern forms with Bootstrap, check out Bootstrap documentation.
Let’s get back to the browser and refresh the page.
It looks much better.
Now, this form has no behavior. Nothing happens if you click the Save button. That’s what we’re going to implement next.
Step 4: Implementing the Controller
As I told you before, in MVC frameworks, a controller is responsible for handling events raised by the view. We’re going to create an Angular controller to handle the click event of the Save button.
Open vidzy.js and type the following code at the end of the file:
app.controller('AddVideoCtrl', ['$scope', '$resource', '$location', function($scope, $resource, $location){ $scope.save = function(){ var Videos = $resource('/api/videos'); Videos.save($scope.video, function(){ $location.path('/'); }); }; }]);
This controller has three dependencies: $scope as the glue between the controller and the view, $resource for working with our RESTful API, and $location for changing the URL in the browser address bar. All of these are built-in Angular services.
Inside the body of this controller, we define the save method on the $scope. This method will be called when the user clicks the Save button. We’ll hook this to our view shortly. For now, let’s see what’s happening inside this method.
First, we call the $resource method passing the address of our API (/api/videos). This returns an object with methods to work with the API. In the last section, we used the query method to get all videos. Here, we use the save method to post a video to our API.
The videos.save method takes two parameters: the object to post, and the callback function, which will indicate that the asynchronous call is complete. In the callback, we use the $location service to change the browser’s address to the root of the site. Angular knows (based on our routes) that this root URL is bound to the home view. It will display the home page to the user.
Now, open partials > video-form.html and change the input fields as follows:
<div class="form-group"> <label>Title</label> <input class="form-control" ng-model="video.title"></input> </div> <div class="form-group"> <label>Description</label> <textarea class="form-control" ng-model="video.description"></textarea> </div>
The ng-model attribute is another directive that we use for data binding. With this, we tell Angular that anytime the value in our input fields is changed, it should automatically update the referenced property of $scope. In the first example, when the value of title text box is changed, Angular will automatically set it in $scope.video.title.
Next, change the button declaration as follows:
<input type="button" class="btn btn-primary" value="Save" ng-click="save()"></input>
The ng-click attribute is yet another Angular directive that we use to handle the click event of HTML elements. With this directive, we’re telling Angular that if the user clicks this button, it should execute the save method on the $scope, which we defined a minute ago.
Finally, register this new controller in the route:
.when('/add-video', { templateUrl: 'partials/video-form.html', controller: 'AddVideoCtrl' })
We’re done. Let’s test the application. Go back to the browser, and fill out the form and submit it. You should see a new video in the list.
Let’s quickly recap what you’ve learned in this section. We created a new API endpoint using Express and used Monk to store a video document in Mongo. Then, we created an Angular view with a form to add a video. We spiced up our form by using Bootstrap. Finally, we created the controller for this view to handle the click event. In the handler for the click event, we used the $resource service to post the data to the server.
In the next section, we’ll add the ability to edit an existing video.
Editing a Video
In this section you’re going to see another example of creating API endpoints, Angular views, controllers and routes.
We’re going to approach this section in a similar manner to the last one. First, we’ll build two API endpoints: one for getting a video with an ID, the other for updating a video. Then, we’ll add a link to each video in our home page. When the user clicks this link, they’ll be redirected to a form populated with the video details. When they click Save, changes will be saved and they will be returned to the home page.
Step 1: Creating the API Endpoints
This step should already be very familiar. We’re going to create two new routes:
GET /api/videos/{id} PUT /api/videos/{id}
So, open routes > videos.js. and add the following route:
router.get('/:id', function(req, res) { var collection = db.get('videos'); collection.findOne({ _id: req.params.id }, function(err, video){ if (err) throw err; res.json(video); }); });
Note that here we have a route parameter, indicated by a colon (:id). You can access the value of this parameter using req.params.id.
Other than that, the rest of this route configuration is similar to the ones you’ve seen before. The only difference is that we’re using the findOne method of the collection to return only one object. The first argument to this method is the criteria object. So, we’re looking for a document with _id equal to req.params.id.
Now, create another route:
router.put(<span class="hljs-string">'/:id'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(req, res)</span></span>{
<span class="hljs-keyword">var</span> collection = db.get(<span class="hljs-string">'videos'</span>);
collection.update({
_id: req.params.id
},
{
title: req.body.title,
description: req.body.description
}, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(err, video)</span></span>{
<span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
res.json(video);
});
});
Note that we’ve defined this route using router.put. This handler will be called only when there is an HTTP PUT request to this endpoint.
We use the update method of the collection object to update a document. The first argument is the criteria object. We’re trying to update only the document with _id equal to req.params.id. The second argument represents the values to update.
The rest is pretty straightforward.
Step 2: Creating the Edit Page
First, we need to add a link to each video on the home page. Open partials > home.html and change the LI as follows:
<li ng-repeat='video in videos'> <a href="/#/video/"> </a> </li>
We’re using a Angular binding expression to render a dynamic URL based on the ID of the video. Again, note that the URL is prefixed with /# for compatibility with older browsers.
Now we need a view with a form to edit a video. However, we already have a view with a form. So, it’s best to reuse it.
In vidzy.js, add this new route:
.when('/video/:id', { templateUrl: 'partials/video-form.html' })
Since we haven’t created the controller yet, I haven’t set the controller for the route. Let’s just review our work up to this point.
Go back to the browser, go to the home page and make sure to refresh the page. Now, each video should be represented using a hyperlink. Click a video. You should see an empty form.
In the next step, we’ll add behavior to this form. We’ll populate the form upon load and handle clicking the Save button.
Step 3: Implementing the Controller
Now we have two choices. We can create a new controller, like EditVideoCtrl, or reuse the existing controller (AddVideoCtrl). What do you think is the best solution? The answer is: there is no best solution. It all depends. If two cases (Add and Edit) have a lot of similarities with few differences, it makes sense to create one controller that handles both scenarios. You’d need a few conditional statements to distinguish between Add and Edit scenarios. On the other hand, if the behaviours in these two scenarios are fairly different, you’ll end up with a lot of ugly conditional statements in one controller. In that case, it’s better to separate them into two different controllers.
Before writing this step of the tutorial, I started by reusing the same controller and I wasn’t very happy with the end result. So, I decided to split them into two different controllers.
In vidzy.js, create a new controller as follows:
app.controller(<span class="hljs-string">'EditVideoCtrl'</span>, [<span class="hljs-string">'$scope'</span>, <span class="hljs-string">'$resource'</span>, <span class="hljs-string">'$location'</span>, <span class="hljs-string">'$routeParams'</span>,
<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$scope</span>, <span class="hljs-variable">$resource</span>, <span class="hljs-variable">$location</span>, <span class="hljs-variable">$routeParams</span>)</span></span>{
<span class="hljs-keyword">var</span> Videos = <span class="hljs-variable">$resource</span>(<span class="hljs-string">'/api/videos/:id'</span>, { id: <span class="hljs-string">'@_id'</span> }, {
update: { method: <span class="hljs-string">'PUT'</span> }
});
Videos.get({ id: <span class="hljs-variable">$routeParams</span>.id }, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(video)</span></span>{
<span class="hljs-variable">$scope</span>.video = video;
});
<span class="hljs-variable">$scope</span>.save = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{
Videos.update(<span class="hljs-variable">$scope</span>.video, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{
<span class="hljs-variable">$location</span>.path(<span class="hljs-string">'/'</span>);
});
}
}]);
Let me explain what is happening here.
First, this controller, unlike our AddVideoCtrl, has four dependencies. We have an extra dependency here: $routeParams, which we use for accessing parameters in the route (URL). In this case, the ID of the video to edit will be our route parameter.
In the body of this controller, first we use the $resource service to get an object to work with our API endpoint. But this time, we’re using the $resource service in a different way.
var Videos = $resource('/api/videos/:id', { id: '@_id' }, { update: { method: 'PUT' } });
The first argument is the URL to our endpoint. However, here we have a route parameter indicated by a colon (:id). We’re using a parameterized route because the two API endpoints we created earlier in this section included route parameters.
GET /api/videos/:id PUT /api/videos/:id
The second argument to this method is an object that provides default values for the :id parameter in our route.
{ id: '@_id' }
Here, ‘@_id’ tells Angular to look for a property called _id in the object included in the body of the request. So, when we send a request to PUT /api/videos/:id, Angular will use the _id property of the video object in the body of the request, to set the :id parameter in the route.
The third argument to the $resource method is used for extending the $resource service.
{ update: { method: 'PUT' } }
For some reason only known to developers of Angular, by default you cannot send HTTP PUT requests using $resource service. You need to extend it by adding an update method that uses HTTP PUT.
Next, we use Videos.get to get the video with the given ID.
Videos.get({ id: $routeParams.id }, function(video){ $scope.video = video; });
This is to populate the form upon page load. The first argument to Videos.get provides the value for the :id parameter in the route. We use $routeParams.id, which gives us access to the parameters in the browser’s address bar. Remember the declaration of the route for the edit page?
.when('/video/:id', { templateUrl: 'partials/video-form.html', })
There, we used a route parameter (:id). So, we can access it with $routeParams.
In the callback method for Videos. get, we get the video returned from the server and store it in the $scope. This way, with Angular’s two-way binding running in the background, the form will be automatically populated with our video object. Remember ng-model? We bound our input fields to properties of the video object on $scope. Any changes in the input field will be reflected in the $scope, and vice versa.
Finally, in the body of the controller, we define a save method, which will be called when the user clicks the Save button.
$scope.save = function(){ Videos.update($scope.video, function(){ $location.path('/'); }); }
Note that here, instead of using Videos.save, we’re using Videos.update. This is the new method we defined earlier when extending the $resource service. So, this will issue an HTTP PUT request to our API endpoint.
We’re almost done. Our new controller is ready. We just need to reference it in the route configuration. Change the route configuration as follows:
.when('/video/:id', { templateUrl: 'partials/video-form.html', controller: 'EditVideoCtrl' })
Let’s test this new feature. Go back to the browser, and refresh the home page. Select one of the videos. Make a few changes and click the Save button. Everything should work.
In the next section, we’ll add one more feature to our video rental store app to build the full CRUD functionality.
Deleting a Video
In this section, you’re going to learn how to delete documents using Monk. You’ll also review what you learned about Express and Angular one more time. By the end of this section, all of the pieces of the puzzle should fit together.
We’re going to implement this feature in a few steps. Starting from the server, we’ll build an API endpoint for deleting video documents. Then, we’ll add a Delete link in front of each video in the list. When the user clicks this link, they’ll be redirected to a page where they can see details of the video. We’ll have a Confirm Delete button on that page. Once they click this button, a call will be made to our API endpoint, and then they’ll be taken back to the video list.
But before we jump into implementation, I have a suggestion. I think that with what you’ve learned so far, you should be able to implement this feature on your own. I want you to spend 10 – 15 minutes working on this feature as an exercise to apply what you’ve learned so far. Then, you can come back and review your solution with mine to see if there is any room for improvement. Before you get started, note that:
Step 1: Building the API Endpoint
Open routes > videos.js and add this new route:
router.delete(<span class="hljs-string">'/:id'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(req, res)</span></span>{
<span class="hljs-keyword">var</span> collection = db.get(<span class="hljs-string">'videos'</span>);
collection.remove({ _id: req.params.id }, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(err, video)</span></span>{
<span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
res.json(video);
});
});
Everything should be familiar here. The only difference is that we’re using router.delete to register a route handler for an HTTP DELETE request.
Also, note that we’re using the remove method of the video collection object. The first argument, as you might guess, is the criteria object.
Step 2: Building the Delete Page
Go to partials > home.html and add a Delete link in front of each video as follows:
<li ng-repeat='video in videos'> <a href="/#/video/"> </a> <a href="/#/video/delete/"> <i class="glyphicon glyphicon-remove"></i> </a> </li>
Here, **** is used to render an icon. glyphicon and glyphicon-remove are both Bootstrap classes for rendering icons. Bootstrap includes tens of modern icons for building applications. To see the list of all icons, go here. To render an icon, you need to use two CSS classes. One is glyphicon (the base for all icons), and the other is the class specific to the icon you’re using (glyphicon-remove). In the Bootstrap documentation, you can see the CSS class for each icon below the icon itself.
Clicking this icon is going to take us to a page at /#/video/delete/. Let’s create this view and register a route for it.
Add a new file named video-delete.html to the partials folder. Write the following code in this file:
<h1>Delete Video</h1> <p> Are you sure you want to delete this video? </p> <ul> <li>Title: </li> <li>Description: </li> </ul> <input type="button" value="Yes, Delete" class="btn btn-danger" ng-click="delete()" /> <a class="btn btn-default" href="/#/">No, Go Back</a>
Nothing fancy here. I’m using a simple UL and LI to display different attributes of a video. In a real-world application, you may use a more complex markup.
Just note that I’ve added the btn-danger class to the Delete button to make it look red, and btn-default to the Back button to make it look white.
Once we finish the following steps, the page will look like this:
Next, we need a controller for this view. In this controller, we’re going to call our API to get the details of the video upon page load. Also, when the user clicks the Delete button, we’ll call the API to delete the video.
Open vidzy.js and create this controller:
app.controller(<span class="hljs-string">'DeleteVideoCtrl'</span>, [<span class="hljs-string">'$scope'</span>, <span class="hljs-string">'$resource'</span>, <span class="hljs-string">'$location'</span>, <span class="hljs-string">'$routeParams'</span>,
<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$scope</span>, <span class="hljs-variable">$resource</span>, <span class="hljs-variable">$location</span>, <span class="hljs-variable">$routeParams</span>)</span></span>{
<span class="hljs-keyword">var</span> Videos = <span class="hljs-variable">$resource</span>(<span class="hljs-string">'/api/videos/:id'</span>);
Videos.get({ id: <span class="hljs-variable">$routeParams</span>.id }, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(video)</span></span>{
<span class="hljs-variable">$scope</span>.video = video;
})
<span class="hljs-variable">$scope</span>.delete = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{
Videos.delete({ id: <span class="hljs-variable">$routeParams</span>.id }, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(video)</span></span>{
<span class="hljs-variable">$location</span>.path(<span class="hljs-string">'/'</span>);
});
}
}]);
Again, everything should be familiar at this point.
Finally, we need to create a route to register this view and controller. Add this route to your application configuration code:
.when('/video/delete/:id', { templateUrl: 'partials/video-delete.html', controller: 'DeleteVideoCtrl' })
You’re done. Let’s test the delete functionality. Go back to the browser, and refresh the home page. Click the delete icon. Delete one of the videos. The video will be deleted, and you’ll be redirected to the home page.
Wrapping Up
If you made it this far, you’ve demonstrated that you’re enthusiastic about learning new things. So, great job. I hope you’ve enjoyed this tutorial and learned the basics of Node, Express, Angular and MongoDB.
Let’s quickly review what you learned in this tutorial:
What’s next? Node is more than what you’ve read, and that’s why I’m planning to create a comprehensive course to teach you many amazing things you can do with Node. In particular, I’ll be teaching you:
- Authentication and authorization
- Prevention of common security attacks
- Data validation
- Caching
- Real-time applications
- And more…
If you enjoyed my teaching style and would like to learn more from me, subscribe to my newsletter. I’ll send out an announcement once my course is ready.
Published on Codepedia.org with the permission of Udemy – source Node.js Tutorial from https://blog.udemy.com/