Deals

Tuesday, September 2, 2014

Showing Multiple Routes on Map with Google Direction Services

Recently in one of our project we have to show routes between two points on map. Those two points can be on same way or can be on different ways. So there were multiple routes. There are ways to do that with Google direction service. One way is that you set way points while plotting routes on the map. But in our case points were random so that would be possible. So in this blog I am going to mention trick I have used.

For showing multiple paths we have to create separate DirectionsRenderer for each route. So first we get latitude and longitude each points in an array. For example I have 4 lat longs in an array that means there will be three paths. From point 0 to point 1, point 1 to point 2 and point 2 to point 3. So we have to create three separate requests and three separate DirectionsRenderer. You can not simply use for loop here as route API has callback functions when it receives routes. So here I have used recursion function. For example you have all the points in an array called markers.  First we will generate Google Map LatLong.

for (i = 0; i < markers.length; i++) {
      var data = markers[i];
      var myLatlng = new google.maps.LatLng(data.lat, data.lng);
      lat_lng.push(myLatlng);
}

Now we will create request for each path separately.

var requestArray = [], renderArray = [];
var cur = 0;
var service = new google.maps.DirectionsService();
for (var i = 0; i < lat_lng.length  -1; i++) {
     var request = {
  origin: lat_lng[i],
           destination: lat_lng[i+1],
   travelMode: google.maps.DirectionsTravelMode.DRIVING
     };
     requestArray.push(request);
 }

So now we have all the requests created we will start with first request.

if(requestArray.length > 0){
     service.route(requestArray[cur], directionResults);
}
   
function directionResults(result, status) {
   if (status == google.maps.DirectionsStatus.OK) {
          renderArray[cur] = new google.maps.DirectionsRenderer();
          renderArray[cur].setMap(map);
          renderArray[cur].setDirections(result);
   }
   cur++;
   if(cur < requestArray.length){
    service.route(requestArray[cur], directionResults);
   }
}

As you see in above code we have variable named cur which is initialized with zero. We start with first request. directionResults is our callback function. Inside direction function we are creating a DirectionsRenderer and setting map and result to it. After that we increase the count and go to next request. Once all the requests are completed you stop the recursion. Using this you can achieve following result.


Hope this helps you.

Monday, September 1, 2014

Sencha Touch - One Way to Implement Autosuggest Textbox

Hello,

Recently in one of our Sencha Touch project there was a requirement to add autosuggest textbox. As user starts typing there should be some suggestions and user should be able to either select one of the option or type in the value. In this blog I am going to explain the approach I used for that. Please note that there could be other ways to implement this.

First lets create a store that has the options for auto suggestions. For that here is the model definition.

Ext.define('MyApp.model.Option', {
    extend:'Ext.data.Model',
    config:{
        fields:[
            { name:'id', type:'int' },
            { name:'text', type:'string' },
        ],
        idProperty: 'id'
    }
});

Now lets create a store which holds the data.

Ext.define('MyApp.store.Option', {
  extend: 'Ext.data.Store',
  config: {
    model: 'MyApp.model.Option',
    autoLoad: true,
    proxy: {
      type: 'memory'
    },
    data : [
        {id: 1,    text: "Option 1"},
        {id: 2, text: "Option 2"},
        {id: 3, text: "Option 3"},
        {id: 4, text: "Option 4"}
    ]
  }
});

Now our approach is quite simple we will create a floating panel with list and assign this store to it and as soon as user starts typing in textbox, we will show this panel near to textbox and filter store with what is typed in textbox. So lets create a floating panel.

Ext.define('MyApp.view.Traffic.AutoSuggestPanel', {
extend: 'Ext.Panel',
xtype: 'autosuggestpanel',
config: {
modal: true,
hideOnMaskTap: true,
hidden: true,
height: '180px',
width: '94%',
layout: 'fit',
margin: '-9px 0 0 0',
items: [
{
xtype: 'list',
id: 'autoSuggestList',
itemId: 'autoSuggestList',
itemHeight: 30,
itemTpl: '<div style="font-size: 13px">{name}</div>',
store: 'Option'
}
]
}
});

We will add this panel to viewport when app launches, as you see it's hidden initially so it will not be visible.

Ext.Viewport.add(Ext.create('MyApp.view.Traffic.AutoSuggestPanel'));

Now lets add keyup event to textfield on which we want to show this suggestions. Also we will add our floating panel as reference to controller.

 config: {
        refs: {
              autoSuggestPanel: 'autosuggestpanel'
              autoSuggestList: '#autoSuggestList',
              autoSuggestTextField: '#autoSuggestTextField'
       }
}

autoSuggestTextField: {
            keyup: 'onAutoSuggestTextFieldKeyUp'
            },
autoSuggestList: {
            itemtap: 'onAutoSuggestListItemTap'
            },

And define it's handler in controller.

onAutoSuggestTextFieldKeyUp: function(text){
        if( this.getAutoSuggestPanel().isHidden( ) ) {
            this. getAutoSuggestPanel().showBy(text,'bc-tc' );
        }

        Ext.getStore('Option').clearFilter();
        Ext.getStore('Option').filter('text',text.getValue());
}


Above code will show auto suggest list next to textfield. Now we have to add itemtap event for the list and set it's value in textbox. Here is handler for it.

onAutoSuggestListItemTap: function(list, index, target, record){
        var name = record.get('text');
this. getAutoSuggestPanel().hide();

       this.getAutoSuggestTextField().setValue(name);
}

That's it and you have autosuggest textbox ready.

Tuesday, August 12, 2014

Sencha Touch List Set Dynamic Height

Hello,

Recently in one of my project, there was a requirement to create a list which has items of different height and we have to set height of the list as per number of items. For example one item has height 80 pixel and other two items have height 100 pixel so list height should be set to 280 pixels. In this blog I will explain how to do this.

As we all now list needs a container with fit or card layout so inside that list can be scrollable based on number of items While in our case we have to make complete panel scrollable along with list so we have to list height as per number of items. For that there is one simple way if items height is fixed. For example if item height is 20 pixel and list has 10 items you can set list height to 200 so all the items would be visible. But in case you have variable heights in items you can use following approach. We will loop through each items in the list and get item element client height. Add it together and set list height to sum of all the item heights.

For example we have list with following config

{
      xtype: 'list',
      itemId: 'myList',
      id: 'myList',
      scrollable: false,
      itemHeight: 80,
      store: 'myStore',
      itemTpl: '<div>{longOrShortText}</div>'
}

And we have added reference in controller.

myList : '#myList'

Now in controller when your store is loaded you can add following logic

var totalHeight = 0;
var items = this.getMyList().getViewItems();
var itemsLn = items.length;
for (i = 0; i < itemsLn; i++) {
     item = items[i];
     totalHeight = totalHeight + item.element.dom.clientHeight;
}
this.getMyList().setHeight(totalHeight);

So here we are looping through all the items, find out item client height and add it together and set list height. Hope this helps you.

Monday, June 23, 2014

How to Access $scope Variable Outside AngularJs Controller

Recently I was working with AngularJs and there was a requirement to call a AngularJs controller function forcefully from other events.  So for that we have to access $scope variable of a controller. This short blog is about accessing $scope variable.

In AngularJs all the scopes are bound to DOM so to access $scope first we have to get the HTML element. You can either use jQuery selectors to get elements or you can use standard document.getElementById method. For example.

var scope= angular.element($(".classselector")[0]).scope();

This gives you the scope of the the element. Once you have the scope you can call respective method of controller.  There is also other way to find out the scope if you don't have reference to element. You can find scope by name of controller.

var scope = angular.element($('[ng-controller=myController]')).scope();

After you make changes to variables of scope you have to call apply method so the AngularJs framework is notified about changes.

scope.$apply();

Hope this helps you.


Saturday, June 21, 2014

AngularJs Communicate Between Directives and Controllers

Hello,

Recently in one of my project we were using AngularJs and created a directive for timepicker where user can enter timer in hh:mm AM/PM format. Now on one of the HTML form we have a button. When the button is clicked we have to disable the input for the timepicker. For that we have to access scope of directive from scope of AngularJs controller so that se can disable the respective field. In this blog I am going to explain how to do this.

AngularJs allows you to create directives with isolated scope which has some binding to parent scope. Bindings are defined by specifying attributes in HTML.  In some cases it may not be good as it's hard to synchronize both the scopes. So ideally parent and directive scope should be maintained separately. Better way to communicate between directives and controllers is through directive attributes. Let's see and example.  I have defined my HTML as follow for my timepicker directive.

<timepicker is-not-open="notOpen" hour-step="1" minute-step="30" show-meridian="true"></timepicker>

As you can see above is-not-open is the attribute defined for directive and it is bind to notOpen variable in my controller.

$scope.notOpen = false;

Now lets see how to mention attribute in directive scope.

angular.module('ui.bootstrap.timepicker', [])
.directive('timepicker', ['timepickerConfig', function (timepickerConfig) {
  return {
    restrict: 'EA',
    require:'?^ngModel',
    replace: true,
    scope: { isNotOpen: "=" },
    templateUrl: 'template/timepicker/timepicker.html',
    link: function(scope, element, attrs, ngModel) {
     
    }
  };
}]);

As you can see in above code we have defined attribute with scope: { isNotOpen: "=" }. Now you can define a function to watch this variable in directives. For example there is a method in parent controller which sets notOpen variable to true.

$scope.setNotOpenStatus = function(){
      $scope.notOpen = true;
}

Once it is set here, the directive is notified about the change and as I mentioned you can keep watch on the attribute.

scope.$watch('isNotOpen', function (newValue, oldValue) {
          if(newValue == true){
              //do something
          }
});

Same way you can have watch function in parent controller which would be notified if attribute value is changed inside directive.

Hope this helps you.

Tuesday, June 3, 2014

Introduction to Swift - the latest programming language from Apple

So Apple stunned all the developers around the globe by introducing new language instead of new iPhones, iPhones or iWatches. Let's see what exactly is the Swift.



Apple says the following about the release of Swift:

"Swift is a powerful new programming language for iOS and OS X® that makes it easier than ever for developers to create incredible apps. Designed for Cocoa® and Cocoa Touch®, Swift combines the performance and efficiency of compiled languages with the simplicity and interactivity of popular scripting languages. By design, Swift helps developers write safer and more reliable code by eliminating entire categories of common programming errors, and coexists with Objective-C® code, so developers can easily integrate Swift into their existing apps. Xcode® Playgrounds make writing Swift code incredibly interactive by instantly displaying the output of Swift code."

Swift code can live right besides C and Objective-C code in the same app. The syntax is quite similar to JavaScript. Here are some of the features of it.


  • Closures (similar to blocks in C and Objective-C) unified with function pointers
  • Tuples and multiple return values
  • Generics
  • Fast and concise iteration over a range or collection
  • Structs that support methods, extensions, protocols.
  • Functional programming patterns, e.g.: map and filter

Here is the first lesson of Swift. How to define a variable and a constant. Constants and variables must be defined before they are used. You can define constants with let keyword and variable with var keyword. For example

let maximumLoginAttemptsAllowed = 10
var currentLoginAttempt = 0

So here is a constant maximumLoginAttemptsAllowed which has a value 10 and a variable currentLoginAttempt which has value 0. 

Saturday, May 31, 2014

Sencha Touch Create Navigation Drawer (Slide Navigation Like Gmail)

Recently in one of our sencha touch project we have created Navigation Drawer for sencha touch. In this blog I will explain how to create it.

Let's first understand what is navigation drawer. We are all familiar with Facebook slide navigation. It has button on top left corner of toolbar, when you tap on it, the content in center slide to right and menu opens with left to right animation. When you again tap on that menu is closed with right to left navigation and center content slides to left. Navigation drawer is introduced in Android 4.0. It's  slight variation of slide menu. Here the center content does not slide left or right but the menu comes on top of slide content. However the top toolbar is still accessible so user can still close the menu. Now lets see how to create this in sencha touch. Please note that this is the one way we used to create navigation drawer, there could be other options as well.

First lets create a list which will act as navigation menu.

Ext.define('SlideNav.view.Navigation', {
    extend: 'Ext.List',
    xtype: 'navigation',
    modal: true,
    hideOnMaskTap: false,
    requires : ['Ext.data.Store'],
    config: {
        width: 250,
        itemTpl : '{title}',
        data : [
            {
                title : 'Item 1'
            },
            {
                title : 'Item 2'
            },
            {
                title : 'Item 3'
            }
        ]
    }
});

As you can see in above code we created a list and set it as modal element with modal config. List extends Ext.container so we can open it as modal element. This is our navigation menu. Now lets add a button on top left corner of our toolbar and create the main view.

Ext.define('SlideNav.view.Main', {
    extend: 'Ext.Container',
    xtype: 'main',
    config: {
        style: {
            zIndex: -1,
            position: 'absolute'
        },
        layout:{
            type: 'card',
            align: 'stretch'
        },
        items: [
            {
                xtype: 'toolbar',
                docked: 'top',
                title: 'Slide Navigation',
                items: [
                    {
                        xtype: 'button',
                        iconCls: 'list',
                        ui: 'plain',
                        itemId: 'slideNavBtn',
                        id: 'slideNavBtn'
                    }
                ]
            },
            {
                xtype: 'panel',
                itemId: 'slideContainer',
                layout: 'card',
                id: 'slideContainer',
                items: [
                    {
                        xtype: 'panel',
                        html: 'Hello Welcome to The Design Shop.Sencha Touch is very good framework.'
                    }
                ]
            }
        ]
    }
});

So this is our main view and it has toolbar with top navigation button. Now lets add tap event for it in controller and add logic to open and close the menu.

Ext.define('SlideNav.controller.App',{
    extend: 'Ext.app.Controller',
    config:{
        refs:{
            main : 'main',
            navigation : 'navigation',
            navBtn : '#slideNavBtn'
        },
        control : {
            navBtn : {
                tap : 'toggleNav'
            }
        }
    },
    init: function() {
        this.toggle = 0;
    },
    toggleNav : function(){
        var me = this;
        if(!me.getNavigation()) {
            Ext.create('SlideNav.view.Navigation');
            Ext.Viewport.add(me.getNavigation());
            me.getNavigation().show();
        }
        if(this.toggle == 0) {
            Ext.Animator.run({
                        element: me.getNavigation().element,
                        duration: 500,
                        easing: 'ease-in',
                        preserveEndState: true,
                        from: {
                            left: -250
                        },
                        to: {
                           left: 0
                        }
        });
        this.toggle = 1;
        }
        else {
        Ext.Animator.run({
                            element: me.getNavigation().element,
duration: 500,
easing: 'ease-in',
preserveEndState: true,
from: {
left: 0
},
to: {
left: -250
}
});
            this.toggle = 0;
        }
    }
});

As you can see in above code we are using one controller variable toggle to know the state of menu and and on tap of it first we create the navigation and menu and add it to viewport and then we are using Ext.Animator to open it with animation. So basically we are setting left property from -250 to 0 as 250 is the width of the menu. You can change it according to your requirement or set dynamic width here.