Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Friday, January 5, 2018

When JSON has URLs but you need data (or how to chain API calls and merging the result)

The Problem

Let's say you have an API (ie. http://api.example.org/stuffs) that returns an array of stuff. But the API dev who worked on it, the bastard that he is, decided that certain fields, like say price is a hyperlink. So it looks like:

[{
   "id": "exde01"
   "name": "Stuff1",
   "type": "just stuff",
   "weight": "3.22",
   "price": "http://api.example.org/price/exde01"
},
{
   "id": "exde02"
   "name": "Stuff2",
   "type": "just stuff",
   "weight": "3.25",
   "price": "http://api.example.org/price/exde02"
}
.....
]

Ok. Now when you do an API call to the price url you'd get something like:

{
   "inlu_price": 69.96
   "exlu_tax": 49.99,
   "price": 123.25
}

So now the problem is how do we loop over the first JSON result with stuff and calling each price URL and then appending back the result. Essentially, we want the end result to look like this:

[{
   "id": "exde01"
   "name": "Stuff1",
   "type": "just stuff",
   "weight": "3.22",
   "price": {
     "inlu_price": 69.96
     "exlu_tax": 49.99,
     "price": 123.25
   }
},
{
   "id": "exde02"
   "name": "Stuff2",
   "type": "just stuff",
   "weight": "3.25",
   "price": {
     "inlu_price": 69.96
     "exlu_tax": 49.99,
     "price": 123.25
   }
}
.....
]

The Solution

My solution is in TypeScript and if it wasn't for reactive extensions (or streams) I'd probably have hanged myself. 

The first step is to get the main JSON. So I wrote a service for it.

    getAllStuff(): Observable {
        const url = "http://api.example.org/stuffs";

        return this.http.get(url}).map((response) => response.json());
    }

Now for the tricky part.

   this.restService.getAllStuff().switchMap((stuffs) => {
      return Observable.forJoin(stuffs.map((s) => {
         return this.http.get(s.price).map((res) => {
            s.price = res;
            return s;
         }
      }
   })
   .subscribe((r) => {
      console.log(JSON.stringify(r));
   });

This looks hard but it isn't really once you understand how it "flows".

First the getAllStuff() call will return the first set of results (technically, an Observable array) which we pass in into the forJoin() function.

What forJoin() does it take an array of API calls (as Observables) and spits out a single "merged" result. That's where the stuffs.map() does. But take note this is a two step process.

If you just focus on just the stuffs.map() . You can access stuff JSON array and drill down to the s.price, ie. ['http://api.example.org/price/exde01', 'http://api.example.org/price/exde02'].

This is why then we do a return with the this.http.get() function to produce that array forJoin() needs. ForJoin() then resolves these calls. After resolving, the result is passed back up to the switchMap() function which we can then subscribe to get the transformed JSON.

There we get our desired JSON result albeit with a bit of processing.

Now, if there's a 2nd URL in your main json, then you'll just need another switchMap(). You can chain multiple switchMaps().

References:

  • http://blog.danieleghidoli.it/2016/10/22/http-rxjs-observables-angular/
  • https://www.learnrxjs.io/operators/transformation/switchmap.html
  • https://stackoverflow.com/questions/38517552/angular-2-chained-http-get-requests-with-iterable-array

Monday, July 18, 2016

Typescript is what JavaScript should have been

When Brendan Eich added JavaScript to the Netscape browser some 20 years ago, he had roughly a month to do it and, context-wise, JavaScript was added to the Netscape browser as a reaction to the popularity of Java - applets - at that time.

JavaScript was something you could use to interact with the browser via small programs and scripts - think sub 1k lines of code. Unfortunately, that's no longer the situation. It has become common to see 1 million lines JavaScript projects. Projects of this size are unmanageable:

1. Tooling is bad - barely there intellisense, unsafe or no refactoring

2. Development flow sucks - you can't check for common errors until you refresh the page

3. JS Code bases of these sizes are hard to reason about for many reasons like duck typing especially if you got code with bad or lazy naming conventions

This is where Typescript comes in.

1. TypeScript's static typing and annotations are great for catching errors on the tool rather than waiting for a page refresh

2. Code is easier to reason about; example, function params are known if you're using interfaces

3. TypeScript allows safe refactoring and good intellisense support

4. Although from Microsoft, TypeScript is open source with a clear roadmap with rapid releases - typically 3-4 months

But Typescript is not without faults.

1. TypeScript is superset of JavaScript. So any valid JavaScript is also valid TypeScript. In that case, if you write crappy JavaScript, you still get crappy TypeScript. Somewhat fixed if you read and apply Douglas Crockford's advice in his seminal book, JavaScript: The Good Parts

2. Typings. Sort of an edge case problem because some javascript libraries don't have typings thus we don't have intellisense for that library

The good stuff out-weights the bad parts for me. Typescript is what JavaScript should have been.

Wednesday, May 11, 2016

Being stupid while calling Twitter's Search API

A few days ago, I just figured out how to authenticate my Ionic app using Twitter's application-only Oauth. Application only authentication allows you call Twitter APIs without that Twitter login screen.

The being stupid part started when I tried using the Search API.

    var twitterStreamURL = "https://api.twitter.com/1.1/search/tweets.json?q="; 
    var qValue = "queryString";
    var numberOfTweets = "&count=10";

It should be easy to see that to call the Search API you'll concatinate the qValue (or query string) and the numberOfTweets (number of tweets to get) to the twitterStreamURL. You'd do then a ajax call then get the resulting JSON.
    
    var cURL = "https://api.twitter.com/1.1/search/tweets.json?q=" + qvalue + numberOfTweets; 

These would be no problem with the query string had only one value or no special characters. This stumped me a bit because I used escape() function at first which I knew about. It still works but the escape() function is deprecated. Which lead me to encodeURI(). It worked until it was asked to search for strings with hash tags. I didn't read the fine print for encodeURI which said it doesn't encode certain special characters. This finally lead me to the encodeURIComponent() function.
    
    var cURL = "https://api.twitter.com/1.1/search/tweets.json?q=" + encodeURIComponent(qvalue) + numberOfTweets; 

The moral of this story is I need read the fine print.

Friday, April 8, 2016

Ionic, Satellizer, Facebook and that "Given URL is not allowed" error

You can have your Ionic mobile application use Facebook authentication. You can do it the hard way - i.e. do it yourself via $http calls - or go the easy route via Satellizer. Being the lazy bastard that I am, I'll be using Satellizer.

Satellizer can be setup quickly, do bower install, add the needed JavaScript bits to your index.html and reference it in you Ionic app.

angular.module('meAwesomeIonicApp', ['ionic', 'ngCordova', 'satellizer', 'ngAnimate']).config(...)

From here you'll need to go to Facebook Developer and register your app. You'll then add the FB application appId to your satellizer settings. It should look something like:

    var commonConfig = {
        popupOptions: {
            location: 'no',
            toolbar: 'yes',
            width: window.screen.width,
            height: window.screen.height
        }
    };

    if (ionic.Platform.isIOS() || ionic.Platform.isAndroid()) {
        commonConfig.redirectUri = 'http://localhost/';
        $authProvider.platform = 'mobile'
    }

    $authProvider.facebook(angular.extend({}, commonConfig, {
        clientId: 'YOUR FB APP ID HERE',
        url: 'http://localhost:3000/auth/facebook',
        responseType: 'token'
    }));

This moves us to the controllers. In the controllers we have access to a $auth service which is provided by Satellizer. The $auth service then provides a authenticate(string) function. So we have:
 
$auth.authenticate(provider)
        .then(function() {n
             // Success login
        })
        .catch(function(response) {
             // Error in login
        });
};

You can easily add this to a ng-click handler. And this is where we encounter the "Given URL is not allowed" error. What's happening is that when we call $auth.authenticate(), it will try to open a FB login page based on the url value we configured in the $authProvider.facebook() call instead we get the error page instead of the login form.

Fortunately, for me the fix was easy. I just didn't configure the settings in the FB developer app page correctly. It isn't enough to just configure the Basic Section in the Settings page. You need to open the Advance Section and also configure the Valid OAuth redirect URIs values also. So if you add the http://localhost value in the textfield, it should fix the "Given URL is not allowed" error.

Saturday, December 12, 2015

Angular Charts and the "undefined" draw error on single series line charts

I've been recently working with Ionic and my app needed a chart. Also, been listening to way too much Tricot and Toe.

This chart requirement lead me to angular-chart which is based on the excellent chart.js library. My use case was simple. I needed a line chart to visualize various "single" series data. And this is where I encountered this "undefined" draw (and update) functions.

For context, this how my data looked.

{
   id: 0,
   labels: ['13:00', '13:15', '13:30', '13:45', '14:00', '14:15', '14:30', '14:45'],
   series: ['Stat #1'],
   data: [28, 30, 29, 32, 70, 79, 89, 98 ]
}

The important part here is the data array. This was the one causing the problem after I traced it to a closed issue in github. To fix this was to just turn the flat data array into a 2-dimensional array and poof the error is gone.

{
   id: 0,
   labels: ['13:00', '13:15', '13:30', '13:45', '14:00', '14:15', '14:30', '14:45'],
   series: ['Stat #1'],
   data: [[28, 30, 29, 32, 70, 79, 89, 98 ]]
}

I can now see my chart.

Tuesday, September 29, 2015

Wat!? HTML is now an application framework? I'm calling bullshit!

You wish it was bullshit, but no. HTML, since HTML5 has provided full-blown component-oriented solutions. Stuff like the Shadow DOM specs, media-queries, validation and error handling are just the tip of this iceburg. New stuff is being added to HTML everyday.

A good example I can give is the way how text (or code) completion is done in HTML5 - let's say a "browser" list textbox. The old way of doing this would be a choke-full of JavaScript. We can use a datalist tag element instead.

<input type="text" name="browserSelect" 
    list="browserList"/> 

<datalist id="browserList">  
   <option value="IE">  
   <option value="Firefox">  
   <option value="Chrome">  
   <option value="Opera">  
   <option value="Safari">  
</datalist>  

Of course, you could further refined this with a dash of JavaScript like say Angular or Knockout.

Now if only companies drop IE6 or IE8. zzzzzz.

Friday, September 4, 2015

AngularJS and the case of "but I don't want to rewrite my event listeners." (also I have directives)

Well, damn. Shit son.....

Calling event listener functions outside of AngularJS is not that hard. There might be a "strong" discussion on how to do this but that's a matter of style. That is a whole other bowl of soup.

We can fix this in a jiffy and we just have to keep in mind that Angular elements are accessible via JQLite.

We start with our directive to which we will then attached a listener function.

// app.js
angular.module('myApp', [])
   .directive('myDirective', function myDirective () {
        return {
            restrict: 'AEC',
            link: myDirectiveLink
        }
   });

function myDirectiveLink (scope, element, attrs) {
    var someDOMElement = element[0];
    someDOMElement.addEventListener("click", myDirectiveEventListener, false);
}

function myDirectiveEventListener () {
    // Handle the event here
   // This could be an existing listener somewhere in a different source file
}

Now all we need is to declare 'myDirective' in a valid DOM element in our view. It will respond to a click event that will be handled by the 'myDirectiveEventListener' function.

Monday, May 4, 2015

Bootstrapping the View Parts

Time to add a face to our project. So, we break out our favorite framework for the designed-impaired programmer, Bootstrap!

Download the stuff and put it in the public/ folder. I made a bootstrap folder in my public folder to keep it organize. Don't forgot to also get jquery. Bootstrap doesn't work without jquery. This is the easy part.

The next part is kinda hit or miss: Jade

Nodejs with Express uses a templating engine to make views. There are a couple of options but jade is the default. I say hit or miss is because some take to Jade like ducklings to water. Some of you might not be ducklings. 

Here's a sample:

nav(class='navbar navbar-default navbar-static-top')
    .container
        .navbar-header
            button(type='button', class='navbar-toggle collapsed', data-toggle='collapse',                    data-target='#navbar', aria-expanded='false', aria-controls='navbar')
                span(class='sr-only') Toggle navigation
                span(class='icon-bar')
                span(class='icon-bar')
                span(class='icon-bar')
            a(class='navbar-brand', href='#')= title
        div(id='navbar',class='navbar-collapse collapse')
            ul.nav.navbar-nav
                li.active
                    a(href='#') Home
                li
                    a(href='#') About
                li
                    a(href='#') Contact

Jade templating language is quite terse to write compared to raw HTML. It also has a few fun parts like includes, conditionals and mixins.

In the Views/ folder, I made a shared folder and move the common stuff like the layout and navbars. This way I can compose the view like lego bricks AND that's where the fun starts.

Clone the repo at Github.

Saturday, April 18, 2015

Finish the REST (Part 2) with Fiddler debugging and testing

We are doing three things for this part: (1) finish coding the REST api (2) Debug with Fiddler (3) Write Frisby test against our API.

Finishing the REST api is the easy part. Make a folder with the path api/v1/ inside the routes folder. Inside the api folder is another folder called v1. I do this just out of habit. APIs will change in even in a production environments. When that happens, I just add a v2 folder. It's just a cheap and easy way to future proof REST API endpoints.

After the folders, create a posts.js file inside.

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');

// Get the model
var post = mongoose.model('Post');

// GET /api/v1/posts - GET ALL
router.get('/', function (req, res) {
    post.find({}, function (err, posts) {
        res.json(posts);
    });
});

// GET /api/v1/posts/:post_id
router.get('/:post_id', function(req, res) {
    post.findById(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        res.json(post);
    });
});

// POST /api/v1/posts
router.post('/', function(req, res) {
    var newPost = new Post();
    newPost.title = req.body.title;
    newPost.body = req.body.body;
    newPost.author = req.body.author;
    newPost.published = req.body.published;

    newPost.save(function(err) {
        if (err) res.send(err);
        res.json({ message: 'Post created!' });
    });
});

// PUT /api/v1/posts
router.put('/', function(req, res) {
    post.findById(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        post.title = req.body.title;
        post.body = req.body.body;
        post.author = req.body.author;
        post.published = req.body.published;
        post.meta.favs = req.body.favs;
        post.meta.dvotes = req.body.dvotes;
        post.meta.uvotes = req.body.uvotes;

        post.save(function(err) {
            if (err) res.send(err);

            res.json({ message: 'Post updated' });
        });
    });
});

// DELETE /api/v1/posts/:post_id
router.delete('/:post_id', function(req, res) { 
    post.findByIdAndRemove(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        res.json({ message: 'Post deleted!' });
    });
});

module.exports = router;

The whole thing should be fairly easy to figure out since this is the actual CRUD stuff.

Run the project and we should see our web page. Now we move to Fiddler to see around our API. Remember, you can just Postman instead of fiddler.

Start here: The Composer Tab in Fiddler
After you've open Fiddler, just go to the composer tab and add the API url you're interested in. Don't forget the HTTP verb. Press the Execute button on the top right to see the results.

You'll be able to go to the other tabs to see a lot of information.

The Inspectors tab contents is what we are interested in. This is where we see what's inside the reply from our API (or lack thereof if that is what we are expecting).

And finally, tests for our REST API endpoints. I wanted to add tests for our API to ensure behavior and for regression. It just makes sure I don't break the API as we continue working on this little project of ours.

We will be using the Frisby framework. Frisby is made to test REST API on node.js projects.

So, we install Frisby. Open a terminal, navigate to the project folder and type in:

npm install -g --save frisby

That should install the latest frisby version and save it a dependency in our package.json file. When frisby installed, create a folder named spec and inside that another folder named api. Inside these folders, a javascript file named posts_spec.js.

var frisby = require('frisby');
var baseURL = 'http://localhost:1337/'; // just replace if on live server

frisby.create('Status 200 for GET /api/v1/posts is returned')
    .get(baseURL + 'api/v1/posts')
    .expectStatus(200)
    .toss();

frisby.create('Status 200 for GET /api/v1/posts/:id')
    .get(baseURL + 'api/v1/posts/5525f1e3f6a7f3a00b234a09')
    .expectStatus(200)
    .expectJSON({ 'author': 'jaypax' })
    .toss();


Here we have two tests. Feel free to add more.

Now we just need to run it for which we need jasmine-node.

npm install -g --save jasmine-node

After NPM is done, you should be able to run the command in your terminal: jasmine-code spec/api/


Friby results after running the test 
By the way, you need the project to be running in order to run the test.

You basically have two terminals open: 1 terminal running the project and other terminal to run the test from.

Clone the code at the github repo.

Wednesday, April 15, 2015

Coding the REST services (Part 1) - The model

Coding up the REST services part is similar to coding up the CRUD parts for you traditional desktop application. The difference is quite subtle because you'll be also dealing with HTTP verbs - POST, GET, PUT, DELETE. We are going to make the data model first so we have something to interact with.

First step is creating a connection. In our case, we are connecting to MongoLab, so in your app.js file you add the following:

// our libs
var mongoose = require('mongoose');
var uriUtil = require('mongodb-uri');

// our connection function
var connectToMongoLab = function () {
    var username = process.env.MongolabUsername;     // external var for our username
    var password = process.env.MongoLabPassword;     // same for the password

    var mongolabUri = "mongodb://" + username + ":" + password + "@ds035448.mongolab.com:35448/dbhaxspace";
    var mongooseUri = uriUtil.formatMongoose(mongolabUri);
    var options = {
        server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
        replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
    };
    mongoose.connect(mongooseUri, options);  // connect us to the db with these options
};

connectToMongoLab(); 

mongoose.connection.on('error', console.log);   // if error in connecting to db, dump errmsg to console
mongoose.connection.on('disconnected', connectToMongoLab); // if disconnected just reconnect

// load models
fs.readdirSync(__dirname + "/models").forEach(function(file) {
    if (~file.indexOf('.js')) require(__dirname + '/models/' + file);
});

This should be added before the routes portions. Now for the actual model.

We're using Mongoose to model our data. Think Entity Framework if you're a C# guy, Hibernate (or JPA) if Java and SQLAlchemy for the python guys. (No, PHP gets not love. #Dealwithit)

Create a folder called Model and create a new javascript file in that folder. In our project, our model is called post and it's declared in the post.js file.

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var PostSchema = new Schema({
    title: { type: String, default: '' },
    author: { type: String, default: '' },
    body: String,
    published: Boolean,
    date: { type: Date, default: Date.now },
    geoloc: {
        latitude: { type: Number, default: 0 },
        longitude: { type: Number, default: 0 },
        label: { type: String, default: ''} 
    },
    meta: {
        uvotes: { type: Number, default: 0 },
        dvotes: { type: Number, default: 0 },
        favs: { type: Number, default: 0 }
    }
});
// methods
PostSchema.method({
    findAll : function(cb) {
        return this.model('Post').find({}, cb);
    }  
});
// statics
PostSchema.static({

});
// register
mongoose.model('Post', PostSchema, 'posts');

Mongoose schema's have some pretty nifty features like types, methods and statics that can be part of the model. The whole thing then wraps up when you call the mongoose.model() function to register the model.

Once we have our model registered. We can then call our model into any part of the app.

var mongoose = require('mongoose');
// Get the model
var post = mongoose.model('Post');

We will pick this up on part 2 where I actually show you the REST parts.

Friday, April 3, 2015

Dude bro, JavaScript's bound functions are stupid

Too many times I've come upon this comment or question, "What happen to 'this'?" If you haven't caught on JavaScript is a fucked up language. It has quirks that you have to work around. One of these is it's JavaScript's Scope behavior which is the root of "What happen this to 'this'?".

Let's take a simple example from Java.

public class Person {
    public String fname;
    public String lname;
    public String getFullName() {
        return this.fname + " " + this.lname;
    }
}

In this case, the getFullname method is bound to each instance of a Person object so when I say:

Person dude = new Person();
dude.fname = "Jay";
dude.lname = "Pax";
dude.getFullName(); // returns "Jay Pax"

I know that this in the getFullname() refers to dude. The binding of this in which I'm running getFullName() is dude, a specific instance of Person.

In JavaScript , functions don't behave like this. They don't have bound methods. In fact, they can be unbound and rebound at the coder's whim.

For example, if I have:

var getFullName = function(){
    return this.fname + " " + this.lname;
}

There is no obvious context that this should refer to.
So now let's go a step futher and say I wrote something like this:

function foo(){
    return this.fname + " " + this.lname;
}
var getFullName = foo;

That's not much different. We don't know what this is referring to exactly. So getFullName still doesn't have a clearly-defined this binding.

So let's give it one:

var dude = {
    fname: "Jay",
    lname: "Pax",
    getFullName: function(){ 
        return this.fname+ " " + this.lname;
    }
};
dude.getFullName(); // returns "Jay Pax"

Well now! That's starting to make sense. Until you do something like this:

var doAThing = dude.getFullName;
doAThing(); // returns "undefined undefined"

Waaaaattttt......

You see, when I pointed the variable doAThing at dude.getFullName, I pointed it a the function of getFullName NOT the object dude. So we lost the this binding in the process.

I know it's fucked up but it's fixable you'll have to use Function.bind.

Sunday, March 29, 2015

My summer 2015 MEAN project: Dormmetita

Dormmetita. That's the name of the app we are building.

I asked a question over at the CDO-ITG FB page a couple of weeks ago what would the community like to read or do over the summer. I had a couple of options for Java, Node and Python. The overall winner though was nodejs. So for the summer I'm doing a MEAN tutorial to build an old app that a couple of guys "brainstormed" about a year back named Dormmetita. Right, +Romar Mayer Micabalo+Paul Michael Labis+Raven Duran?

Technically it's "Dorm me, tita." which is an app to find and post dorm rooms, apartments for students localized to my city, Cagayan de Oro which is a university town. We might throw in reviews but let's keep it simple for now. We can make up stuff as we go.

 I've broken down the tutorial in these topics:
  1. Setting up 
  2. Node is up: hello world
  3. Coding the REST services (Part 1) - The Model
  4. Finish the REST (Part 2) with Fiddler debugging and testing
  5. Bootstrapping the view parts 
  6. Add Angular to the page
  7. Deploy to Azure, because free is nice

So bookmark this post to follow. 

Monday, May 26, 2014

SoundManager2, jquery, angular and the Hotline Miami OST - Part 1

Sound Manager 2
I haven't written anything in the last 30 days. I've been a busy and lazy (among other things). But I had to write these things down before I forget again. I'm planning to do this in 2 parts so it won't be that long to read.

Sound Manager 2
Sound Manager 2 is this JavaScript library simplify playing audio on a web page. Think embedded players like SoundCloud and such. It's pretty nifty with fail-over support for Mp3 via Flash if you somehow have a retarded web browser who can't play an HTML5 audio tag. The whole point is you end up with a single API to use to play audio files IF only it didn't have a few gotchas.

The SM2 Gotchas that got me in the ass
  • Read the requirements page closely. Don't do what I did and dove straight into the API and got hung up on a few issues (some Flash crap and arbitrary seeking) which could have been resolved quite easily and quickly if I have READ THE FUCKING REQUIREMENT'S PAGE a bit more closely. 
  • Variable Bitrate (VBR) MP3s bad, Constant Bitrate (CBR) MP3s good
  • HTTP 206 Header (Partial Content). If you are like me and got a soup nazi for web administrator, use curl or Fiddler and test your Apache because it might be turned off. We don't want a "No soup for you" incident.
Using SM2 and turning it into a Jquery plugin
SM2 can easily be used with Jquery and turn it into a plugin. The challenging parts are deciding on how to deal with the settings (and there are a lot of SM2 settings) and how to handle the sound objects.

For the setting, I decided to go with sensible defaults that can be overridden and use jquery's $.extend function to merge it. It more or less looks like:
// default settings
var settings = {
    autoplay: false,
    loop: false,
    playNextOnFinish: true,
    hideTrackDetailsAfterPlay: false, /* N (Number) seconds, or false (Boolean) to always show it */
    soundManagerMultiShot: false, /* let sounds "restart" or "chorus" when played multiple times..*/
    soundManagerStream: true,  /* allows playing before entire file has loaded (recommended) */
    soundManagerSwfURL: 'swf/', /* path (String), relative to your html page */
    soundManagerFlashVersion: 9,
    soundManagerDebug: false, /* displays the SM2 debug info into the page and in the console */
    soundManagerHandleFlashBlock: true,
    soundManagerPreferFlash: false,
    soundManagerHTML5Audio: true,
    soundManagerFlashLoadTimeout: 1000
};
    .
    .
    // jquery plugin
    $.fn.smsplayer = function(options){
      if(options){
         $.extend(settings, options); // Merge options to settings
      }
      return this.each(function (){
         ....
      }
    } 

Usage therefore would look like:


As for the Sound objects, I decided to to handle them in an array.

var tracks = [],trackIDs = [];
.
.
$("#player").find('#playlist li > a').each(function(i) {
  var soundID = 'sms_sound_' + i.toString();
      $(this).addClass(soundID);
      trackIDs.push(soundID);
      var sound = soundManager.createSound({
                  id: trackIDs[trackIDs.length - 1],
                  url: $(this).attr('href'),
                  whileplaying: function() {
                    Player.prototype.updateTime(this.position, this.durationEstimate);
                  },
                  whileloading: function() {
                    Player.prototype.updateLoading(this.bytesLoaded, this.bytesTotal);
                  },
                  onfinish: function(){
                    isPlaying = false;
                    $('#playlist .playing').removeClass('playing');
                        
                    if(settings.autoplay){
                       var nextSound = Player.prototype.getNextTrackFrom(trackIDs, this.id);
                       currentTrackID = nextSound;
                       $('.' + currentTrackID).parent().addClass('playing');
                       Player.prototype.playSound(nextSound);   
                    }
                         
                  }
       });
       tracks.push(sound);

I'm going to explain the Hotline Miami OST in part 2.

Friday, November 15, 2013

When we need something more than Firebug

Us web developers in our quest to build something unique will eventually come upon a wall that looks insurmountable with our current set of debugging tools like Firebug and Chrome's or IE's developer tools. Sometimes you just need something that can work at the HTTP protocol. This is where Fiddler2 comes in. Fiddler is a web debugging proxy for any browser, system or platform. Which makes it quite handy if you're doing AJAX stuff on a lot of different platforms from Java to Node.js.

What's really special with Fiddler is the composer feature which allows to make AJAX verb (GET, DELETE, PUT, HEAD, etc.) calls to your server side API. It then allows you to look at the response headers, cookies, the raw results and a bunch of other values to help you debugged that code.

Use this with Mozilla Firefox to get the most mileage out of it since it does integrate into it quite nicely. Chrome doesn't do it because of that new rule that you can't install a plugin that's not found in the Chrome store.

It also has a nice set of add-ons which is just icing on cake. I like StresStimulus add-on which allows you to do load testing with your web apps.

Another thing is this thing is free and will run on Linux boxes (needs Mono though).

Add this to your toolbox.

Tuesday, October 15, 2013

Knockout style computed fields in AngularJS (sort of)

AngularJS has a few peculiar things. Here's a pair of them.

Suppose you have 3 input text fields - f1, f2, f3. And want you want is to have f3 a "computed" field based on what's the values on f1 and f2. Simple enough, right? Not exactly.

If you do did something like this:

<div ng-app>  
   <div ng-controller="CTRL">  
     <input type="text" ng-model="f1" />  
     <input type="text" ng-model="f2" />  
     <input type="text" value="{{total()}}" />  
     <p>{{'Angular works!'}}</p>  
   </div>  
 </div> 

And your Angular script is like this:

function CTRL ($scope) {
    $scope.f1= 3;
    $scope.f2= 4;
    $scope.total = function() {return $scope.f1 + $scope.f2;};
}

You are in for a bad time. You will notice it will work at the start but when you change the value on either f1 or f2, the total field is showing a concatenated string and not a sum. DAFUQ!  Peculiarity #1. The fix is actually pretty easy if you use a directive.

var app = angular.module('intDirective', []);

app.directive('integer', function(){
    return {
        require: 'ngModel',
        link: function(scope, ele, attr, ctrl){
            ctrl.$parsers.unshift(function(viewValue){
                return parseInt(viewValue);
            });
        }
    };
});

To use this is to add a ng-app="intDirective" property to the root div and the input tags should look like this:

<div ng-app='intDirective'>  
   <div ng-controller="CTRL">  
     <input type="text" ng-model="f1" integer/>  
     <input type="text" ng-model="f2" integer/>  
     <input type="text" value="{{total()}}" />  
     <p>{{'Angular works!'}}</p>  
   </div>  
 </div> 

OK, its looking good but try typing in a character on either f1 or f2? Yes, another thing we have do. We have to check the value being typed it is not shit (sometimes called Validation).

var app = angular.module('intDirective', []);
var INTEGER_REGEXP = /^\-?\d*$/;
app.directive('integer', function(){
    return {
        require: 'ngModel',
        link: function(scope, ele, attr, ctrl){
            ctrl.$parsers.unshift(function(viewValue){
                ctrl.$parsers.unshift(function(viewValue) {
                if (INTEGER_REGEXP.test(viewValue)) {
                   // it is valid
                   ctrl.$setValidity('integer', true);
                   return parseInt(viewValue);
                } else {
                   // it is invalid, return undefined (no model update)
                   ctrl.$setValidity('integer', false);
                   return undefined;
                }
            });
        }
    };
});

What's left is a simple $watch function to mimic Knockout computed fields (Peculiarity #2). Just add this snippet inside the controller.

    $scope.$watch(function(){
        return $scope.val1 + $scope.val2;
    }, function(newValue, oldValue){
        $scope.computed = newValue;
    });

There.

Wednesday, October 9, 2013

AngularJS with underpants

What I really meant was AngularJS with underscore but what the heck.

AngularJS as powerful as it is doesn't really have a lot utility methods and this is where underscore comes in. Underscore provides 80-odd functions that support both the usual functional suspects: map, select, invoke — as well as more specialized helpers.

To get the most of underscore with AngularJS, you have to "provide" underscore into AngularJS via a factory method:
var myapp= angular.module('underscore', []);
 myapp.factory('_', function() {
  return window._; // underscore has been loaded before this script
 }); 
With that, we can now inject underscore into our controllers:
myapp.controller("SomeCtrl",[$scope, _, function($scope, _){
    $scope.maxVal = _.max([1,2,3]); // Returns 3
});

Which leads to a couple of pretty handy stuff like checking for undefined values:
myapp.controller("SomeCtrl",[$scope, _, function($scope, _){
    if(_.isUndefined($scope.someValue){
          // do something because someValue is undefined
    }
});
Or do a search over some array using some attribute without resorting to a loop.
myapp.controller("SomeCtrl",[$scope, _, function($scope, _){
    
var data = [{model:"T", manufacturer: "Nokia"},
            {model:"S", manufacturer:"Samsung"},
            {model:"r8", manufacturer:"Cherry Mobile"},
            {model:"One", manufacturer:"HTC"}];
//Code to fetch a Cherry Mobile phone
var phone = _.where(data, {manufacturer: "Cherry Mobile"});
// phone should be [{model:"r8", manufacturer:"Cherry Mobile"}]
});
By combining these awesome frameworks, you're setting up yourself to dish out some serious can of whoop ass.

Sunday, September 29, 2013

Cold Sunday morning code

It's been interesting morning. I woke up way to early on account of the cold. A cup of coffee later, I decided to sign up and try out these free NoSQL backends which could be used for AngularJS apps. This is where I stumbled upon Mongolab.com. Mongolab is a mongodb as a service website and gives out a free 500MB account which is enough when you're trying out their stuff. But trust me when I tell you that unless your pulling 5,000 hits per month on your app that 500MB will last for a long bit.

Since I was on a roll getting free shit on the Internet, I decided to also get a github.com account. You can only ride a joke for so long, right Josan Astrid Dometita?

Amazingly, while I was trying to learn how to use the MongoLab APIs, I also found out that someone has already written an adapter for it for AngularJS.

It didn't take long to get all the stuff together. Twitter-bootstrap for my interface framework, AngularJS as my app framework, Mongolab for my backend. And since the point was to learn how to do stuff, I decided to do a simple contacts app with full CRUD features. It was easy as pie!

Here's the github repo for the code if you want to study it also: https://github.com/killertilapia/Mongolabular

Now with that done, we'll see what other stuff I can do with it. *knowing grin*

Also, I can now tag Google+ friends in my blog! SWEET! +Romar Mayer Micabalo +Paul Michael Labis +Jon Doblados +Arthur Vincent Simon +Lionel Amarado

Sunday, September 8, 2013

Parsing JSON with keys that have the at sign or @ symbol

I had to work with this interesting JSON file which had a metadata section which can be accessed with @metadata key. Here's a small sample of the JSON file:

 "twitter_handle": "..........",
 "website": ".............",
 "@metadata": {
  "Access-Control-Allow-Credentials": "true",
  "Raven-Entity-Name": "4fff7413",
  "@id": "4fff7413-f1bd-4e00-ab51-6754f1111c03",
  "Last-Modified": "2013-09-08T08:29:35.2587326Z",
  "Raven-Last-Modified": "2013-09-08T08:29:35.2587326",
  "@etag": "01000000-0000-0003-0000-000000000001",
  "Non-Authoritative-Information": false
 }

The twitter_handle or the website data are just normal JSON values so they are not that interesting but the @metadata is where it gets interesting. How do you access that?

At first I tried object.@metadata, didn't work. So I tried the next one which is object[@metadata] which also didn't work. I then found out over at StackOverflow that I was quite near. All I had to do was put single quotes so it would look like object['@metadata'].

It also works if you're trying to get a value inside, like say @id within @metadata. It would end up looking like object['@metadata']['@id'].


Monday, July 29, 2013

Overcoming the same-origin policy in AJAX/JS programming

If you are serious with AJAX (and/or JavaScript) then you probably ran into the same-origin policy. The policy is an important security concept and SHOULD NOT be turned off. But like everything else on the web, it cramps programming or limits system designs and overcoming it is a mess of kludges and dirty hacks. Enter CORS.

Cross-Origin Resource Sharing (CORS) is a specification that allows you to implement cross-domain request (ie. use an AJAX resource from another domain). The spec defines a set of headers that allow the browser and server to communicate about which request are (and are not) allowed. It isn't that hard and its supported by all browsers (it even works on IE8, which is down-right surprising).

For example, Adding CORS on an Apache server is just:

headtroll@trollmachine:/# a2enmod headers

And then to expose the header, you simply add the following to your Apache .conf file:

Header set Access-Control-Allow-Origin "*"

More details here.

As for the client side, HTML5Rocks.com already has a tutorial on how to use CORS.

Saturday, February 23, 2013

CoffeeScript and JQuery

Writing JQuery code with CoffeeScript was bit of a Challenge for me. I sort of had to unlearn my previous coding habits so not to make my CoffeeScript look like JavaScript. With me its more of a coding style problem but overall writing DOM manipulation code with CoffeeScript (with JQuery) is more pleasant that I expected. It's certainly shorter.

Let's start with the HTML doc that we will be playing with.

<html>  
   <head>  
     <title></title>  
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
     <link href="css/mystyle.css" rel="stylesheet">  
     <script src="js/jquery-1.9.1.js" type="text/javascript"></script>  
     <script src="js/Control.js" type="text/javascript"></script>  
   </head>  
   <body>  
     <div id="hoverElem">Hover over <a href="#" id="target">this</a> to show message</div>  
     <div id="message" class="hidden">I be rollin' with CoffeeScript and   
     they be hatin'!</div>  
   </body>  
 </html>   

It's quite easy to figure out what I'm trying to do here. I have a target "this" when you hover over it, it shows some kind of message.

The CSS is also quite simple.

root { 
    display: block;
}

#message{
    border: 1px solid #9966cc;
    margin: 10px;
    padding: 10px;
    text-align: center;
}

.hidden{
    display: none;
}

The real work is again done with our CoffeScript file.

$ ->
  $('#target').mouseover (e) -> $('#message').removeClass 'hidden' 
    
  $('#target').mouseout (e) -> $('#message').addClass 'hidden'

The first line "$ ->" is equivalent to the document.ready() or $.function() for JQuery. The next two lines are where the work is done. The syntax is quite compact to handle a mouseover and mouseout events. The (e) element is the event parameter. The arrow part leads to inside of the function with the removeClass and addClass methods.

The sample here is quite trivial but it does show the basics of using CoffeeScript with JQuery. A couple of more weeks (or months) of puttering around with it I think I can get pretty good with CoffeeScript and another popular JavaScript libraries like underscore, knockout or maybe gmap.

Can't wait to try this out with a real project. Let's see if Odesk got some. *grin*