01 Mar, 2018 · 8 minutes read
The first thing you are going to want to do is to start with a seed project. Read my articleon how to quickly get started using a seed project I created and then come back here.
If you completed the How do I start?section and finished executing the init.jssuccessfully, you would have the following things:-
These changes are the name, description, repository URL & output filename for your project that you provided while executing the init.jsscript.
Open the project folder in your favorite IDE. I prefer Visual Studio Code.
code .
As mentioned in the pre-requisites section, the project now contains changes related to the new project’s name, description, URLs, etc.
Verify the changes and commit them with a message like “Updated package metadata”.
Now do a
npm install
to download the development dependencies. Install
bower,
gulp&
eslintglobally as the
postinstallscript of
package.jsonis set to do a
bower installfollowed by running the default task of
gulp. Gulp itself runs
eslintto check your JavaScript files for errors.
After this, you should have a bower_componentsdirectory in your project. Recall from the previous article that this was ignored using .gitignoreas these aren’t files we should commit (Somebody tell this to whoever manages the default ASP .NET template for Visual Studio. I have to go back in Git history, add the wwwroot/libfolder on .gitignore, delete the damn JQuery files and then ammend the commit.)
Open the srcdirectory where all your source JavaScript files will reside. You should a file name mx-angular-notify.jsin there. This is the JS file that declares your AngularJS module.
My naming convention for this file is as follows:-
At this moment, the file looks like this:
(function () {
"use strict";
angular.module("mx-angular-notify", []);
})();
The entire JavaScript file is wrapped in an annonymous function that is also immediately executed. This is a way to implement namespaces and encapsulation in JavaScript. Read this excellent
postby
"use strict";
While JavaScript is a very powerful language, it is pretty easy to write really messy code in it; code that even you wouldn’t understand after a few months.
“Use Strict”; is an insurance that programmer will not use the loose or the bad properties of JavaScript
angular.module("mx-angular-notify", []);
Next, we declare our AngularJS module mx-angular-notify. Again, I am using mxAngularas a prefix to prevent clashes with other AngularJS modules. You can choose anything anything that seems unique to you or if your module is very unique and nobody has published anything similar on Bower you can omit the prefix. But, in this case, there are several toast notification modules available on Bower. My module is more of a wrapper around the toastrmodule that I intend to use across many of my projects.
Speaking of toastr, let’s add it as a dependency in our module.
angular.module("mx-angular-notify", ["toastr"]);
So, the entire file looks like:-
(function () {
"use strict";
angular.module("mx-angular-notify", ["toastr"]);
})();
The next step is to add a Bower dependency for the package angular-toastrwhich contains the toastrmodule we need. So, I added the following line to bower.jsonin the dependenciessection.
"angular-toastr": "2.1.1"
The Bower.json file now looks like:-
{
"name": "mx-angular-notify",
"description": "AngularJS module for showing toast notifications",
"version": "1.0.0",
"homepage": "https://github.com/maxotek/mx-angular-notify",
"license": "MIT",
"private": false,
"dependencies": {
"angular": "v1.6.9",
"angular-toastr": "2.1.1"
}
}
You may have to do a
bower install
from the command line. But, many IDEs automatically download bower dependencies when
bower.jsonchanges. You
bower_componentsfolder should now have a folder for
angular-toastr, our new package.
It is time to add our AngularJS service. But, before that we need to create a directory to hold all of our services (well in this case there is only going to be one, but you get the idea). So create a servicesfolder under src.
Now add our AngularJS service file. We’ll call it
mxngNotifyService.js. The naming convention is
Paste the following code in this file:-
"use strict";
(function () {
angular
.module("mx-angular-notify")
.factory("mxngNotifyService", mxngNotifyService);
mxngNotifyService.$inject = ["toastr"];
function mxngNotifyService(toastr) {
return {
displaySuccess: displaySuccess,
displayError: displayError,
displayWarning: displayWarning,
displayInfo: displayInfo,
handleDataError: handleDataError
};
function displaySuccess(message) {
toastr.success(message);
}
function displayError(error) {
if (Array.isArray(error)) {
error.forEach(function (err) {
toastr.error(err);
});
} else {
toastr.error(error, "Error");
}
}
function displayWarning(message) {
toastr.warning(message);
}
function displayInfo(message) {
toastr.info(message);
}
function handleDataError(response) {
console.log(response);
if (!response.data)
return displayError("Unable to connect to API server");
var error = response.data.message || response.data.error_description;
if (error)
displayError(error);
else
displayError(response.statusText);
}
}
})();
Here, we are registering our service. Again, we use the global prefixing here to avoid clash with AngularJS services we might use from other projects.
angular
.module("mx-angular-notify")
.factory("mxngNotifyService", mxngNotifyService);
Next, we are using dependency injection to get a reference to the toastrservice.
mxngNotifyService.$inject = ["toastr"];
function mxngNotifyService(toastr) {
Setting the dependency with $inject and a string reference for
toastrhelps us during minification which will rename the
toastrargument to the
mxngNotifyServicefunction. No matter what it’s name is after minification, it will passed a reference to the
toastr
service because the string inside
["toastr"]
will not be renamed during minification. This is used by AngularJS framework to pass the correct service.
One thing to note here is that the order of the services must be identical inside $injectand the parameters inside mxngNotifyServiceotherwise you’ll end up with wrong services being passed to your function parameters!!!
I know its a bit of extra work this way. But, you get the benefit of there being no issues during minification which is a must for production.
Next, we expose some functions through our service by returning them in this object:-
return {
displaySuccess: displaySuccess,
displayError: displayError,
displayWarning: displayWarning,
displayInfo: displayInfo,
handleDataError: handleDataError
};
I prefer returning the object upfront so that it is clear right at the top, what properties/functions this service is exposing. But, you could return this at the very end as well.
The next section comprises of defining these exposed functions which are just wrappers that I use to handle various errorneous situations with things like HTTP request failures.
function displaySuccess(message) {
toastr.success(message);
}
function displayError(error) {
if (Array.isArray(error)) {
error.forEach(function (err) {
toastr.error(err);
});
} else {
toastr.error(error, "Error");
}
}
function displayWarning(message) {
toastr.warning(message);
}
function displayInfo(message) {
toastr.info(message);
}
function handleDataError(response) {
console.log(response);
if (!response.data)
return displayError("Unable to connect to API server");
var error = response.data.message || response.data.error_description;
if (error)
displayError(error);
else
displayError(response.statusText);
}
Finally, we enclose our module in the annonymous function that does encapsulation while executing it immediately.
})();
Now, let us commit the changes below with a message like Added notification service
Finally, let us update the README.MD file with details of the new project and commit it.
Next go to the terminal and run
gulp clean default
.
The clean task declared in
gulpfile.jswill remove any temporary files generated in the
distfolder when we initially ran
npm install
.
The default task itself just calls the lintand scriptstasks which inspect the JavaScript files for errors, combines them and puts them under the distfolder as: mx-angular-notify.js. Furthermore, the scripttask uglifies this file by renaming locals, removing whitespace, etc and generates the mx-angular-notify.min.jswhich is meant to be used in production. If we did not use the $injectproperty in our code, dependency injection would fail when we tried using the mx-angular-notify.min.jsfile in our projects because the parameter toastrwould be renamed to something obscure. Dependency injection in AngularJS works by matching names.
So, that’s it folks. We have created our AngularJS service.