Implementing “constants” in JavaScript

Tweet about this on TwitterShare on FacebookShare on Google+

Unlike most modern languages, JavaScript till ES5 doesn’t have a clearly defined way of declaring constants. However, in this language, when there is no single defined way, there are multiple suggested way of the implementation.

Math.PI, Math.LN10 are examples of constants which exists in language. We can implement constants in the following three ways:

1. Object.defineProperty

By making a fixed return value for an accessor property or by making writable to be false for a data property we can achieve constant object property.

'use strict';
 
	var CONSTANTS = {};
	Object.defineProperties(CONSTANTS, {
		'PI': {
			get: function(){
				return 3.141592653589793;
			}
		},
		'LN10': {
			value: 2.302585092994046,
			writable: false
		}
	})

2. Object.freeze

This makes the object immutable. You can’t add or delete properties let alone changing the values of assigned properties.

'use strict';
 
	var CONSTS = {
		PI: 3.141592653589793,
		LN10: 2.302585092994046
	}
 
	Object.freeze(CONSTS);

3. Using “const” keyword

This is proposed in Ecmascript 6 (Harmony) proposal.

const PI = 3.141592653589793, LN10 = 2.302585092994046;

This would be the best implementation of constants. Till then, the above two are for you to use.

Tweet about this on TwitterShare on FacebookShare on Google+

Curious case of JavaScript function arguments

Tweet about this on TwitterShare on FacebookShare on Google+

tl;dr: JavaScript function arguments are array like objects, but not exactly an array. It doesn’t support most of the array properties, however you can invoke array methods using ‘call()/apply()’ from the array prototype object.

All JavaScript function objects (every function is an object) have a property called “arguments”. This object contains an entry for each argument passed to that function. Print the argument and you’ll see an array like representation.

The thing to note here is that, the arguments are not an object of the array class. They are just array like indexed elements and support length() method. argumentsInstanceOf.js

They don’t support the array methods like join(), reverse() etc, which an array object would normally have.

However, to run any of these methods use the call() or apply() function of array prototype object in the context of the arguments object. Here are two examples showing the same:

Hope it helps you to understand arguments a little better.

Tweet about this on TwitterShare on FacebookShare on Google+

Console API you may not have known

Tweet about this on TwitterShare on FacebookShare on Google+

Javascript console API may be a non standard API, however, it is indispensable for a web developer. You might have restricted yourself to console.log, which, for most of the times, is the only function we might want. But it could result in a bulky and messily logged screen. Console object has lots of additional useful methods, which could boost your debugging.

1. Count

This gives a count of the number of times count() has been called. You could use it to get know how many times a  function was called. Using an optional label argument, you can get the count for that label.

An example of console.count()

Using console.count() to count function calls

 

2. Group

On your developer console, you can section out related content using group function. This gives a nice indented look. You can use it to separate logs from different regions of the code.

 

Making console sections using console.group()

Making console sections using console.group() & console.groupEnd()

 

3. Timer

This one is particularly useful when you want to know how much time a particular piece of code is taking.

Get to know how much time it takes to execute a piece of code using console.timer()

Get to know how much time it takes to execute a piece of code using console.time()

 

4. CSS

Using “%c”, you can add CSS styles to console.

Style your logs with %c

Style your logs with %c

5. Stack Trace

At times, tracing your path through is crucial. Although browsers provide a lot of useful tools do the same. You might still want to use it in places which has multiple entry points.

 

Build a stack trace using console.trace()

Build a stack trace using console.trace()

 

Try these on your favorite browsers and let me know where did you use it.

Tweet about this on TwitterShare on FacebookShare on Google+

Project: Discussion extractor from JIVE using v3 API

Tweet about this on TwitterShare on FacebookShare on Google+
Jive discussion extractor

Jive discussion extractor

I recently did a small project on Jive API, which extracts discussions marked as questions from a Jive place and downloads to user’s machine as an excel file. This has been particularly useful for people, who track questions they have posted and can filter the results on excel.

Coming to the technology behind the project. It’s an Express – NodeJS application, where in I’m using request to make REST calls to get the Jive response.

request.get(url, {
    'auth': {
        'user': cred.uname,
        'pass': cred.password
    },
    'timeout': 8000
}, function(error, response, body) {
    if (error) {
        console.log("ERROR: " + error);
        throw error;
    }
    var formattedBody = body.replace("throw 'allowIllegalResourceCall is false.';", "");
    callback(JSON.parse(formattedBody));
});

Some of the response, especially the question content, contains HTML response. To extract the text from I’m using a sweet HTML parsing library called Cheerio, this brings all of jQuery features on server side.

// Get's text from a input (just a string or html)
getHTMLText: function(input) {
    if (!!input) {
        $ = cheerio.load(input);
        return $.root().text();
    }
},

Finally to get the response into excel, there is an excellent utility called excel-export, this allows you to put formatted data to excel as well as style your excel file using the styles.xml (In this case, I’ve not used it).

/**
 * Excel creation logic
 */
generateExcel: function(req, res) {
    /**
     * Excel Creation
     */
    var conf = {};
 
    // Excel Headers
    conf.cols = [{
        caption: 'Subject',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            return util.getHTMLText(cellData);
        },
        width: 70
    }, {
        caption: 'Description',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            return util.getHTMLText(cellData);
        },
        width: 70
    }, {
        caption: 'Reply Count',
        type: 'number',
        width: 15
    }, {
        caption: 'Status',
        type: 'string',
        width: 15
    }, {
        caption: 'Resolved',
        type: 'string',
        width: 15
    }, {
        caption: 'Updated Date',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            var date = new Date(cellData);
            return date.toLocaleDateString()
        },
        width: 30
    }, {
        caption: 'Tags',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            if (cellData) {
                return cellData;
            } else {
                return "";
            }
        },
        width: 60
    }, {
        caption: 'Question Author',
        type: 'string',
        width: 30
    }, {
        caption: 'Answer Description',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            if (cellData) {
                return util.getHTMLText(cellData);
            } else {
                return "";
            }
        },
        width: 70
    }, {
        caption: 'Answer Updated Date',
        type: 'string',
        beforeCellWrite: function(row, cellData) {
            if (cellData) {
                var date = new Date(cellData);
                return date.toLocaleDateString()
            } else {
                return "";
            }
        },
        width: 30
    }, {
        caption: 'Answer Author',
        type: 'string',
        width: 30
    }];
 
    // Excel Rows
    conf.rows = [];
 
    orc_resp.forEach(function(item) {
        if (item.answer) {
            conf.rows.push([item.subject, item.description, item.replyCount, item.status, item.resolved, item.updatedDate, item.tags, item.questionAuthor, item.answer.description, item.answer.updatedDate, item.answer.answerAuthor]);
        } else {
            conf.rows.push([item.subject, item.description, item.replyCount, item.status, item.resolved, item.updatedDate, item.tags, item.questionAuthor, "", "", ""]);
        }
    });
 
    conf.rows = util.filterPrimitiveFromArray(conf.rows);
 
    var result = nodeExcel.execute(conf);
    res.setHeader('Content-Type', 'application/vnd.openxmlformats');
    res.setHeader("Content-Disposition", "attachment; filename=" + "Discusssions.xlsx");
    res.end(result, 'binary');
}

The code is available to download at: https://github.com/ShivrajRath/JiveDiscussionQsExtractor

Tweet about this on TwitterShare on FacebookShare on Google+

Cross domain communication using postMessage and local storage

Tweet about this on TwitterShare on FacebookShare on Google+

There could be scenarios like having an iFrame from sister application, which is hosted on a different domain within a host application. If data needs to be passed between these applications and server side way is ruled out, then here’s a safe way to do so entirely on client side.

AT HOST

window.postMessage API is safest way to conduct cross-origin communication. It is always recommended to give the targeted domain, which can receive the message. If you don’t want to mention it, “*” would apply to all.

/**
 * Post message to the other window and restricted to some domain
 * @param  {[type]} win    [Other window]
 * @param  {[type]} msg    [Message to be sent]
 * @param  {[type]} domain [Targeted domain]
 */
function postCrossDomainMessage(win, msg, domain) {
    if (domain) {
        win.postMessage(msg, domain);
    } else {
        win.postMessage(msg, "*");
    }
}

I’d suggest the message which is posted, should be in a particular format for the target. In this example all the messages which we’ll send would be a serialized JSON.

/**
 * This creates a message in a suitable format for reading at other window
 * @return {[string]} [Message to be sent]
 */
function createMessage(key, msg) {
    return "{\"postedmessage\":{\""+key+"\":\""+msg+"\"}}";
}

Now, the target domain, which our host want’s to communicate can be a iFrame or a pop-up window. In either case, we’d need the window object of the target. For example sake I’ve considered an iFrame to be our target window here. This is how we’d post the message:

/**
 * Initiating a message
 */
var win = document.getElementById('ifr').contentWindow;
var msg = createMessage("localstoragekey", "this is some random localstoragevalue " + Math.random().toString(36).substring(7));
postCrossDomainMessage(win, msg);

One key thing to note here is the message should be passed to the target window only once the window (here iFrame) has completely finished loading.

AT TARGET

postMessage fires a “message” event on the target. The event.data property contains the data sent by the host. To keep the message persisted on to the target domain, we’d put the message against the key, which we had set at the host.

var PERMITTED_DOMAIN = "http://example.com";
 
/**
 * Receiving message from other domain
 */
window.addEventListener('message', function(event) {
	if (event.origin === PERMITTED_DOMAIN) {
        var msg = JSON.parse(event.data).postedmessage;
        var msgKey = Object.keys(msg)[0];
        localStorage.setItem(msgKey, msg[msgKey]);
    }
});

Again it is adviced to use event.origin to permit only allowed domains. This will avoid cross site scripting hacks.

One final thing, which is optional is to write local storage event handlers. This event would let the target domain open in other window/tab about the local storage changes.

/**
 * Local storage event capture to detect changes
 */
window.addEventListener('storage', function(event) {
	if (event.key === 'localstoragekey') {
		console.log(localStorage.getItem(event.key));
		//doSomething
	}
}, false);
Tweet about this on TwitterShare on FacebookShare on Google+

Local storage service for AngularJS

Tweet about this on TwitterShare on FacebookShare on Google+

I loved the concept of Angular services. It helps in writing cleaner code, which can be shared across the app.

We use local storage a lot these days and there are plenty of wrapper around local storage. I wrote this wrapper in form of angular service. It provides a bit improved way to access the APIs.

Tweet about this on TwitterShare on FacebookShare on Google+