April / May 2021
🔨 Blog for developers using Node and Express, MongoDB and Mongoose as ODM, and Angular on Client side (MEAN Stack). From udemy: La MEAN stack par la pratique - Samir Medjdoub / Code Concept with some improvements.
Mean Stack refers to a collection of JavaScript technologies used to develop web applications. Therefore, from the client to the server and from server to database, everything is based on JavaScript. MEAN is a full-stack development toolkit used to develop a fast and robust web applications.
MEAN is a user-friendly stack which is the ideal solution for building dynamic websites and applications. This free and open-source stack offers a quick and organized method for creating rapid prototypes for web-based applications.
MEAN is comprised of four different technologies:
- MongoDB express is a schemaless NoSQL database system
- Express JS is a framework used to build web applications in Node
- AngularJS is a JavaScript framework developed by Google
- Node.js is a server-side JavaScript execution environment
With this app, developers can register and login to add and share some articles about technologies, languages, librairies and so on.
The homepage displays all the articles (extracts). When clicking on them, we have access to the complete article. Authors can add, delete or update their own articles. Admin have the right to do the same but for all authors.
Angular is the part that manage displaying of the views according to events. But evything is Managed with the node server including session management (passport), password encryption and credential validation (Mongoose schemas) or user registrations, sending the articles of the author only or all to the admins, check size and mime of the images (Multer) or send errors to the client side.
Test the application on Heroku.
You can test the app using these credentials if you don't want to register:
User name: special-guest
Password: MeanStack-2021-05-25
NB: due to the fact that the application is hosted on Heroku using external services like MongoDB Atlas, it can be slow to start (services use cold start) and when running.
With file uploads and MongoDB on local:
Clone and use dev-version branch.
With cloudinary and MongoDB Atlas instead, clone main.
Start server
You need MongoDB installed for dev-version.
sudo service mongodb start
From root: cd server
npm install
npm start
The server should run at http://localhost:3000.
Start client app
From root: cd client
npm install
npm start
The app should run at http://localhost:4200.
Whatever the version, environment variables will have to be change from both server and client side following the exemples.
- ./src/app/app.module.ts: import / export all modules used in the application.
- ./src/app/app-routing.module.ts: routing.
- ./src/app/material.module.ts: import / export modules related to material design. ./src/app/material.module.ts has to be imported in ./src/app/app.module.ts.
Home
- ./src/app/app.component.html: <router-outlet> add the content from routing component ./src/app/app-routing.module.ts.
blogposts list
- ./src/app/models/blogpost.ts: typed interface for Blogpost.
- ./src/app/services/blogpost.service.ts: request on MongoDB.
- ./src/app/blogpost-list/blogpost-list.component.ts: observable on Blogpost[].
- ./src/app/blogpost-list/blogpost-list.component.html: view. Uses routerLink to not reload the page when we click on a link.
- ./src/environments/environment.ts: images path
blogpost by id
- ./src/app/models/blogpost.ts: typed schema.
- ./src/app/app-routing.module.ts: add a route for "blog-posts/:id".
- ./src/app/services/blogpost.service.ts: request on MongoDB.
- ./src/app/services/blogpost/blogpost.component.ts: observable on Blogpost. Uses ActivatedRoute to retrieve url and id.
- ./src/app/blogpost/blogpost.component.html: view.
Exemple to display detail of an object: <div>{{blogPost$ | async | json}}</div>
admin
- ./src/app/admin/admin.component.html: view with CRUD.
- ./src/app/admin/admin.component.ts: request on MongoDB. CRUD on all articles.
blogposts create
- ./src/app/services/blogpost.service.ts: request on MongoDB +
subject
to refresh ./src/app/admin/admin.component.html. Method upload(). - ./src/app/blogpost-create/blogpost-create.component.html: view with submission form.
- ./src/app/blogpost-create/blogpost-create.component.ts: manage FormGroup and dispatching for refresh.
blogposts edit
- ./src/app/services/blogpost.service.ts: request on MongoDB
- ./src/app/blogpost-edit/blogpost-edit.component.html: Template driven form
- ./src/app/blogpost-edit/blogpost-edit.component.ts: Manage upload and updated blogpost
auth
- ./src/app/auth/auth.component.html: Display login.
- ./src/app/auth/auth.component.ts: Manage login.
- ./src/app/models/user.ts: typed interface for login page.
- ./src/app/services/auth.service.ts: Connect to base url. Manage login/logout/register routes.
- _./src/app/services/add-cookie.interceptor.ts: HTTP Interceptor: centralizes the sending of the header in each request (used for the cookie).
register
- ./src/app/register/auth.component.html: Display register.
- ./src/app/register/auth.component.ts: Manage register.
- ./src/app/models/user.ts: typed interface for Blogpost.
- ./src/app/services/auth.service.ts: Connect to base url. Manage login/logout/register routes.
- ./appjs: Express and Mongo connection. Static folders. Session midlewares
- ./utils/resize.js: Helper to resize images.
- ./api/models/blogpost.js: Mongoose model for CRUD.
- ./api/v1/index.js: Routes + Api CRUD.
- ./auth/models/user.js: Mongoose model for users.
- ./auth/routes/index.js: Routes + Api users.
An observable is source of collections of multiple values pushed when we suscribe.
An Observer is a consumer of values delivered by an Observable. Observers are simply a set of callbacks, one for each type of notification delivered by the Observable: next
, error
, and complete
.
A subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified. Subscribing to the output Observable will also subscribe to the input Observable.
We define a higher-order Observable whenever we use data emitted from one Observable to emit another Observable. ... In the code above, we subscribe to the outer Observable but we don't subscribe to the inner Observable. Since Observables are lazy, they won't emit until subscribed.
In Angular, a module is a mechanism to group components, directives, pipes and services that are related, in such a way that can be combined with other modules to create an application. An Angular application can be thought of as a puzzle where each piece (or each module) is needed to be able to see the full picture.
Ex: ng g m material --flat
=> Ceate module _src/app/material.module.ts
Components are the main building block for Angular applications. Each component consists of: An HTML template that declares what renders on the page. A Typescript class that defines behavior. A CSS selector that defines how the component is used in a template.
Ex: ng g c blogpost --skip-tests --module=app
=> Create new blogpost component
We use interfaces instead classes because we don't need behaviors (methods).
Ex: Interface blogpost.ts in _src/app/models
Angular services are singleton objects that get instantiated only once during the lifetime of an application. ... The main objective of a service is to organize and share business logic, models, or data and functions with different components of an Angular application.
Ex: ng g s blogpost
=> Create new blogpost service
Template Driven Forms Features
- Easy to use
- Suitable for simple scenarios and fails for complex scenarios
- Similar to AngularJS
- Two way data binding(using [(NgModel)] syntax)
- Minimal component code
- Automatic track of the form and its data(handled by Angular)
- Unit testing is another challenge
EX: ./src/app/blogpost-create/blogpost-edit.component.html:
Reactive Forms Features
- More flexible, but needs a lot of practice
- Handles any complex scenarios
- No data binding is done (immutable data model preferred by most developers)
- More component code and less HTML markup
- Reactive transformations can be made possible such as
- Handling a event based on a debounce time
- Handling events when the components are distinct until changed
- Adding elements dynamically
- Easier unit testing
EX: ./src/app/blogpost-create/blogpost-create.component.html:
Two-way binding gives components in your application a way to share data. Use two-way binding to listen for events and update values simultaneously between parent and child components.
Dependency Injection is often more simply referred to as DI. The paradigm exists throughout Angular. It keeps code flexible, testable, and mutable. Classes can inherit external logic without knowing how to create it. Any consumers of those classes also do not need to know anything.
DI saves classes and consumers alike from having to know more than necessary. Yet the code is as modular as it was before thanks to the mechanisms supporting DI in Angular.
The Angular HTTP Interceptor is introduced along with the new HTTPClientModule. The Interceptor helps us to modify the HTTP Request by intercepting it before the Request is sent to the back end. The Interceptor can be useful for adding custom headers to the outgoing request, logging the incoming response, etc.
The process whereby an object or data structure is translated into a format suitable for transferral over a network, or storage (e.g. in an array buffer or file format).
In JavaScript, for example, you can serialize an object to a JSON string by calling the function JSON.stringify().
- express: Fast, unopinionated, minimalist web framework for node.
npm i express
- eslint: ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code.
npm i eslint --save-dev
npm install --save-dev eslint-config-prettier
- cors: CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
npm i cors
- nodemon: nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
npm install --save-dev nodemon
- mongoDB: MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.
WSL2:
sudo service mongodb status
: status for checking the status of your database.sudo service mongodb start
: start to start running your database.sudo service mongodb stop
: stop to stop running your database.
Shell
-
mongo
: MongoDB shell -
show dbs
: View databases -
use [DB_NAME]
: Choose databases -
show collections
: View collections -
db.[COLLECTION_NAME].find({})
: View documents in collection -
mongoose: Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.
npm i mongoose
- multer: Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.
npm i multer
- sharp: The typical use case for this high speed Node.js module is to convert large images in common formats to smaller, web-friendly JPEG, PNG, WebP and AVIF images of varying dimensions.
npm i sharp
- passport: Passport is Express-compatible authentication middleware for Node.js.
npm i passport cookie-parser express-session passport-local
- dotenv: PDotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.
npm i dotenv
- npm i mongoose-unique-validator: mongoose-unique-validator is a plugin which adds pre-save validation for unique fields within a Mongoose schema.
npm i mongoose-unique-validator
- argon2: A library to help you hash passwords.
npm i argon2
- password-validator: A library to check password validity.
npm i password-validator
- cloudinary: Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline..
npm i cloudinary
Kill process on port (here 3000)
lsof -i:3000
kill -9 [PID]
- Angular CLI: The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications directly from a command shell.
ng new my-first-project
cd my-first-project
ng serve
npm install -g @angular/cli
- Angular Material: Material Design components for Angular.
ng add @angular/material
- @kolkov/angular-editor: A simple native WYSIWYG/Rich Text editor for Angular 6-10+.
npm i @kolkov/angular-editor
npm i @angular/flex-layout
cd client
ng build --prod --base-href --output-path ./../server/public/client
On root:
heroku login
(heroku create my-app
)
(heroku git:remote -a my-app
)
git add .
git commit -m "my message"
git subtree push --prefix server heroku master
If errors, check with:
heroku logs --tail
- codeconcept/whisky-cms-ng.
- codeconcept/whisky-cms-ng-srv.
- Comment installer MongoDB sur Ubuntu 20.04.
- Install MongoDB - WSL 2.
- The mongo Shell.
- Moogose - Models.
- Node.js Authentication with Passport.
- Using Argon2 with Node.js.
- Angular la difference entre ngoninit et constructor.
- Angular Dependency Injection Explained with Examples.
- Structural Directives.
- Comment gérer l’injection de dépendances dans angular?.
- Angular Forms - Template Driven & Reactive Forms | Explain.
- Angular - Text interpolation.
- Angular - https://angular.io/guide/router.
- Understanding Angular Property Binding and Interpolation.
- Interpolation Vs Property Binding in Angular2.
- Understanding Angular Property Binding and Interpolation.
- Angular 11 MatDialog Basics
- Theming your Angular Material app
- How to reset file input form after uploading the image in Angular?
- Angular2 set value for formGroup
- How to use environment variables to configure your Angular application without a rebuild
- FormData.append()
- Tout pour la redirection HTTP vers HTTPS.
- Deploy Git subdirectory to Heroku.
- Uploading Images to Cloudinary Using Multer and ExpressJS.