Section 8 - Examining Famous Frameworks and Libraries
Building Our own Framework
Requirements
Name: Greetr
Generates form and informal greetings
Reusable, and non interfearing
English and Spanish
Easy to Type structure
$G
Support Jquery
Structuring safe code
...
(function (global, $){
})(window, $)
What happened:
Immediately invoked function that creates a new execution context, keeping our variables safe.
2 global objects where passed that we're going to work with.
Part 2
(function (global, $){
var Greetr = function(first, last, lang) {
return new Greetr.init(first, last, lang);
}
}
Greetr is a function, that when invoked, returns a new object, so that we do have to use the keyword ourselves.
Init is not yet defined, but is a common keyword used to handle initialization.
(function (global, $){
var Greetr = function(first, last, lang) {
return new Greetr.init(first, last, lang);
}
Greetr.prototype = {};
Greetr.init = function(first, last, lang) {
this.firstname = first || '[users first name]';
this.lastname = last || '[users last name]';
this.language = lang || 'en';
// defined later -> checks if language is supported
this.validate();
}
Greetr.init.prototype = Greetr.prototype;
})(window, $)
Next we implement our object constructor.
Unique variable primitive to our library are defined as a properties to each respected object.
Default variables are invocated by coersion.
We defined a new object as a prototype (inheritance) to each object.
Save memory space by not passing it into the constructor.
Empty for now
Because objects where constructed with .init (seperate execution context), we want all Greetr/prototype objects to point to Greetr.init.prototype.
Allows us to define methods in Greetr.prototype more cleanly.
global.Greetr = global.$G = Greetr;
One last thing before we finish. To establish a neat alias, all we have to set our object function constructor as part of the global window.
Now, we can treat Greetr, and $G equivalently as constructors.
var g = $G('dan','mak');
console.log(g); // G…r.init {firstname: "dan", lastname: "mak", language: "en"}
Part 3
var supportedLang = ['en', 'es'];
Greetr.prototype = {
};
The next part is really cool. Its just like constructing classes in C++.
Each unique object will have access to methods defined without our prototype, thanks to our pointer fix.
Variables constructed WITHIN the immediately invoked function will remain 'private' to the methods within the prototype.
That way, our framework is defined where it needs to be, and does not mess around with any global context.
Our prototype, however - maintains access to these variables because of closure.
var greetings = {
en: 'Hello',
es: 'Hola'
};
var formalGreetings = {
en: 'Greetings',
es: 'Saludos'
};
var logMessages = {
en: 'Logged In',
es: 'Inicio sesion'
};
Next, we define a few reference variables for our prototype methods.
fullname: function() {
return this.firstname + ' ' + this.lastname;
},
validate: function() {
if (supportedLang.indexOf(this.language) === -1) {
throw "Invalid language";
}
else {
console.log("Valid language");
}
},
greeting: function() {
return greetings[this.language] + ' ' + this.firstname + '!';
},
formalGreeting: function() {
return formalGreetings[this.language] + ' ' + this.fullname();
},
greet: function(formal) {
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
//show whats happening
if (console) {
console.log(msg);
}
return this;
},
log: function() {
//Internet explore check if console is open
if (console) {
console.log(logMessages[this.language] + ' ' + this.fullname());
}
//chainable
return this;
},
setLang: function(lang) {
this.language = lang;
this.validate();
return this;
}
Each of these functions will reference with a uniquely constructed new object.
This is why the keyword this becomes so important.
validate searches through our index of supported languages with this.language, - the current language supplied to an object.
throws and error if the language is invalid.
function greet is not required, but it grants chainable methods to our library. It also simplifies two methods with a single invocation
Optional boolean variable passed in to invoke a formal greeting.
At first I thought it was strange that setLand first let the language, and then validated it, but then I realized something.
Even if we change the language of an object to something that is not supported, it does not matter because it of this.validate().
If an error is thrown, then the setLand does not return, so it wouldn't allow it to pass through.
Testing so far
var a = g.fullname();
console.log(a); // dan mak
g.validate(); // Valid language
var b = g.greeting();
console.log(b); // Hello dan!
var c = g.formalGreeting();
console.log(c); // Greetings dan!
g.greet(); // Hello dan!
g.log(); // Logged In dan mak
g.setLang('germen');
g.validate(); //Uncaught Invalid language
Part 3
Adding jQuery support
EnglishSpanish
HTMLGreeting: function(selector, formal) {
if (!$) {
throw 'Jquery not loaded';
}
if (!selector) {
throw 'Missing Jquery selector';
}
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
$(selector).html(msg);
return this;
}
This function will be used to modify our html page once all of our variables are taken into account. The selector is a jQuery element.
Everything else references variables that are already known in the constructed object.
We also have a bit of jQuery code on the bottom, that is used to modify any html attribute.
It is always best to commenet up your code once you finish. It may be understood now, but in time - the memory of your intents may be lost.
It also helps other coders.
Since I've documented my thoughts here, I wont bother.
$('#login').click(function() {
var g = $G('dan','mak');
var loginGreeter = g;
$('#logindiv').hide();
loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
});
Finally, its time to finish up our project by adding jQuery functionality to our html.
That long chained method looks complecated, but lets break it down:
Using our constructed object, we set our variable property using a jQuery selector on the html element.
The next function call can be thought of as being executed on a new line.
The Final Library/Framework
//HTML
<html>
<head>
</head>
<body>
<div id="logindiv">
<select id="lang">
<option value="en">English</option>
<option value="es">Spanish</option>
</select>
<input type="button" value="Login" id="login">
</div>
<h1 id="greeting"></h1>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="Greetr.js"></script>
<script src="app.js"></script>
</body>
</html>
//Greetr.js
(function (global, $){
var Greetr = function(first, last, lang) {
return new Greetr.init(first, last, lang);
}
var supportedLang = ['en', 'es'];
var greetings = {
en: 'Hello',
es: 'Hola'
};
var formalGreetings = {
en: 'Greetings',
es: 'Saludos'
};
var logMessages = {
en: 'Logged In',
es: 'Inicio sesion'
};
Greetr.prototype = {
fullname: function() {
return this.firstname + ' ' + this.lastname;
},
validate: function() {
if (supportedLang.indexOf(this.language) === -1) {
throw "Invalid language";
}
else {
console.log("Valid language");
}
},
greeting: function() {
return greetings[this.language] + ' ' + this.firstname + '!';
},
formalGreeting: function() {
return formalGreetings[this.language] + ' ' + this.fullname();
},
greet: function(formal) {
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
//show whats happening
if (console) {
console.log(msg);
}
return this;
},
log: function() {
//Internet explore check if console is open
if (console) {
console.log(logMessages[this.language] + ' ' + this.fullname());
}
//chainable
return this;
},
setLang: function(lang) {
this.language = lang;
this.validate();
return this;
},
HTMLGreeting: function(selector, formal) {
if (!$) {
throw 'Jquery not loaded';
}
if (!selector) {
throw 'Missing Jquery selector';
}
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
$(selector).html(msg);
return this;
}
};
Greetr.init = function(first, last, lang) {
this.firstname = first || '[users first name]';
this.lastname = last || '[users last name]';
this.language = lang || 'en';
// check language
this.validate();
}
Greetr.init.prototype = Greetr.prototype;
global.Greetr = global.$G = Greetr;
})(window, $)
//app.js
$('#login').click(function() {
var g = $G('dan','mak');
var loginGreeter = g;
$('#logindiv').hide();
loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
});
Last updated
Was this helpful?