0 Comments

The Problem

Recently, at work, we ran into an issue where a particular package update (angular-bootstrap) broke one of our crucial features.  Apparently, as mentioned here: https://github.com/angular-ui/bootstrap/wiki/Migration-guide-for-prefixes, the newer version (since 0.14.0) requires the directive selector to be prefixed with “uib-“. 

Potential Solutions

So, there are some solutions / options here:

Option 1

Completely fall back to version 0.13.4 to avoid the prefixing.

Advantage: there is very little new code that depends on the newer version where everything is prefixed with “uib-“.  So there is really minimal rework to be done to fix this issue.

Disadvantage: This locks any new development on the same project to version 0.13.4 and if anything new added afterward, we will not be able to take advantage of that.

Option 2

Upgrade the crucial feature to the latest version (i.e. 1.3.3).

Advantage: If anything new implemented in the package, we can take advantage of it.   Latest and greatest, yes!

Disadvantage: You are basically on the upgrade train forever.  Tons of rework and retesting to make sure that legacy code is always working going forward.

Option 3

Somehow allow multiple version of the library to be used side-by-side

Advantage: No major rework need to be done on the crucial feature.  It can stay happy at version 0.13.4.  New custom components / features can be on a newer version of the library (i.e. 1.3.3).  Good isolation.

Disadvantage: Eh…. *thinking*… *more thinking*…. nothing… (Well this is not true, we will still need to retouch the crucial feature where we are importing this component since the alias will change in the require / import statements)

Option 3 is definitely the clear winner here, but the question is … HOW?

So, I’ve looked at the different package managers that come to mind, which are:

  1. NPM
  2. JSPM
  3. Webpack

Webpack

Well, let’s rule Webpack out since it’s not really a package manager.  I have to admit I’m not a Webpack user, but looking around the web, I found this article: http://ilikekillnerds.com/2015/07/jspm-vs-webpack/ which basically tell me straight out that basically, and I am quoting here, “It actually offers almost everything that Jspm does except it is not a package  manager”.  Then again this article is pretty old (in JavaScript timeframe, LOL), so things might have changed now.  If anyone know any different, let me know…

So that leaves me with only NPM and JSPM.

JSPM

Now, at work, we are already using JSPM, so this becomes the first choice for me to investigate.  And from my investigation (which is not much…), basically, I ran jspm help on the console and Ouila! I came across this line: install jquery=…     Hmm… that looks like aliasing to me, so I gave it a try.  Created a test folder, ran jspm init, and then ran jspm install angular-bootstrap0134=angular-bootstrap@0.13.4 and then again jspm install angular-bootstrap133=angular-bootstrap@1.3.3.  And… guess what?  It FREAKING works!!! YAY!!

In package.json I saw:

"jspm": {
  "dependencies": {
    "angular-bootsrap133": "github:angular-ui/bootstrap-bower@1.3.3",
    "angular-bootstrap0134": "github:angular-ui/bootstrap-bower@0.13.4",

Similarly, in system.js config file:

map: {
    "angular-bootsrap133": "github:angular-ui/bootstrap-bower@1.3.3",
    "angular-bootstrap0134": "github:angular-ui/bootstrap-bower@0.13.4",

Therefore, now where I need the older version I can just require(“angular-bootstrap133”) or in ES2015 syntax: import “angular-bootstrap133”

PERFECT! Problem solved.

So…

NPM

Just to be complete, I tried to figure out how to do this using plain vanilla NPM… 

I looked around on the web and I found this article which is pretty old and it looks a bit promising: http://blog.izs.me/post/1675072029/10-cool-things-you-probably-didnt-realize-npm, especially the big bold section titled 1:Handle multiple versions of the same thing at the same time.

Looked through npm help install documentation as well, but there is nothing there that tell me how to do this…

So, I tried by running npm install angular-ui-bootstrap@0.13.4 --save and that net me a node_module/angular_ui_bootstrap folder and the following lines in package.json:

"dependencies": {
   "angular-ui-bootstrap": "^0.13.4",

Then I tried again using npm install angular-ui-bootstrap@1.3.3 --save, and as expected, it basically override the node_module/angular_ui_bootstrap folder with the newest version and the dependencies line for it is also updated to:

"dependencies": {
    "angular-ui-bootstrap": "^1.3.3",

This is DEFINITELY NOT what I want.  So searching further on the web, net me no solution to this.  There are discussions around this topic such as this GitHub issue: https://github.com/npm/npm/issues/5499, which looks like this is still not possible using NPM  and http://stackoverflow.com/questions/26414587/how-to-install-multiple-versions-of-package-using-npm  which again point to JSPM for something like this.  Also found a google group message (couldn’t find it again) that basically tell you to install the old version, copy it to a folder like angular-ui-bootstrap0134 and install it again so it will override the original folder with version 1.3.3.  Very very messy.   I guess a different approach is to create your own copy of npm package for the different versions and use those instead… again not very good solution.

Conclusion

And so… the clear winner here is… JSPM.  Lucky us… we already use JSPM at work Smile.

0 Comments

Well, maybe not the best, but it comes very close to it.  For sure, it's the FUNNEST time you can have while trying to understand jQuery internal and at the same time learn about some exotic things about JavaScript and browser DOM.

What I am talking about is the More Things I Learned from the jQuery Source videos by Paul Irish.

Trust me... If you are a JavaScript / jQuery geek, it is definitely worth the time to look at them.

Paul is quite a fun guy to watch and his explanation style kind of remind me of how Head First book series are written.

Fun, Fun, Fun.

http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/

http://paulirish.com/2011/11-more-things-i-learned-from-the-jquery-source/

0 Comments

Bumped into this a while back, but haven’t got a chance to use it so I sort of forgot about it.  It’s been floating around in the back of my mind.  I found this one pattern to be quite clever in helping with JavaScript function optimizations, especially when doing browser specific code and some other code that might only require a one time hit and sort of cache the result in the function afterward.

The code is as follow:

function A() {    
    //Do some initial calculation of some sort...    
    var returnValue = GetValueFromWebService("...");

    //Rewrite A to actually return the calculated returnValue    
    //and stop going to the web service ever again    
    //In essence, caching the inital returnValue for subsequent calls    
    A = function()  {
        return returnValue;   
    };

    return A();
}

Very neat

0 Comments

I am not sure if this is of any use or not.  While playing around with trying to find a more elegant syntax for my LINQ-like querying code, I accidentally bumped into this topic.

Say... I want to be able to write something like:

var peoples = [ ... ]; 

function from() {
    // do something with the arguments passed here...
} 

from (a, in, peoples)

This will never work since "a" is undefined and "in" is a JavaScript keyword.  What I wanted to do is cache the arguments that were passed to the "from" function into a local buffer so I can do something with it later inside the function.

There are several problems here that are related to JavaScript global object.

Problem 1: 'a' is undefined will be thrown when the "from" function is called.  Now, how can we possibly remedy this?  Well, we can declare "a" as a global variable and assigned something to it (does not matter what), but that's kind of weird.  Is it possible to inject "a" into global on the fly?  Well, yes, somewhat.  You can use try and catch block and detect the "'a" is undefined" error that was thrown and have the catch block inject the missing variable as a global variable.

Example:

try {
    from(a, inside, people);
} catch(e) {
    var m = e.message.match(/^'(.+)' is undefined$/);
    if  (m) {
        this[m[1]] = {};
    }
}

Well, this will inject variable 'a' into the global object (this). If you need a proof for this, just output 'a' somewhere after the above code. (i.e. WScript.Echo(a)). Unfortunately, this route does not take me to where I want since once the error is caught the function will never complete the call anyway.  Hmm...

Problem 2: Ignoring the 'in' Syntax error, the second thing that bugs me is how to get the function parameter variable name (in this example, I want to be able to get the name of the people object (which is "people").  So, how can you reflect over JavaScript global object to get this value?

After a little experimentation, I finally found the answer.  Take a look at the code below:

function GetGlobalObjectName(aGlobalMember) {
    var global = this; //when the function is called as a function, "this" will point to global object
    for (var object in global) {
        if (global[object] === aGlobalMember) {
           return object;
         }
    }
    return null;
}

now I can modify my "from" function as follow:

function from() {
    for (var x = 0, a = arguments, k = a.length; x < k; x++) {
        var v = a[x];
        if (typeof(v) === "object") {
           WScript.Echo(GetGlobalObjectName(v);
        }
    }
}

Now I can pass any object to my "from" function and if it detects that the argument type is "object" it will get the name of that object as defined in the global.  Afterward I can use that name string to do whatever I want.  In this example, perhaps use it to construct dynamic JavaScript statement from all the arguments being passed and do an eval() on it.

Hmm... with all these problems, I doubt I can get the syntax structure to anywhere close to C# LINQ... alternatively, mixing string into the function call might work, but that's just messy Sad smile.

from("a", "in", people)

Hmm... frankly I like the current syntax that I have, minus the orderby array part that is still in string.

from(people)
    .where(function(n) { n.Age > 19 && n.Age < 31) })
    .select(function(n) { return { FullName : n.FirstName + " " + n.LastName }; });

To me that seems a little bit a elegant than mixing string substitutions into the function argument. 

I don't anticipate that I'll get anywhere far with this in regard of finding a more elegant way to write my query syntax, but this is sure is one fun trip into JavaScript internals.  I learnt something new today Smile .  It's all good.

0 Comments

Just coding for coding sake, I decided to try implement a LINQ-like query in JavaScript.  And the result is as follow:

(function() {
    'use strict';
    
/**
 * Javascript LINQ-like query proof of concept
 * Jimmy Chandra - 16 July 2007
 * Updated on 2015-02-22
 */
 
/*
 * Quicksort implementation for JavaScript Array (based on 
 * http://en.literateprograms.org/Quicksort_(JavaScript)),
 * modified to pass a function delegate for the comparison function.
 */
Array.prototype.swap = function(i, j) {
    var a = this, 
        t = a[i];
    a[i] = a[j];
    a[j] = t;
};
 
function partition(a, s, e, p, l) {
    var v = a[p],
        t = s,
        i;
    a.swap(p, e - 1);
    for (i = s; i < e - 1; i++) {
        if (l(a[i], v)) {
            a.swap(t, i);
            t++;
        }
    }
    a.swap(e - 1, t);
    return t;
}
 
function qsort(a, s, e, l) {
    var p;
    if (e - 1 > s) {
        p = s + Math.floor((e - s) / 2);        
        p = partition(a, s, e, p, l);
         
        qsort(a, s, p, l);
        qsort(a, p + 1, e, l);
    }
}
 
Array.prototype.quicksort = function (l) {
    qsort(this, 0, this.length, l);
};
 
 
/*
 * JavaScript LINQ-like query engine sample implementation
 */
function _each(o, l, a) {
    var r = [],
        m = o.length,
        i;
         
    if (l) {
        for (i = 0; i < m; i++) {
            if (l(o[i])) {
                a(r, o, i);
            }
        }
    } else {
        for (i = 0; i < m; i++) {
            a(r, o, i);
        }
    }
    return r;   
}
  
function from(o) {
    return new From(o);
}
 
function From(o) {
    /*jshint validthis: true */
    this.items = o; 
}
  
From.prototype.where = function(l) {
    return new Where(
        _each(this.items, l, 
            function(r, o, i) {
                r.push(o[i]);
            }));
};
  
function _select(l) {
    /*jshint validthis: true */
    return _each(this.items, l, 
        function(r, o, i) {
            r.push(l(o[i]));
        });
}
  
From.prototype.select = _select;
 
function Where(o) {
    /*jshint validthis: true */
    this.items = o;
}
  
Where.prototype.select = _select;
Where.prototype.orderby = function(a) {
    var f, 
        k = a.length,
        r = _each(this.items, null,
        function(r, o, i) {
            r.push(o[i]);
        });
     
    if (k === 1 && a[0] === "") {
        f = function(i, j) { return i <= j; };
    } else {
        f = function(i, j) {
            var l = "", 
                r = "";
            for (var n = 0; n < k; n++) {
                l += i[a[n]];
                r += j[a[n]];
            }
            return l <= r;
        };
    }
     
    r.quicksort(f);
     
    return new Orderby(r);
};
  
function Orderby(o) {
    /*jshint validthis: true */
    this.items = o;
}
 
Orderby.prototype.select = _select;
  
/*
 * Javascript LINQ-like querying example
 */
 
var numbers = [17, 6, 12, 14, 20, 13, 10];
  
var b = 
    from (numbers).
    where (function(n) { return n > 9 && n < 20; }).
    orderby ([ "" ]).
    select (function(n) { return n; });
     
 
for (var x = 0, l = b.length; x < l; x++) {
    console.log(b[x]);
}
 
 
var peoples = [ 
    { FirstName : "John", LastName : "Doe", Age : 29 },
    { FirstName : "Jane", LastName : "Doe", Age : 33 },
    { FirstName : "Mary", LastName : "White", Age : 31 },
    { FirstName : "Barry", LastName : "White", Age : 31 },
    { FirstName : "Kevin", LastName : "Black", Age : 31 },
    { FirstName : "Anna", LastName : "Smith", Age : 1 }];
     
 
var p =
    from (peoples).
    where (function(n) { return n.LastName === "Doe" || n.LastName === "White"; }).
    orderby([ "Age", "LastName", "FirstName" ]).
    select(function(n) { return { FullName : n.FirstName + " " + n.LastName, Age : n.Age }; });
     
 
for (x = 0, l = p.length; x < l; x++) {
    console.log(p[x].FullName + ":" + p[x].Age);
}
}());

Run it on jsfiddle: http://jsfiddle.net/jchandra/6ugyxc2s/

Fun :)