Friday, 10 June 2016

Partially rendering Handlerbars from Backbone view

handlebars_logo
While working on a project I had this situation where I wanted to render a view partially after some ajax is done. In this post I will explain how to render HandlerBar views partially. For the purpose of demonstrate I will simulate delay using setTimeout() function instead of an ajax request. So for an example lets consider following setup 1. Template

2. Backbone Model
var PersonModel = Backbone.Model.extend({
    defaults: {
        firstName: 'Bharat',
        lastName: 'Patil',
        website: ''
    }
});
3. Backbone view using Handlerbars view
var TestView = Backbone.View.extend({
    //assign model view instance
    model: objPerson,

    //get the template
    template: Handlebars.compile( $('#PersonTemplate').html() ),

    //container element
    el: '#test',

    render: function(){
        var that = this;
     var html = this.template(this.model.toJSON());
        this.$el.html(html);

        //partial rendering
        setTimeout(function(){
            //set value to model
            that.model.set('website', 'http://www.digitoffee.com');

            //again render template
            html = that.template(that.model.toJSON());

            //selector to find and put content
            var selector = "#divPartial";
            that.$el.find(selector).replaceWith($(selector, html));

        },3000);
    }
});
4. Container in which view will be rendered
To make it easier to understand model has already been set up with the default values. Now lets go step by step to understand what exactly happens
var html = this.template(this.model.toJSON());
Above line will render your complete view and as we don't know the website of that user, there will be no link displayed in the view.
that.model.set('website', 'http://www.digitoffee.com');
Lets pretend after doing ajax now we know the website of user and our model is populated with the value
html = that.template(that.model.toJSON());
Now to update our view render template again with updated model
var selector = "#divPartial";
If you see template you can find a div with an id divPartial
that.$el.find(selector).replaceWith($(selector, html));
This is the juicy line. If you know jQuery very well you will be able to understand this quickly. What we are doing here is finding divPartial in current rendered element and replacing its content by finding the same div inside newly rendered template passing as a 2nd argument to jQuery function. jQuery function takes 2 parameters of which 2nd parameter is doing magic here by finding whats inside newly rendered template which is in html variable in step 3. If you find it difficult to understand please comment below. I have also created a jsfiddle for this which is as below

Step by step Cordova calabash-ios automation

Step by step guide about how to integrate calabash-ios with Cordova in an automated way without opening Apple Xcode.
calabash-ios-cordova
Note: First try steps given on https://github.com/calabash/calabash-ios.
If those steps aren’t working for you then try following steps. For me only manual steps given on above link worked.
Also this script doesn’t create separate target same as “calabsh-ios setup” command.

I also presume that you have already setup your cordova project and nodejs.
  1. sudo gem install calabash-cucumber If you get any error then try using following command
    sudo ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future gem install calabash-cucumber
    reference
  2. Go inside your Cordova project directory npm install xcode
    npm install fs-extra
    npm install underscore
  3. Download script “cordova-calabash-ios.js” from here and paste it inside your cordova project at www level (not inside www).
    (Note: This is very primitive script you can modify it according to your need. Let me know also know when you modify it. I will update your link here)
  4. Downlaod calabsh.framework.

    You may want to modify path to calabash.framework inside above downloaded script. I have added calabash.framework in https://github.com/bharatpatil/cordova-calabash-ios however it is good if you get updated version.
  5. cordova platform add ios
    if not already added.
  6. node cordova-calabash-ios.js
  7. cordova compile ios
  8. APP_BUNDLE_PATH=”platforms/ios/build/emulator/Your ProjectName.app” DEVICE_TARGET=’iPad – Simulator – iOS 7.0′ DEVICE=”ipad” POST_START_BREAK=0 calabash-ios console

    You should be seeing something like
    Running irb…
    irb(main):001:0>
  9. start_test_server_in_background

    This will attempt to start iOS simulator and your app. Wait until it starts simulator and your app.
  10. query(“webView”)

    In output of above command you should be able to see string containing “class” => “UIWebView”.
    Further you can go through https://github.com/calabash/calabash-ios/wiki/06-WebView-Support
If you have any issues please comment below.

DataSync PhoneGap/Web applications using LocalStorage

Offline / Online Data Sync

Recently I have developed a PhoneGap application in which I wanted to synchronize data with server. In this post we will see a simple method to send data from PhoneGap application / Web application using LocalStorage as a queue.
Conditions were like below:
  • Store data in queue locally in LocalStorage
  • Sync data with server if online
  • when application comes online it should start syncing the data again if any
  • upon successful sync remove from queue else try again
  • synching one item at a time
I have developed this solution using Backbone and Backbone LocalStorage plugin.

Lets start understanding the solution.

1. Backbone Model
var QueueModel = Backbone.Model.extend({
  defaults:{
    'url': null,
    'method': null //http method like GET, PUT, POST etc.
  }
});
This model is nothing but representation of ajax settings that can be found here.
2. Backbone Collection used as a Queue which is using Backbone.LocalStorage plugin. You should use singleton pattern for following backbone class.
var SyncQueue = Backbone.Collection.extend({
  
  model: QueueModel,
  
  currentModel: null, 
  
  timeOutVar: null,
  
  localStorage: new Backbone.LocalStorage(QUEUE_NAME),
  
  initialize: function() {
    setSelf(this);
  },
  
  setSyncTimer: function(milliSeconds) {
    milliSeconds = typeof milliSeconds !== 'undefined' ? milliSeconds : 5000;
    if(self.timeOutVar) { clearTimeout(self.timeOutVar); }
    setTimeout(self.startSync, milliSeconds);
  },
  
  //add model into queue 
  enqueue: function (model) {
    self.localStorage.create(model);
    self.setSyncTimer(1000);    
  },  

  //when syncing is done
  syncSuccess: function () {
    self.localStorage.destroy(self.currentModel);
    self.currentModel = null;
    self.setSyncTimer(1000);
  },
  
  //when error occurred while syncing
  syncError: function () {
    self.currentModel = null;
    setTimeout(self.startSync, 1000);
  },
  
  //sync init method
  startSync: function () {
    console.log('startSync '+ 'models length: ' + self.models.length);
    self.localStorage = new Backbone.LocalStorage(QUEUE_NAME);
    self.fetch();   
    if (self.models.length > 0 && self.currentModel === null) {
      self.currentModel = self.models[0];
      self.send();
    }
  },
  
  send: function() {   
    var ajaxJSON = self.currentModel.toJSON();
    $.ajax(ajaxJSON)
    .done(function(){
      self.syncSuccess();
    })
    .fail(function(){
      self.syncError();
    });
  }
});

Understanding above Backbone Collection

model: QueueModel = Set Backbone collection model
currentModel: null = currentModel being synced
timeOutVar: null = holds reference to timeout id
  enqueue: function (model) {
    self.localStorage.create(model);
    self.setSyncTimer(1000);    
  },  
Above function will add ajax settings model in the queue. As I said earlier this is essentially jquery ajax settings like url, method, contentType, dataType etc.
  syncSuccess: function () {
    self.localStorage.destroy(self.currentModel);
    self.currentModel = null;
    self.setSyncTimer(1000);
  },
Success callback after ajax is successful. It will remove currentModel from queue and will start synching method again.
  syncError: function () {
    self.currentModel = null;
    setTimeout(self.startSync, 1000);
  },
Error callback when ajax is unsuccessful. It will again try to sync the same model again.
  startSync: function () {
    console.log('startSync '+ 'models length: ' + self.models.length);
    self.localStorage = new Backbone.LocalStorage(QUEUE_NAME);
    self.fetch();   
    if (self.models.length > 0 && self.currentModel === null) {
      self.currentModel = self.models[0];
      self.send();
    }
  }
Above is the function which will fetch collection from localStorage and it will try to sync first model from queue.
  send: function() {   
    var ajaxJSON = self.currentModel.toJSON();
    $.ajax(ajaxJSON)
    .done(function(){
      self.syncSuccess();
    })
    .fail(function(){
      self.syncError();
    });
  }
This function will execute ajax on currentModel and will call respective callback function.
I am using above code as is in one of my application which is currently in beta mode. Improvement to above synching code can be done. If you have any suggestions please let me know.
You can find demo of above code at http://jsfiddle.net/bharatpatil/EeNH2/3/

Wednesday, 19 February 2014

How to get local time from UTC using Moment.JS


Moment.JS is a beautiful javascript library for parsing, validating, manipulating, and formatting dates. This is a must have utility library when it comes to manipulating timestamps and dates in javascript.

Here I will show how to get local time if you have a utc date time string.

Lets say you have a UTC date-time string as 2014-02-19 05:24:32 AM and you want to determine time in your timezone then use following code:
 moment.utc('2014-02-19 05:24:32 AM').toDate();

toDate() method gives javascript Date() object.

Below I have shared an example of how to use it. You can click on JavaScript link below to see the code.

Sunday, 16 February 2014

Measure the height of keyboard on PhoneGap app using jQuery


 I have been working on a PhoneGap project where I wanted  to scroll the content up and down whenever keyboard  appears and disappears.

 After a bit of searching here and there, I found out that  whenever keyboard appears window's resize event if fired.

 So to determine height of keyboard do the following steps

 1. Inside device ready event store original window height  inside a window variable

 window.height = $(window).height();


2. Now on window resize event execute a callback function

 $(window).resize(function(){
    window.currentHeight = $(this).height();
    window.heightDiff = window.height - window.currentHeight;
 });


So whenever there is focus on an input element, window's resize event will be triggered which will execute above function and we will have the height of keyboard inside window.heightDiff variable.

Putting it all together
 function onDeviceReady() {
   window.height = $(window).height();
   $(window).resize(function(){
    window.currentHeight = $(this).height();
    window.heightDiff = window.height - window.currentHeight;
  });
 }