We have always loved using MV* frameworks for data-binding. Well, we have our reasons. There was never an easy way to set event listeners on RAW objects and perform certain tasks. Thanks to the recent ECMASCRIPT’s (7.0) proposal, data-binding has never been so easy and best of all, without any help from any framework
Announcing Object/Array.observe
Allow me to introduce you to
a method that asynchronously keeps track of the changes to the data model or
simply an array which allows you to perform certain tasks by providing a callback function every time it detects a change in your data model.
This callback function returns an object that provides the following information.
type of change(add, update, delete) and splice if you are calling observe on an array
name of the property changed
changed object
and the old value of the changed property
Why are we going gaga over data-binding? Well, data-binding is important if you care about keeping the content, presentation and behavior separate. HTML is perfect for declaring static documents and therefore, we need a way to tie our document and data together. With data-binding, we achieve just that. Using Object/Array.observe, we observe the changes in our data model and keep the DOM upto date.
Without further ado, let me show you how easy it is.
Note: Following example uses handlebars (which depends on jQuery) to save me from writing unnecessary DOM manipulation code.
If you have ever written any custom Node.js modules, getting started with Browserify will be a walk in the park. Browserify enables us to write Node.js style modular code and declaring dependencies is even simpler than you think, if you have used require.js in the past. Configuring require.js is a world of hell and their documentation doesn’t help in any way. This is when browserify turns out to be such a relief. Take a look at the following code.
module-alerter.js:
module.exports = function alerter(message) { window.message(message); }
Now, if we were to import this in main.js, we’d write the following.
main.js:
var alerter = require(‘./modules/module-alerter’); document.addEventListener(‘DOMContentLoaded’, function(){ alerter(‘This is awesome’); }, false);
I am sold already. Aren’t you?
Install browserify
You need Node.js installed and NPM comes with Node.js.
npm install -g browserify
Now, let’s set jQuery as our dependency library in our module-alerter.js
var $ = require('jquery'); // Note that we don’t need to specify relative path for our jquery library // jQuery 2.0+ is AMD compatible and it returns jQuery or $ module.exports = function alerter(message) { window.message(message); $(‘body’).css(‘color’, ‘red’); }
Please, use the appropriate directory structure for your modules, libraries. I usually adhere to the following
/modules
- This is where you will put all your custom modules
/vendor
- This is where you will put all your libraries such as jQuery, Backbone, underscore
/assets/js/
- This is where browserify will bundle up all your modules along with vendor libraries in 1 neat and tidy file. (Notice we don’t have anything there yet? We will get to that part)
browserify Magic
It is time to let browserify wave it magic wand over our code and get us to work. Just run the following command by reaching your project directory. In my case, I should be in the directory node (Don’t worry. This is a non-node project. I named it node because I am in love with node.js)
$ browserify src/js/main.js -o assets/js/bundle.js // Please do not prefix $ to the command
Now, switch to the browser and reload or whatever to see the result. Boom! Now, wasn’t that easy?
Your
assets/js/
directory should now look
like this
assets/js/bundle.js
bundle.js is that neat and tidy file I mentioned earlier. You don’t have to worry about what’s in there.
Include this bundle.js in your HTML code right before the body ends. Like this
<script src="assets/js/bundle.js"></script>
There’s one problem though. You might wonder, “Do I have to run this command everytime I add new module/vendor library or re-arrange my modules in project structure?” NO.
What you need is something that will keep a track of changes happening in your project. Something that will over watch your beautiful modular code. Fortunately there’s a Node package that can do that for us. Introducing watchify
I hope that was quick enough and believe me we just took a crack at browserify. There is a ton of things we can do with it. The best place to read up more on Browserify would be the handbook.
If you know what require.js does and Ruby on Rails is your thing, then you have come to the right place. If not, I encourage you to read up on following topics:
Modular approach to writing JavaScript
AMD and JavaScript
Dependency management, Module Loading and Lazy Loading
Installation and Setup
Add 'requirejs-rails' gem in the Gemfile of your project. It relieves you from some manual labour.
Get rid of everything from your application.js which is located under /assets/javascripts/application.js
Now locate your application layout under views/layouts/application.html.erb
Replace your
<%= javascript_include_tag :application %>
with
<%= requirejs_include_tag :application %>
Do ‘Bundle Install’ and Restart rails server. When your server is back up and running, view page source and you should see following in your HEAD
If everything went well thus far, you should see an alert and if you are using Google Chrome, you should also see that in 'Developer Tools’, under ’Network’, require.js and then application.js loaded.
Start writing your modules
Let’s say you need an Ajax loader for your Ajax requests and you wish to write a separate module for it. Great idea. Now, let me tell you how you can write a module that can be loaded with require.js. In other words, this module that we are about to write will comply to AMD (Asynchronous module definition)
Basic module syntax:
ajaxloader.js
define([], function() { //return an object to define the “ajaxLoader" module. var ajaxLoader = { addLoader: function() { // Method }, removeLoader: function() { // Method } } return ajaxLoader; });
You define a module by using ‘define’ and it usually takes 2 arguments 1st of which is an array of it’s dependencies and 2nd is an anonymous function. You can either return a value, another function or an object literal as above.
Basic module with dependencies:
Let’s say our ajaxloader module depends on jQuery. jQuery needs to be passed as a reference. Like this
define([jQuery], function($) { //return an object to define the “ajaxLoader” module. var ajaxLoader = { addLoader: function(element) { // sample method // Perform operation on element passed // Like this console.log($(element)); }, removeLoader: function(element) { // Method // Perform operation on element passed // Like this console.log($(element)); } } return ajaxLoader; });
You must wonder, how does ‘define’ find dependancies? Well, we need to tell require.js about the location where it can find modules, dependencies.
Configure require.js
Open your application.js and let’s add jQuery as your dependency.
There’s a lot of configuration options available at http://requirejs.org/docs/api.html#config however, for now we shall focus on setting jQuery as a dependancy (jQuery is AMD compatible unlike Backbone, underscore and many other popular libraries however, SHIM config can help you our in that regard http://requirejs.org/docs/api.html#config-shim).
Explanation:
Now it’s time to tell require.js about our ajaxloader module. Follow the steps below
Add the following code in application.js right below require.confirg chunk of code
require([‘ajaxloader’], function(){ // This is will only load our ajaxloader module but no need to write anything though });
Now, let’s take a look at our module. our first string parameter in a dependency array is ‘jQuery’ and according to our require.config jquery if CDN fails will be pulled from a ‘vendor’ directory.
Order on which require.js pulls files and sticks them in the head:
require.js
application.js
jquery.min
ajaxloader.js (Loaded after jQuery because it depended on jQuery)
In closing, require.js helps you
Abstract your code without polluting the global namespace by using AMD pattern in your modules.
Manage Dependencies in a much more structured way.
Recently I spoke at an event organized by Idyllic Software for those who are interested in 'Responsive Web Design' and we usually conduct internal sessions for fellow co-workers but this time our front end team decided to push an envelope and wow the strangers.
Checked attribute vs Checked property on checkbox input
This may seem very obvious or unworthy of being talked about but I am sure during our learning era we all have mistakenly used checked attribute to check and uncheck the checkbox input and surprisingly found out that it made no difference. By that I mean, although it changed the visual state of the checkbox input, expected boolean output didn't change. That's because there's a criteria that needs to be fulfilled in order for it provide correct output i.e. Either true or false
checked attribute must only be used to set an initial value because it deals with 'defaultChecked' and not 'checked'.
checked attribute doesn't change the state of the checkbox input however 'checked' property does.
JavaScript
var checkbox = document.getElementById('myCheckBox'); checkbox.onclick = function(){ console.log(this.checked); };
Code above is straightforward. I am attaching an event handler to an input checkbox and inside a function attaching DOM 'checked' property to the current object 'this'. We all know how 'this' works. So, depending on the state of the checkbox, this code logs the correct output in the console.
This is a true story.
It was yet another graveyard shift at MOBIL service station & I was restless. I felt the worst that night while my friends were killing time running around downtown I was working the shift.
1. MOBIL Station
I was considerably calm despite my mood at the time. I put on the uniform, got behind the counter, pushed the cash till back in and greeted my co-worker who was a couple of minutes early but didn't bother me. Never did much for that matter.
I wasn't so busy that night being the busiest station in all of country & all but the usual crowd lingered for coffee & pies. It was going to be just another boring night at work until the incident I am about to let you all in on.
There was only one customer in the store looking out the glass, drinking the coffee I'd made him sometime ago. He was probably a Taxi driver. Irrelevant...
While I was busy weirdly staring at that customer, a woman, probably in her 60s walked in & asked for a cookie & cappuccino. I directed her towards the rack where we kept cookies & newspaper & walked over to the coffee machine.
She waited patiently while I banged, frothed the coffee mug on the platform like it didn't matter how distracted I was. I glanced once or twice & confirmed my suspicion. She was a Prostitute. Not like it mattered. People started pouring in sometime later & I had to finish making the coffee as it always took longer.
I was finally done. I handed her the coffee. She reached into her purse and grabbed as much change as she could find. It was handfull & I knew what was coming. She was going to spend at least a couple of minutes counting it all & giving me the exact but too bad for her. She was short of $2.25
She knew she was going to lose the coffee over that $2.25 but like always I felt sympathy. Maybe this feeling of sympathy comes from my always putting myself into other's shoes. There was not even a bit of hesitation before I offered her that coffee for nothing.
I was glad & so was she. My co-worker saw it all but didn't utter a word because he know I was going to do what I was going to do. My till at the end of my shift was going to be $2.25 short & I was prepared.
I had seen her around the corner on the same street station was on. She'd stand around but never once I saw her trying hard & patronizing the pedestrians.
2. The Corner
This is where it gets interesting. I spotted her back in the store in a que a couple of weeks later. I was feeling little cocky from the past encounter. I was just a young bloke.
Finally it was her turn. She approached the counter, we smiled. We knew each other. She handed me some money & said "Throw that in your till". She had come to pay for the coffee. I counted it but It was more than I expected.
Before disappearing for the night she said something I haven't forgotten till date. It's been almost 5 years but I still hear those words vividly in my ears. She said "YOU ARE A GOOD MAN!", turned around & walked out.
There's nothing much to write except I was already tired of my CMS & wanted something as simple as Tumblr. Now that I have discovered Tumblr can do so many things that I couldn't possibly have imagined doing with Wordpress, it makes me look so dumb, thinking I could have done this months ago as opposed to sitting on my ass with shitty looking blog all this time.
Anyway...wordpress is the past & Tumblr is the new knight.