Download node and npm
$ mkdir mean-demo$ cd mean-demo$ vim package.json # like a manifest file{"name": "mean-demo","version": "0.0.1"}$ vim myserver.jsconsole.log("Hello from node")$ node myserver$ vim myserver.js # delete the console line and make the most basic express server we canvar express = require("express"),app = express();app.get('/', function(req, res){res.sendfile(__dirname + '/client/views/index.html');});app.listen(3000, function(){console.log('I\'m listenning...');});$ npm install express --save # --save will save it to package.json$ cat package.json # express has been saved in the package.json{"name": "mean-demo","version": "0.0.1","dependencies": {"express": "^4.9.8"}}$ mkdir -p client/views$ vim client/views/index.html<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content=""><meta name="viewport" content="width=device-width, initial-scale=1"><title></title></head><body><p>Hello!</p></body></html>$ node myserver.jsbrowse to http://localhost:3000 Angular js is a client side MVC and allows us to build more dynamic web applications. by separating concerns model/view/controller.
$ vim client/views/index.html # add angular script to html. we added angular.js instead of angular.min.js so that we get more friendly error messages if we need to debug. start to use these declarations to tell angular that this html page is an application. angular is named after these angular brackets. and ng is short for angular <!doctype html>
# angular will look for a function with the name of our controller and it will inject the scope. The scope is what's used to talk between the view and the controller so that's how angular manages to handle the binding between these two things and allow them to talk. so on the scope we want to have something called meetupsCount. angular.module('meetupApp', []) so we need to include this script, we made it in its own file and its not part of our client. its not downloaded in the browser yet <!doctype html >
there are {{meetupsCount}} meetups Ctrl+Shift+i to open developer tools in chrome. in console tab you see Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:3000/js/controllers/meetups-controller.js
$ vim client/views/index.html <ul> </div> $ vim client/js/controllers/meetups-controller.jsangular.module('meetupApp', []).controller('meetupsController', function($scope) {$scope.meetupsCount = 10; $scope.meetups = [{name:"SF Developers"}, {name:"Some other meetup"}] }); # add attribute ng-model to the input of the form. Anything we do here is going to have two way binding to the controller, actually scope on the controller. So anything we type in the inout text box will have acess on our controller through the scope. Have a submit button. Now we could do a click event on the button and handle it and pass that into our controller but I like tot use ng-submit and angular would do the submission of the form back to your controller and call a function. The function doesn't take any arguments because we will have access to that variable that we defined through ng-model. </script> $ vim client/js/controllers/meetups-controller.js
$ vim client/views/index.html # add attribute ng-model to the input of the form. Anything we do here is going to have two way binding to the controller, actually scope on the controller. So anything we type in the inout text box will have acess on our controller through the scope. Have a submit button. Now we could do a click event on the button and handle it and pass that into our controller but I like tot use ng-submit and angular would do the submission of the form back to your controller and call a function. The function doesn't take any arguments because we will have access to that variable that we defined through ng-model. $ vim client/js/controllers/meetups-controller.js<!doctype html><html ng-app="meetupApp"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content=""><meta name="viewport" content="width=device-width, initial-scale=1"><title></title></head><body><!-- This is our Meetups View, but usually we have them in a separate file and include them here. the value of the meetupsCount --><div ng-controller="meetupsController"><h1> there are {{meetups.length}} meetups </h1><ul><li ng-repeat="meetup in meetups"> {{meetup.name}} </li></ui><form ng-submit="createMeetup()"><input type="text" placeholder="Meetup name" ng-model="meetupName"></input><button type="submit">Add</button></form></div><script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js"></script><script type="text/javascript" src="/js/controllers/meetups-controller.js"></script></body></html>
$scope.meetupName = ''
$ vim client/js/app.js var app = angular.module('meetupApp', ['ngResource']); now that we have our module we have our controller just sitting in the space and it's not a part of this application. so now that we have an app defined we want to add this controller to the application so that it has access to the ngResource. add dependencies (scope and resource) and add a funciton and name those dependencies i like to use the same name $ vim client/js/controllers/meetups-controller.js
So we said on our app there is a controller named metupsController it has a dependency on scope and dependency on resource so angular will inject those in to the function parameters. So we should be able to take our code out of the controller down there and put it inside the function. So we added app.js so we need to use app.js and bootup our app. $ vim client/views/index.html
So now it knows to use this particular meetupApp angular module which is our application and we've configured our controller on it so it will also be able to see our controller and do all the things it needs to do. So now controller has access to ngResource. ngResource is equivalent of model I guess. The way it works is if you give it a base URL for your server, for meetups for example, it knows how to do all ReSTfull operations. get post put delete, ... and as long as the server follows a standard API, it makes you not to have to deal with not much code in the client side it handles all the http requests and gives you a nice syntax around it. So one way to use it is: meetup = a new resource and all we have to do is say what the base URL of our server, of our restful service is. we will create the restful service. /api/meetups will be the base url of our rest resource for our model essentially app.controller('meetupsController', ['$scope', '$resource', function($scope, $resource){ var Meetup = $resource('/api/meetups') $scope.meetups = [{name:"SF Developers"}, {name:"Some other meetup"}] $scope.createMeetup = function(){ var meetup = new Meetup(); meetup.name = $scope.meetupName; meetup.$save(); } } ]); So this means when you say add this meetup, call this function on the controller on the client side and our client side will call the restful service on our server and try to save that there browse to http://localhost:3000 and you'll see that it gives an error of not finding the api path. you can open the network tab of developer tools and see it is a post request and see the json of the meetup you wanted to add there. So let's go to our server and add the path. app. verb name for our route and we're going to name the path. and give it a call back function and we can read values from request and respond back to the user. $ vim myserver.js
now I don't like to code everything in one file so I create a directory for server side code. $ mkdir -p server/controllers $ vim server/controllers/meetup-controller.js
so this is just a node module and we're going to require it from our server so that we can use this module. So the way that node works is if you want somebody to have access to your module and have access to something like a function then you need to export it. so we export a function called create. So I'm going to take the newly function added above to here. just to reorganize my code. now I go back to the server and the server need to pass that to the controller. I would normally create a namespace so inside controller i create index.html or js and I have different name spaces for differnet controllers. So yu can require diffenret controllers folder and you could say controller.meetups, controller.this, bla bla but for this demo we just do something a little bit straight forward. so once we have that we can say meetupControllers.create (the exported function) $ vim myserver.js
So that just says when somebody calls this route call this function on the meetups controller. now restart the server because we added some routes browse to http://localhost:3000 and you'll note you get undefined for req.body, but we did see the json in the request above. The reason it says it's undefined is because express doesn't use a body parser by default. So it doesn't recognize the body of hte request as json and it doesn't parse it. $ npm install body-parser --save $ vim myserver.js
bodyParser = require('body-parser'),
http://localhost:3000 and it correctly displays body of request. So now on our server we want to store this. So we look at our controller that's handling this we want to store this in our mongodb databse. So what do we do for that? we could use a native mongodb drivers for node, I like to use something called mongoose, it's an ODM (Object Data Mapping) and it allows you to define your schema in your application and gives you some nice syntax around the driver for that. it's not always the right choice there are some performance overhaed to it, so make your own choice $ npm install mongoose --save So we are doing MVC on the server and on the client. so I wouldn't use MVC right in the controller. I would create a model object $ mkdir server/models $ vim server/models/meetup.js This will be the meetup model for mongoose. so I just create mongoose. and I use the simplest way to define schema but yo can do a lot better. like validation, ... So again this is just a module and people gotta have access to it. so export. Meetup will be its name
module.exports = mongoose.model('Meetup', { name: String }) usually I use name space like models.meetup .... but now I just use directly. $ vim server/controllers/metups-controller.js var Meetup = require('../models/meetup')
var meetup = new Meetup(req.body); // it will just create a new obj as it is json meetup.save(); I need to connect to the databse. so in server: $ vim myserver.js
bodyParser = require('body-parser'),
mongoose.connect('mongodb://localhost:27017/mongo-demo');
save DONE. now have a call back on save $ vim server/controllers/metups-controller.js var Meetup = require('../models/meetup')
var meetup = new Meetup(req.body); // it will just create a new obj as it is json meetup.save(function(err, result){ } $vim ./client/js/controllers/meetups-controller.js
$scope.meetupName = '';
so when you add a new meetup, it stores it in the data bse, responds back to the client and adds it to the collection! awesome! pull all the data back from DB instead of the hardcoded ones in clinet $vim ./client/js/controllers/meetups-controller.js
Meetup.query(function(results){ $scope.meetups = results;
$scope.meetupName = '';
So we need to define the REST route of meetups to the server $ vim myserver.js
bodyParser = require('body-parser'),
mongoose.connect('mongodb://localhost:27017/mongo-demo');
$ vim server/controllers/metups-controller.js var Meetup = require('../models/meetup')
var meetup = new Meetup(req.body); // it will just create a new obj as it is json meetup.save(function(err, result){ }
Meetup.find({}, function(err, results){ //mongoose }); } |