Introduction
Encapsulation is one of the main concepts in object oriented programming. It allows an object to group both private and public members under a single name. All the object oriented programming languages support this. Since JavaScript is also an object oriented programming language, it supports it too.
In this article, we will see how to achieve encapsulation in JavaScript by creating a simple object named CssManager
that helps to dynamically add, remove, or swap a style-sheet.
Plan
- Create a namespace named
Managers
that wraps our object. - Create a singleton object named
CssManager
. - Add public methods to the object for adding, removing, and swapping a stylesheet.
- Create private members.
Code
Create a namespace named Managers
that will wrap our object
In JavaScript, creating a namespace is as simple as creating an object literal.
var Managers = {};
Very simple, right?
Now you can wrap all the classes and objects related to Managers
in a single namespace.
Create a singleton object named CssManager
Managers.CssManager = {
}
The code between the pair of curly braces forms the part of the object.
Add public methods to the object for adding, removing, and swapping a stylesheet
In JavaScript, an object acts much like an associative array, i.e., an array of key-value pairs. The key is a property or a method.
Create the method addStyleSheet
that takes two parameters: the stylesheet element ID, and the reference URL.
Managers.CssManager = {
addStyleSheet: function(id, url){
}
}
In addStyleSheet()
, we will do the following things: dynamically create a link element, set its attributes, and append to the head section.
Managers.CssManager = {
addStyleSheet: function(id, url){
var newStyleSheet = document.createElement("link");
newStyleSheet.setAttribute("rel", "stylesheet");
newStyleSheet.setAttribute("type", "text/css");
newStyleSheet.setAttribute("id", id);
newStyleSheet.setAttribute("href", url);
document.getElementsByTagName("head")[0].appendChild(newStyleSheet);
}
}
Add the other two methods..
Managers.CssManager = {
addStyleSheet: function(id, url){
var newStyleSheet = document.createElement("link");
newStyleSheet.setAttribute("rel", "stylesheet");
newStyleSheet.setAttribute("type", "text/css");
newStyleSheet.setAttribute("id", id);
newStyleSheet.setAttribute("href", url);
document.getElementsByTagName("head")[0].appendChild(newStyleSheet);
},
removeStyleSheet: function(id){
var currentStyleSheet = document.getElementById(id);
if(currentStyleSheet){
currentStyleSheet.parentNode.removeChild(currentStyleSheet);
}
},
swapStyleSheet: function(id, url){
this.removeStyleSheet(id);
this.addStyleSheet(id, url);
}
}
In removeStyleSheet
, we query for the particular stylesheet element (link) and remove it completely from DOM. While in swapStyleSheet
, we are calling the other two methods to replace an existing stylesheet with a new one.
Create private members
So far, all the methods created are public. I would like to add two private members for the sake of the article. The first one is a variable that has the reference to the document
object.
var doc = document;
The second one is a method that sets multiple attributes to the link element at once instead of calling setAttribute()
multiple times.
var setAttributes = function(attributes){
}
Unlike other languages, we can't easily mark members as public or private in JavaScript. To create private members, we have to use Closures. Closures help to create a private space. We are not going to see what closures are here, but let's see how they help to create private members.
Let's modify our CssManager
to apply a closure:
Managers.CssManager = (function(){
return{
addStyleSheet: function(id, url){
var newStyleSheet = doc.createElement("link");
setAttributes(newStyleSheet, {
rel : "stylesheet",
type : "text/css",
id : id,
href: url
});
doc.getElementsByTagName("head")[0].appendChild(newStyleSheet);
},
removeStyleSheet: function(id){
var currentStyleSheet = doc.getElementById(id);
if(currentStyleSheet){
currentStyleSheet.parentNode.removeChild(currentStyleSheet);
}
},
swapStyleSheet: function(id, url){
this.removeStyleSheet(id);
this.addStyleSheet(id, url);
}
}
})();
What we have done is created a Closure that looks like a self executing anonymous function that returns the public methods we added earlier. The pair of parentheses at the end makes the code get executed automatically. All the members returned by the return
statement are public, while the ones that come before are private.
(function(){
return{
}
}();
Add our two new members in the private space:
Managers.CssManager = (function(){
var doc = document;
var setAttributes = function(element, attributes){
for(attribute in attributes){
element[attribute] = attributes[attribute];
}
}
return{
addStyleSheet: function(id, url){
var newStyleSheet = doc.createElement("link");
setAttributes(newStyleSheet, {
rel : "stylesheet",
type : "text/css",
id : id,
href: url
});
doc.getElementsByTagName("head")[0].appendChild(newStyleSheet);
},
removeStyleSheet: function(id){
var currentStyleSheet = doc.getElementById(id);
if(currentStyleSheet){
currentStyleSheet.parentNode.removeChild(currentStyleSheet);
}
},
swapStyleSheet: function(id, url){
this.removeStyleSheet(id);
this.addStyleSheet(id, url);
}
}
})();
How to use
Our CssManager
is ready! If you want to add a stylesheet to a page dynamically, call the addStyleSheet
method, passing a unique ID and the HREF of the external CSS file as below:
Managers.CssManager.addStyleSheet("myStyleSheet", "Default.css");
Likewise, you can even remove it or replace it with a new one:
Managers.CssManager.removeStyleSheet("myStyleSheet");
Managers.CssManager.swapStyleSheet("myStyleSheet", "Advanced.css");
That's all! We have done it!! Thanks for reading this. If you feel this article is helpful to you, don't forget to vote. Please check out the attached sample code that shows how the CssManager
helps to dynamically change the theme of a page.
**Coding is poetry**