Difference between revisions of "Getting MEAN"
m (→Installation) |
|||
(25 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | + | =Installation= | |
− | + | To install MEAN, make sure you already have all of the following components installed and configured correctly. | |
− | 1. Node.js (should come with npm) | + | <br/> |
− | To find out if you have node and npm, | + | '''1. Node.js''' (should come with npm) <br/> |
− | + | To find out if you have node and npm, try checking their versions (may not be the same): | |
− | + | <source lang="bash"> | |
node --version | node --version | ||
v0.10.25 | v0.10.25 | ||
npm --version | npm --version | ||
1.3.24 | 1.3.24 | ||
+ | </source> | ||
+ | |||
+ | IF you don't have node.js, install it [http://nodejs.org/ here]. | ||
+ | |||
+ | '''2. Bower''' | ||
+ | |||
+ | Bower is a web application manager used by MEAN. To install bower, type the following command in your terminal: | ||
+ | <source lang="bash">npm install -g bower</source> | ||
+ | |||
+ | '''3. MongoDB''' | ||
+ | To install MongoDB, follow the instructions for your OS [http://docs.mongodb.org/manual/installation/ here]. | ||
+ | |||
+ | '''4. Grunt''' | ||
+ | To install Grunt type the following command: | ||
+ | <source lang="bash">npm install -g grunt-cli</source> | ||
+ | |||
+ | |||
+ | '''5. and finally, MEAN''' | ||
+ | In your terminal, type: | ||
+ | <source lang="bash"> > sudo npm install -g mean-cli </source> | ||
+ | |||
+ | |||
− | + | == What did all that mean? == | |
− | + | You just installed four different command line tools. Here's what they all do. | |
− | + | * '''npm''' is the package manager for Node.JS. It installs libraries for use by your Node.JS applications. The configuration file for ''npm'' (the list of packages for ''npm'' to install) is ''package.json''. | |
+ | * '''bower''' is a package manager for front-end libraries. Rather than manually downloading your jQuery, Bootstrap, Angular, and other front-end JavaScript and CSS (and remembering to update them when a new version of one of those libraries comes out), ''bower'' installs them for you. The configuration file for ''bower'' (the list of packages for ''bower'' to install) is ''bower.json''. | ||
+ | * '''grunt''' is a build tool designed for JavaScript. It's like ''make'' or ''ant'', but for JavaScript. The configuration file for ''grunt'' (the list of commands to run when building your project) is ''Gruntfile.js'' (a name inspired by the ''Makefile'' for ''make'', the dominant C and C++ build tool). | ||
+ | * '''mean''' is a utility designed to help you carry out routine tasks associated with developing for the MEAN stack. | ||
− | + | Don't be confused by the fact that you use ''npm'' to install ''bower'', ''grunt'', and ''mean''. The people who made ''bower'', ''grunt'', and ''mean'' just all decided to use ''npm'' as the place to publish their projects, probably because the executables themselves are written in Node.JS. They could just as well have chosen ''apt-get'' or ''yum'' or any of the other package managers you've been using in this class. | |
− | |||
+ | =Running the Default App = | ||
+ | * Init and run an app. | ||
+ | <source lang="bash"> | ||
+ | > mean init myApp // create your first app | ||
+ | > cd myApp | ||
+ | > npm install // Install dependencies | ||
+ | > grunt // Launch mean | ||
+ | </source> | ||
+ | Make sure MongoDB is connected and running (if you run into problems, refer to the section on MongoDB) | ||
− | + | * Go ahead and explore features of the default Article app (such as logging in, adding/deleting articles). | |
− | * | ||
− | = | + | =Generating a Package = |
− | * | + | * By now you should know what a package is in MEAN. If you don't, read [http://learn.mean.io/#mean-io-packages this]. |
− | |||
− | + | * Try creating a package named myPackage by typing: | |
− | * | + | <source lang="bash"> |
− | + | > mean package myPackage | |
+ | </source> | ||
+ | Locate it inside the packages folder: | ||
* Compare the structure of myPackage folder to that of the default app. Make sure you see both '''public''' and '''server''' folders and their subfolders. | * Compare the structure of myPackage folder to that of the default app. Make sure you see both '''public''' and '''server''' folders and their subfolders. | ||
* Restart your app, make sure you can see a link to the newly created package. | * Restart your app, make sure you can see a link to the newly created package. | ||
− | + | =A Closer Look at the App = | |
Take a look at the directory where you app resides, you will see two folders '''public''' and '''server''', which contain code for the client side and server side respectively. | Take a look at the directory where you app resides, you will see two folders '''public''' and '''server''', which contain code for the client side and server side respectively. | ||
− | = Models = | + | == Models == |
Open up article.js in /server/models | Open up article.js in /server/models | ||
Line 44: | Line 77: | ||
The models are mongoose models that's why we need to require mongoose (what the following line does): | The models are mongoose models that's why we need to require mongoose (what the following line does): | ||
+ | <source lang="javascript"> | ||
var mongoose = require('mongoose'), Schema = mongoose.Schema; | var mongoose = require('mongoose'), Schema = mongoose.Schema; | ||
− | + | </source> | |
The following part then defines the schema: | The following part then defines the schema: | ||
− | + | <source lang="javascript"> | |
var ArticleSchema = new Schema({ | var ArticleSchema = new Schema({ | ||
created: { | created: { | ||
Line 68: | Line 102: | ||
} | } | ||
}); | }); | ||
− | + | </source> | |
The next part is validations, or criteria an object needs to pass before it can be saved to the DB. | The next part is validations, or criteria an object needs to pass before it can be saved to the DB. | ||
The following code is to make sure that an article has a title: | The following code is to make sure that an article has a title: | ||
− | + | <source lang="javascript"> | |
ArticleSchema.path('title').validate(function(title) { | ArticleSchema.path('title').validate(function(title) { | ||
return title.length; | return title.length; | ||
}, 'Title cannot be blank'); | }, 'Title cannot be blank'); | ||
− | + | </source> | |
Finally, Mongoose allows us to define methods to our data objects as well. | Finally, Mongoose allows us to define methods to our data objects as well. | ||
These are called statics. From the Mongoose doc: Schemas not only define the structure of your document and casting of properties, they also define document instance methods, static Model methods, compound indexes and document lifecycle hooks called middleware. | These are called statics. From the Mongoose doc: Schemas not only define the structure of your document and casting of properties, they also define document instance methods, static Model methods, compound indexes and document lifecycle hooks called middleware. | ||
The following code defines a method called load for the article schema: | The following code defines a method called load for the article schema: | ||
− | + | <source lang="javascript"> | |
ArticleSchema.statics.load = function(id, cb) { | ArticleSchema.statics.load = function(id, cb) { | ||
this.findOne({ | this.findOne({ | ||
Line 86: | Line 120: | ||
}).populate('user', 'name username').exec(cb); | }).populate('user', 'name username').exec(cb); | ||
}; | }; | ||
+ | </source> | ||
If you have trouble understanding what the code does, review the Mongoose [http://mongoosejs.com/docs/index.html quick start] guide. | If you have trouble understanding what the code does, review the Mongoose [http://mongoosejs.com/docs/index.html quick start] guide. | ||
− | = Models Practice = | + | === Models Practice === |
Define a schema for a model named '''Phone''', name it phone.js and save it in the corresponding folder in 'myPackage' (hint: /packages/myPackage/server/models/) | Define a schema for a model named '''Phone''', name it phone.js and save it in the corresponding folder in 'myPackage' (hint: /packages/myPackage/server/models/) | ||
A product needs to have the following fields with specific types. Here is an example of a Phone object can be stored in the MongoDB: | A product needs to have the following fields with specific types. Here is an example of a Phone object can be stored in the MongoDB: | ||
− | + | <source lang="javascript"> | |
{ | { | ||
"age": 0, | "age": 0, | ||
Line 98: | Line 133: | ||
"imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", | "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", | ||
"name": "Motorola XOOM\u2122 with Wi-Fi", | "name": "Motorola XOOM\u2122 with Wi-Fi", | ||
− | "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM | + | "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM wi.. d by Android 3.0 (Honeycomb)." |
} | } | ||
+ | </source> | ||
This is taken from phones.json used by the AngularJS tutorial. If you have gone through the tutorial, you should have realized that instead of using a DB, json files were used to simplify the tutorial. | This is taken from phones.json used by the AngularJS tutorial. If you have gone through the tutorial, you should have realized that instead of using a DB, json files were used to simplify the tutorial. | ||
Find phones.json in /app/phones in the angular tutorial folder and try importing its content to MongoDB so you can use them in your current MEAN package. | Find phones.json in /app/phones in the angular tutorial folder and try importing its content to MongoDB so you can use them in your current MEAN package. | ||
+ | <br/> Here is how (assuming mongod is running): | ||
− | + | <source lang="bash"> | |
− | + | > mongo --shell // connect to mongo shell | |
− | + | > use mean-dev // switches to database used by mean. | |
+ | > mongoimport --db mean-dev --collection phones --type json --file ''<path to phones.json>'' --jsonArray // imports json file to the DB | ||
+ | > show collections // check to see if phones are added to your database | ||
+ | > coll = db.phones // to see the content of the file | ||
+ | </source> | ||
− | = Controllers = | + | == Controllers == |
− | You'll find a controllers folder on both the server side and the client side. | + | You'll find a controllers folder on both the server side and the client (public) side. |
* The client side controllers are part of the Angular MVC scheme that contains client side logic and may issue requests to the server. | * The client side controllers are part of the Angular MVC scheme that contains client side logic and may issue requests to the server. | ||
* The server side controllers deal with the models and requests from the client side. | * The server side controllers deal with the models and requests from the client side. | ||
Line 117: | Line 158: | ||
* Find articles.js in the controllers folder. Try to understand what each part does. | * Find articles.js in the controllers folder. Try to understand what each part does. | ||
− | |||
− | |||
− | + | '''Client side:''' open up articles.js in /articles/public/controllers | |
+ | Compare the functions defined in ArticlesController, can you find the server side implementation of corresponding functions? | ||
− | + | Here is a diagram to help you understand how this works: | |
− | |||
− | |||
− | |||
− | + | [[File:Mean.png]] | |
− | + | == Views & Routing == | |
− | + | Even though typically views are implemented and used for the client end, routing happens on both ends. | |
− | + | * Find articles.js in /server/routes | |
+ | You'll see that it requires the articles controller and its methods for querying the database. | ||
− | + | The first section requires the articles controller, which defines different methods | |
+ | For example, code below tells the server to use a method named "all" in the articles controller when the url is pointed to /articles: | ||
− | = | + | <source lang="javascript"> |
− | + | app.route('/articles') | |
+ | .get(articles.all) | ||
+ | </source> | ||
− | Go to public/ | + | *Go to http://localhost:3000/articles, what do you see? Does it make sense? |
+ | |||
+ | Let's switch to the public folder where the views reside. Go to articles/public/views, open up list.html: <br/> | ||
The first line tells the framework that ArticlesController is responsible for this particular view and when this view is loaded, use find() to initiate data binding. | The first line tells the framework that ArticlesController is responsible for this particular view and when this view is loaded, use find() to initiate data binding. | ||
− | + | <source lang="html4strict"> | |
<section data-ng-controller="ArticlesController" data-ng-init="find()"> | <section data-ng-controller="ArticlesController" data-ng-init="find()"> | ||
+ | </source> | ||
Feel free to take a look at what find() does. Make sure you understand that what find() does is actually done by the backend, where a corresponding find() is written (as mentioned above). | Feel free to take a look at what find() does. Make sure you understand that what find() does is actually done by the backend, where a corresponding find() is written (as mentioned above). | ||
Line 156: | Line 200: | ||
+ | <source lang="html4strict"> | ||
+ | <div class="left pull-left"> | ||
+ | <ul class="navbar-nav nav"> | ||
+ | <li data-ng-repeat="item in menus.main" ui-route="/{{item.link}}" ng-class="{active: $uiRoute}"> | ||
+ | <a mean-token="item.link" ui-sref='{{item.link}}'>{{item.title}}</a> | ||
+ | </li> | ||
+ | </ul> | ||
+ | </div> | ||
+ | </source> | ||
− | *<nowiki | + | * Try changing <nowiki>{{item.title}} </nowiki> inside the <a> </a>tags to "my articles" see what happens to the page. |
− | + | * The ui-sref is "href" in ui-route, an AngularJS plugin, try changing <nowiki>{{item.link}}</nowiki> to #!/myarticles, | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | * The ui-sref is "href" in ui-route, an AngularJS plugin, try changing {{item.link}} to #!/myarticles, | ||
* What happens to the application now? When you click on "my articles"? | * What happens to the application now? When you click on "my articles"? | ||
The page to articles is no longer served! | The page to articles is no longer served! | ||
− | But how does the framework know which page to serve given a certain url? The file | + | But how does the framework know which page to serve given a certain url? The file responsible for this (called routing in web development) is in public/articles/routes |
− | open up articles.js | + | open up articles.js in this folder and find the line that specifies the routing scheme for /articles: |
+ | <source lang="javascript"> | ||
.state('all articles', { | .state('all articles', { | ||
Line 184: | Line 228: | ||
} | } | ||
} | } | ||
+ | </source> | ||
+ | |||
This is ui-route's way of telling the server what to serve the page specified by the templateUrl when it sees "localhost:3000/#!/phones". | This is ui-route's way of telling the server what to serve the page specified by the templateUrl when it sees "localhost:3000/#!/phones". | ||
The #! is a hash prefix used for MEAN to make ajax calls so make sure to include it when coding your views. | The #! is a hash prefix used for MEAN to make ajax calls so make sure to include it when coding your views. |
Latest revision as of 04:38, 1 September 2015
Contents
Installation
To install MEAN, make sure you already have all of the following components installed and configured correctly.
1. Node.js (should come with npm)
To find out if you have node and npm, try checking their versions (may not be the same):
node --version
v0.10.25
npm --version
1.3.24
IF you don't have node.js, install it here.
2. Bower
Bower is a web application manager used by MEAN. To install bower, type the following command in your terminal:
npm install -g bower
3. MongoDB To install MongoDB, follow the instructions for your OS here.
4. Grunt To install Grunt type the following command:
npm install -g grunt-cli
5. and finally, MEAN
In your terminal, type:
> sudo npm install -g mean-cli
What did all that mean?
You just installed four different command line tools. Here's what they all do.
- npm is the package manager for Node.JS. It installs libraries for use by your Node.JS applications. The configuration file for npm (the list of packages for npm to install) is package.json.
- bower is a package manager for front-end libraries. Rather than manually downloading your jQuery, Bootstrap, Angular, and other front-end JavaScript and CSS (and remembering to update them when a new version of one of those libraries comes out), bower installs them for you. The configuration file for bower (the list of packages for bower to install) is bower.json.
- grunt is a build tool designed for JavaScript. It's like make or ant, but for JavaScript. The configuration file for grunt (the list of commands to run when building your project) is Gruntfile.js (a name inspired by the Makefile for make, the dominant C and C++ build tool).
- mean is a utility designed to help you carry out routine tasks associated with developing for the MEAN stack.
Don't be confused by the fact that you use npm to install bower, grunt, and mean. The people who made bower, grunt, and mean just all decided to use npm as the place to publish their projects, probably because the executables themselves are written in Node.JS. They could just as well have chosen apt-get or yum or any of the other package managers you've been using in this class.
Running the Default App
- Init and run an app.
> mean init myApp // create your first app
> cd myApp
> npm install // Install dependencies
> grunt // Launch mean
Make sure MongoDB is connected and running (if you run into problems, refer to the section on MongoDB)
- Go ahead and explore features of the default Article app (such as logging in, adding/deleting articles).
Generating a Package
- By now you should know what a package is in MEAN. If you don't, read this.
- Try creating a package named myPackage by typing:
> mean package myPackage
Locate it inside the packages folder:
- Compare the structure of myPackage folder to that of the default app. Make sure you see both public and server folders and their subfolders.
- Restart your app, make sure you can see a link to the newly created package.
A Closer Look at the App
Take a look at the directory where you app resides, you will see two folders public and server, which contain code for the client side and server side respectively.
Models
Open up article.js in /server/models
MEAN is MVC on the client side and the server side. Since the model is tied to the backend to MongoDB, you will only see the models folder on the server side, which is normal. The models are mongoose models that's why we need to require mongoose (what the following line does):
var mongoose = require('mongoose'), Schema = mongoose.Schema;
The following part then defines the schema:
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
The next part is validations, or criteria an object needs to pass before it can be saved to the DB. The following code is to make sure that an article has a title:
ArticleSchema.path('title').validate(function(title) {
return title.length;
}, 'Title cannot be blank');
Finally, Mongoose allows us to define methods to our data objects as well. These are called statics. From the Mongoose doc: Schemas not only define the structure of your document and casting of properties, they also define document instance methods, static Model methods, compound indexes and document lifecycle hooks called middleware. The following code defines a method called load for the article schema:
ArticleSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
}).populate('user', 'name username').exec(cb);
};
If you have trouble understanding what the code does, review the Mongoose quick start guide.
Models Practice
Define a schema for a model named Phone, name it phone.js and save it in the corresponding folder in 'myPackage' (hint: /packages/myPackage/server/models/) A product needs to have the following fields with specific types. Here is an example of a Phone object can be stored in the MongoDB:
{
"age": 0,
"id": "motorola-xoom-with-wi-fi",
"imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg",
"name": "Motorola XOOM\u2122 with Wi-Fi",
"snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM wi.. d by Android 3.0 (Honeycomb)."
}
This is taken from phones.json used by the AngularJS tutorial. If you have gone through the tutorial, you should have realized that instead of using a DB, json files were used to simplify the tutorial.
Find phones.json in /app/phones in the angular tutorial folder and try importing its content to MongoDB so you can use them in your current MEAN package.
Here is how (assuming mongod is running):
> mongo --shell // connect to mongo shell
> use mean-dev // switches to database used by mean.
> mongoimport --db mean-dev --collection phones --type json --file ''<path to phones.json>'' --jsonArray // imports json file to the DB
> show collections // check to see if phones are added to your database
> coll = db.phones // to see the content of the file
Controllers
You'll find a controllers folder on both the server side and the client (public) side.
- The client side controllers are part of the Angular MVC scheme that contains client side logic and may issue requests to the server.
- The server side controllers deal with the models and requests from the client side.
Server side:
- Find articles.js in the controllers folder. Try to understand what each part does.
Client side: open up articles.js in /articles/public/controllers Compare the functions defined in ArticlesController, can you find the server side implementation of corresponding functions?
Here is a diagram to help you understand how this works:
Views & Routing
Even though typically views are implemented and used for the client end, routing happens on both ends.
- Find articles.js in /server/routes
You'll see that it requires the articles controller and its methods for querying the database.
The first section requires the articles controller, which defines different methods
For example, code below tells the server to use a method named "all" in the articles controller when the url is pointed to /articles:
app.route('/articles')
.get(articles.all)
- Go to http://localhost:3000/articles, what do you see? Does it make sense?
Let's switch to the public folder where the views reside. Go to articles/public/views, open up list.html:
The first line tells the framework that ArticlesController is responsible for this particular view and when this view is loaded, use find() to initiate data binding.
<section data-ng-controller="ArticlesController" data-ng-init="find()">
Feel free to take a look at what find() does. Make sure you understand that what find() does is actually done by the backend, where a corresponding find() is written (as mentioned above). Hopefully you have a better understanding of how these technologies all work together now.
Review the AngularJS section if you have any questions regarding the view data binding.
The view files in articles/views only defines the code for displaying the articles, where does the navigation bar gets defined. The answer is in /public/system.
- The .html files in public/system/views provide a container/layout for the application.
For example, header.html includes the menu bar (displayed on the top of the page):
<div class="left pull-left">
<ul class="navbar-nav nav">
<li data-ng-repeat="item in menus.main" ui-route="/{{item.link}}" ng-class="{active: $uiRoute}">
<a mean-token="item.link" ui-sref='{{item.link}}'>{{item.title}}</a>
</li>
</ul>
</div>
- Try changing {{item.title}} inside the <a> </a>tags to "my articles" see what happens to the page.
- The ui-sref is "href" in ui-route, an AngularJS plugin, try changing {{item.link}} to #!/myarticles,
- What happens to the application now? When you click on "my articles"?
The page to articles is no longer served!
But how does the framework know which page to serve given a certain url? The file responsible for this (called routing in web development) is in public/articles/routes
open up articles.js in this folder and find the line that specifies the routing scheme for /articles:
.state('all articles', {
url: '/articles',
templateUrl: 'public/articles/views/list.html',
resolve: {
loggedin: checkLoggedin
}
}
This is ui-route's way of telling the server what to serve the page specified by the templateUrl when it sees "localhost:3000/#!/phones". The #! is a hash prefix used for MEAN to make ajax calls so make sure to include it when coding your views. Now try changing the url to "/myarticles", save and go back to your app, click on "my articles" now, what happens?
- This is important if you want to customize your navigation bar and links. Just remember that each url needs an entry in the route file, in the format of the example above.
Practice
Can you implement a view in your myPackage to display all phones injected in the DB? Hint: myPackage has the same file structure as the default app.