Monday, 4 August 2014

Nicer JavaScript inArray

so I'm presently using the fantastic Stormpath for user management for some work I'm doing for the equally fantastic HopeUK... I'm getting to play with nodejs and as such I'm rediscovering all those lovely things about JavaScript I've missed having to develop for IE6 and so resort to jQuery - don't get me wrong: I love jQuery... but after a couple of years developing for old and busted browsers it's nice to get back to bleeding-edge vanilla JavaScript. One of the joys of jQuery is it's $.inArray() function as it just works!

I needed to a method to discover whether or not a user had access to a specific route within the application... let's call it the "/Educators" route. Stormpath lets me query the user's Groups so I so that and get an object back from their API which has an array of "items" (not the actual result):

{
    "user": "User Name",
    "something": "else",
    "items": [
        {
            "name": "Educators",
            "something": "else"
        },
        {
            "name": "Administrators",
            "something": "else"
        },
        {
            "name": "Funders",
            "something": "else"
        }
    ]
}

Initially I wrote a lovely function taking two variables (the groups array and the group name I was interested in) it initialized a return value to false then iterated over the items array and if the array item name equaled the group name set the return value to true - at the end of the loop the return value was returned. Dead simple, ehh? You can imagine how it looks even I'll bet?

Then I got to thinking about the map() function available in JavaScript and thought that that must be a better approach so I took the original array and fed it to map to produce and array like this (all within the console of Chrome as it seems like the best place to test JavaScript sometimes):

var d = {
    "user": "User Name",
    "something": "else",
    "items": [
        {
            "name": "Educators",
            "something": "else"
        },
        {
            "name": "Administrators",
            "something": "else"
        },
        {
            "name": "Funders",
            "something": "else"
        }
    ]
};
var e = d.items.map(function(item){return item.name});
console.log(e);
["Educators", "Administrators", "Funders"]

So to test I simply did something like this if(e.indexOf("Educators")) !== -1)

But I got to thinking more, especially about truthy falsy, and I clocked the bitwise NOT operator. Now I could do some simple tests like this:

if(~d.items.map(function(item){return item.name}).indexOf("Educators")){
    console.log("true");
}else{
    console.log("false");
}
if(~d.items.map(function(item){return item.name}).indexOf("Fred")){
    console.log("true");
}else{
    console.log("false");
}
if(~d.items.map(function(item){return item.name}).indexOf("Funders")){
    console.log("true");
}else{
    console.log("false");
}
true
false
true

So from a clunky function we get a nice one-liner! I'm really rather pleased with it.

Of course, all that there playing within the console doesn't help with my Codeivate score does it?