Thursday, 19 July 2012

Node js: TypeError: Cannot read property 'prototype' of undefined at Object. (/http.js:49:35)

So I'm deploying my node app to the OpenStack framework using AppFog, but unfortunately even if you supply a package.json specifying your dependencies, you still need to manually copy over the files from your .npm directory
TypeError: Cannot read property 'prototype' of undefined at Object. (/http.js:49:35)

So I started copying over the dependencies manually, ie.


tchan@tommy:~/repo/afbirthday$ cp -a ~/.npm/cssom/0.2.4/package node_modules/cssom


I got to copying over express and its dependencies, and I had two versions of connect I could choose from. Naturally I chose the latest one, which turned out to be a bad idea when I tried to deploy the app.

I searched through forums, and eventually I came across a niffy feature of npm, which allows you to see the dependent versions of your dependencies.

npm ls

You will then see what version of connect is required by express. Turns out I used the newer version, which was causing issues.

Lesson of the day...use npm ls to see what versions your dependencies are before copying shiet over!

Monday, 16 July 2012

Node and ampq plugin: /amqp/amqp.js:1229 this.channels[channel] = exchange; ^ TypeError: Cannot set property '1' of undefined

This is the error I got initially:



 /home/repo/404hound/node_modules/amqp/amqp.js:1229 
  this.channels[channel] = exchange;
              ^
 TypeError: Cannot set property '1' of undefined  


The solution is to wait until the connection is ready before invoking any start functions:




   var conn = createConnection(); 
   conn.on('ready', function () {
     conn.exchange(config.exchangeName, function (exchange) {
       console.log("Starting...");
       conn.queue(config.queueName, {durable:true, exclusive:true},
         function (q) {
           q.bind(config.exchangeName, '#'); //subscribe to all messages.
           q.subscribe(function (msg) {
             console.log(msg);
           });
         });
     });
   });  



Saturday, 14 July 2012

Problems with Express js 3.x and EJS for node

So I upgraded to the latest version of Express, and to my dismay, they dropped support by the register() method in favor of the engine() method. Furthermore, they dropped partial view rendering (among others), which means one needs another plugin to restore the old functionality.

My solution:

 app.engine('.html', 

   require('ejs-locals') 

 );  

Saving to package.json and installing a node plugin in one step

I just found this from someone on Github:

$ npm install  --save
(--save automatically writes to your package.json file, tell your friends)
Pretty cool!

Using Node and RabbitMQ step-by-step tutorial

I spend a few hours today trying to configure the messaging part of my app using Rabbitmq on node js. I wanted to make sure it can be deployed to CloudFoundry. Anyways here is the finished module:



 var amqp = require('amqp'); 

 function rabbitUrl() { 

   if (process.env.VCAP_SERVICES) { 

     conf = JSON.parse(process.env.VCAP_SERVICES); 

     return conf['rabbitmq-2.4'][0].credentials.url; 

   } 

   else { 

     return "amqp://guest:@localhost";  

   } 

 } 



 var config = { 

   exchangeName:'404hound', 

   queueName:'ping.job' 

 }; 

 function init() { 

   var conn = createConnection(); 

   conn.on('ready', function () { 

     console.log("Starting..."); 

     conn.queue(config.queueName, {durable:true, exclusive:true}, 

       function (q) { 

         q.bind(config.exchangeName, '#'); //subscribe to all messages. 

         q.subscribe(function (msg) { 

           console.log(msg); 

         }); 

       }); 

   }); 

 } 

 function publish(msg, conn) { 

   if (conn === undefined) { 

     conn = createConnection(); 

   } 

   conn.on('ready', function () { 

     console.log("Sending message..."); 

     conn.publish(config.queueName, {body:msg}); 

   }); 

 } 

 function createConnection() { 

   return amqp.createConnection({url:rabbitUrl()}, {defaultExchangeName:config.exchangeName}); 

 } 

 module.exports.init = init; 

 module.exports.publish = publish; 

 module.exports.createConnection = createConnection;  


The first function defines the url value. Notice that we are saying if it's defined by CloudFoundry, then we use it...otherwise we use our local config.

We then define an init() function that will create the connection with the exchange it we want. After that we wait until the connection is ready. Once it's ready we can then bind it to the messages we want to read. A '#' means we want to subscribe to all messages. Then we define what should happen when a message comes in. In this simply case we just log it.

The second part of this is the publish function. There are times where we don't want to create a connection for each message we're sending, so we can opt to pass in the connection. Again it's simple as publishing to the queue you want to send to.

Here's some sample output:


 Starting... 

 Sending message... 

 { body: 'hello' }  


Notice my code above differs from the sample code from CloudFoundry...after reading the ampq plugin for Node I realized that the guys at CF are using a deprecated way to sending/receiving messages.

Note #1: You will need to create your exchange on RabbitMQ first. In my case I created the exchange 404hound. You can also use the ampq plugin to create the exchange.

Unable to remove the tipsy tooltip plugin with using the fallback option

So I am using the tipsy tooltip plugin to alert a user that the form input in invalid if a XHR request returns false. Now I wanted to add the error text dynamically, so I used the 'fallback' option of the tipsy config, which looks like this:


   self.showTipsy = function() { 

     $('#keywords').tipsy({gravity: 'w', fallback: "Whoops. Did not find matching keywords."}); 

   };  

This is what the manual said if I want to remove it:
Tipsy tooltips are 'live' - if the source attribute's value changes, the tooltip text will be updated the next time the tooltip is shown. There's one caveat - if you wish to remove the tooltip by setting the title attribute to an empty string, set theoriginal-title attribute instead (this only applies if you're using the title attribute).
Unfortunately though, when I tried that it did not work. I also try to try to hide the tipsy as mention also in the manual. Still no luck. I did find a solution for it after doing a search on google:


   self.hideTipsy = function() { 

     $("#keywords").unbind('mouseenter mouseleave'); //workaround 

   }  

Hope that helps someone!

Wednesday, 4 July 2012

Knockout binding doesn't work when using jquery $.load() method

So I encountered a problem today with knockout binding apparently not working when I load it via ajax using the $.load() method. I had the content loaded into a modal body, and the html content had data-bind elements in it, like so:




    <form id="create-form" class="form-horizontal"> 

     <fieldset> 

      <div class="control-group success"> 

       <label class="control-label">Email address</label> 

       <div class="controls"> 

        <span class="input-xlarge uneditable-input"><%= email %></span> 

       </div> 

      </div> 

      </div> 

     </fieldset> 

    </form>  



This is my js file that comes with it:




 ko.applyBindings(new CreatePageViewModel()); 

 function CreatePageViewModel() { 

   var self = this; 

   self.fetchContents = function() { 

     alert('hello'); 

   } 

 }  


Everything should work right? Wrong. Because we have already loaded the knockout library previously and it was activated, we need to specify the context in which to apply bindings, like so:



 ko.applyBindings(new CreatePageViewModel(), document.getElementById('create-form')); 

 function CreatePageViewModel() { 

   var self = this; 

   self.fetchContents = function() { 

     alert('hello'); 

   } 

 }