Building A Content Management System Using The MEAN Stack - 7 (Front-End Development)
Repository
https://github.com/nodejs/node
What Will I Learn
The codebase for this tutorial is based on MEANie an open source content management system by Jason Watmore.
This is the seventh in the series of tutorials on building a content management system using the MEAN technology.
In the last tutorial we created the pages
, redirects
and account
view for the admin area.
In this tutorial we will work on the last service module needed for the admin area.
We will also work on all directives and filters needed for this application.
By the end of this tutorial we will have completed work on all the features for the admin section of the application.
N.B;- LINK TO THE EARLIER TUTORIALS IN THIS SERIES CAN BE FOUND AT THE END OF THIS POST
Requirements
- NodeJS and NPM,
- Angular
- MongoDB
- Code Editor
Difficulty
- Intermediate
Tutorial Contents
Services
Data Service
In the admin area of the CMS we have the following views
- Posts
- Pages
- Redirects
- Accounts
Each view has a service that interacts with the backend to extract data, all these service need a data service in the client side that will fetch and get all needed from the backend.
This data service will then provide all data needed by all other client side services.
We will create the data service in the services
directory located in the admin
directory.
Create a new file data.service.js
and paste the code
(function () {
'use strict';
angular
.module('app')
.factory('DataService', Service);
// generic data service to be used as base for other entity services
function Service($http, $q) {
return function (endPoint) {
var service = {};
service.GetAll = GetAll;
service.GetById = GetById;
service.Save = Save;
service.Delete = Delete;
return service;
function GetAll() {
return $http.get(endPoint).then(handleSuccess, handleError);
}
function GetById(id) {
return $http.get(endPoint + '/' + id).then(handleSuccess, handleError);
}
function Save(entity) {
if (entity._id) {
// update
return $http.put(endPoint + '/' + entity._id, entity).then(handleSuccess, handleError);
} else {
// create
return $http.post(endPoint, entity).then(handleSuccess, handleError);
}
}
function Delete(id) {
return $http.delete(endPoint + '/' + id).then(handleSuccess, handleError);
}
}
// private functions
function handleSuccess(res) {
return res.data;
}
function handleError(res) {
return $q.reject(res.data && res.data.Message);
}
}
})();
Data service contains the main function Service()
which is the container function for all the other DataService
methods.
DataService()
firstly returns an object service
which has the following methods
GetAll
GetbyId
Save
Delete
GetAll()
returns the data gotten as the result of a http GET
request to the endpoint specified.
GetById()
returns the id
of the data gotten as the result of a http GET
request to the endpoint specified.
Save()
has a parameter entity
which represents a collection in the database.
The function checks if the collection already exists in the database by comparing ids
.
If the collection exists the function updates data in the collection with new data provided else the function creates a new collection with the name stored in entity
and saves the data provided in it.
Delete()
has a parameter id
representing the id
of the endpoint specified in the database.
The function sends a DELETE
request to the endpoint that has id
that matches the one provided as parameter to the function.
Directives
Our application uses some extra features that requires special instructions to make them work the way we want them to.
We are going to issue special instructions for post tags
The special instructions will be stored in a directory directives
in the admin
directory.
Post Tags
In the directives
directory add a new file tags.directive.js
which will contain the directives for the post tags behavior.
In the tags.directive.js
file paste the following code
(function () {
'use strict';
angular
.module('app')
.directive('tags', Directive);
function Directive($filter) {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
// convert to comma separated string for display
ngModel.$formatters.push(function (tags) {
return $filter('csv')(tags);
});
// convert to array for storage
ngModel.$parsers.push(function (tagsString) {
var tags = _.map(tagsString.split(','), function (tag) {
// trim any extra spaces
return tag.trim();
});
// remove any empty tags
tags = _.filter(tags, function (tag) { return tag; });
return tags;
});
}
};
}
})();
Directive($filter)
is the main function in the file and it returns an object which determines the behavior of the tags included in the posts.
require: 'ngModel'
allows us access the controller for the ngModel
directive.
The link()
function contains parameters scope, element, attr
which are requirements for any custom directive.
ngModel.$formatters.push()
will format the post tags such that all post tags will be displayed with a comma separating one from the other using the csv
filter which will be created later.
ngModel.$parsers.push()
will convert all the inputted tags into an array to prepare for storage in the database.
Filters
In this section we will add the filters needed for some of the front end features to display correctly.
Create a new directory filters
in the admin
directory. We will add two filters including
- CSV filter
- Slugify filter
CSV Filter
In the filters directory add a new file csv.filter.js
.
In the tags directive earlier we used the csv
filter to add commas in between the tags.
The code for csv.filter.js
(function () {
'use strict';
angular
.module('app')
.filter('csv', Filter);
function Filter() {
return function (array) {
if (!array)
return;
return array.toString().replace(/,/g, ', ');
};
}
})();
The Filter()
method will check if the tags are not stored in an array, if that condition is true then the function ends.
If the condition is false the function converts the contents of the array into string and all the cases where /
can be found in the list of tags will be replaced with ,
.
Slugify Filter
The slugify filter will format the display characteristics of the slugs included in the page and post details.
In the filters
directory add a new file slugify.filter.js
.
Paste the following code in the file
(function () {
'use strict';
angular
.module('app')
.filter('slugify', Filter);
function Filter() {
return function (input) {
if (!input)
return;
// make lower case and trim
var slug = input.toLowerCase().trim();
// replace invalid chars with spaces
slug = slug.replace(/[^a-z0-9\s-]/g, ' ');
// replace multiple spaces or hyphens with a single hyphen
slug = slug.replace(/[\s-]+/g, '-');
return slug;
};
}
})();
The Filter()
method in this file firstly checks if there is an input to work on, if there isn't the function ends but if there is the function continues with the execution.
The value of input
is then converted to lowercase and and trimmed of any whitespace. This new value is stored in the variable slug
All invalid characters in slug
is then replaced with spaces.
And all spaces in slug
is then replaced with hyphens.
We have completed work on the admin
section of the application, in the next tutorial we will start work on the front end view of the blog
section of the application.
Curriculum
Building A Content Management System Using The MEAN Stack - 2(Create Controller Modules 1)
Building A Content Management System Using The MEAN Stack - 3 (Create Controller Modules 2)
Building A Content Management System Using The MEAN Stack - 4 (Create Services Modules)
Building A Content Management System Using The MEAN Stack - 5 (Front-End Development)
Building A Content Management System Using The MEAN Stack - 6 (Front-End Development)
Thank you for your contribution @gotgame.
After analyzing your tutorial we suggest the following points:
We suggest you put images of what is being developed. Images makes the tutorial more interesting.
Put the title with more keywords, such as NodeJS and Angular.
The code is very well explained and quite simple. Good job!
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Thank you for your review, @portugalcoin!
So far this week you've reviewed 8 contributions. Keep up the good work!
Hi @gotgame!
Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server
Hello, as a member of @steemdunk you have received a free courtesy boost! Steemdunk is an automated curation platform that is easy to use and built for the community. Join us at https://steemdunk.xyz
Upvote this comment to support the bot and increase your future rewards!
Hey, @gotgame!
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!