Monday, June 20, 2016

Sencha Touch Data Store Tips and Tricks

Recently one my friend asked me for some help on Sencha Touch Data store and form our conversation I got an idea for this blog.

Tip 1

If you want to pass extra params to store there are two ways to do that.

1) Pass it in load method.

store.load({
            params: {
                param1 : value1
            }
        });

2) Set it as extra param.

store.getProxy().setExtraParams({
            'param1' : value1,
            'param2': value2
        });

So what's the difference between this two and when to use which.

When you have requirement to add and use params only once. Also every time store load, you want to pass different params you have to use below method.

store.load({
            params: {
                param1 : value1
            }
        });

Params added here are only added once. Next time when you call load method of store, these params are not passed. You can use it for dynamic parameters.

When you have fixed params that you have to pass every time,  a store is loaded. You have to use following method.

store.getProxy().setExtraParams({
            'param1' : value1,
            'param2': value2
        });


This will permanently add those params to the store and it will be passed every time store.load() method is called.


Tip 2

How can you add callback function for store load dynamically. Again there are two ways to do that. If you want to add and use it only once, use following method. 

store.load({
       callback: function(){
              console.log('store is loaded'); 
       }
});

But if you want to wait for store load every time you should use following logic.

store.on({
       load: function(){
              console.log('store is loaded'); 
       },
       scope: this
});

Tricks

1) To reset all the extra params in store use do the following.

store.getProxy().setExtraParams({
});

Just pass the empty object in function and it will clear all previous params.

2) Reset page param in store when using list paging.

You can use currentPage config. store.currentPage = 1

3) Get raw response from of store load.

store.getProxy().getReader().rawData

This will return you all the raw data your API has returned.

Saturday, June 18, 2016

Sencha Touch Create Dropdown Like Standard HTML Control

Recently in one of my project, we have a requirement to create dropdown like standard HTML dropdown with Sencha Touch. See the below screenshot.


As we know in Sencha Touch Selectfield (dropdown)  uses either floating panels and bottom picker to show and choose value from one. So in this blog I am going to mention how to do this. 

First of all following should be our views.

{
    xtype : 'panel',
    height: 40,
    itemId: 'monthSelector',
    id: 'monthSelector',
    style: 'background-color:#ffffff;color: #019297;border-bottom:1px solid #019297;font-size: 12px',
    html: '<div style="height:100%;width:100%;display: table;">$lt;div style="display: table-cell;vertical-align: middle;">Select Month</div><img style="position:relative;float:right;top:10px" height="20" width="20" src="resources/css/images/black-down-arrow.png"/></div>',
    listeners: {
         initialize: function( element ) {
               this.element.on({
                    tap: function( ele ){
                             MyApp.app.getController('MyController').toggleDropDown();
                    }
               });
         }
     }
},

{
xtype: 'dataview',
itemId: 'expenseMonthSelector',
id: 'expenseMonthSelector',
scrollable: false,
style: 'font-size: 12px',
height: 80,
store: {
fields: ['id', 'name','color'],
data: [
{id : 1, name: 'Current Month', color: '#9decf0'},
{id : 2, name: 'Previous Month', color: '#6cd2d6'}
]
},
itemTpl: '<div style="background-color: {color}; color:#000000;height:40px;width:100%;display: table;"><div style="display: table-cell;vertical-align: middle;padding-left: 20px">{name}</div></div>'
}

As you can see above we have one panel with layout look like a dropdown and one dataview which will act like options for the dropdown.

After this we will add our toggleDropDown function to toggle dropdown.

toggleDropDown: function(){
        if(this.getExpenseMonthSelector().isHidden() == true){
            this.getExpenseMonthSelector().show();
        }else{
            this.getExpenseMonthSelector().hide();
        }
},

Above code will simply show hide data view. Hope this helps you.

JavaScript Create Date With TimeZone

Hello,

Recently in one of my project we faced lots of issues regarding in correct dates displayed to users. The problem was TimeZone. A user is in India but he don't know that he has set timezone to USA timezone and hence we get user's device date it was showing wrong date and time.

We asked our users to fix it but as we know end users are always unpredictable they still set the timzone to USA or others and keep complaining us about dates and times.

So here is what we did to fix this issue.

Step 1 : Get User's Current Location

You can use HTML 5 GeoLocation.

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(gotUserPosition);
}

Step 2 : From the Latitude and Longitude, get user's current timezone using Google API.

function gotUserPosition(position){

     Ext.Ajax.request({
            url: 'https://maps.googleapis.com/maps/api/timezone/json?       location='+ position.coords.latitude +','+position.coords.longitude+'&timestamp='+parseInt(Date.now()/10)+'&key=YOUR_KEY',
            method: 'GET',
            disableCaching: false,
            success: function(response) {
                var result = Ext.decode(response.responseText);
                if(result.status == 'OK'){
                    localStorage.setItem('time_offset',result.rawOffset);
                    localStorage.setItem('timeZoneId',result.timeZoneId);
                }
            },
            failure: function(response) {
             
            },
            scope: this
     });

}

For this you have to create a Google API project and enable timezone API and add your key in stead of YOUR_KEY

As you can see above we are sending user's latitude and longitude to google maps api and getting the result. If result is OK. then we are saving time offset to local storage.

Now this time offset is the offset in number of seconds from UTC time. For example Indian Standard Time is ahead of UTC for 5 hours and 30 minutes. So here my offset will be 19800 seconds which is 5 hours and 30 minutes.

Now use the following logic to create date object.


var utcDate = (new Date()).toISOString();
var offsetHours = parseInt(Number(localStorage.getItem('time_offset'))/60/60);
var offsetMinutes = parseInt(Number(localStorage.getItem('time_offset'))/60%60);

var currentDate = new Date(Date.UTC(Number(utcDate.split('T')[0].split('-')[0]), Number(utcDate.split('T')[0].split('-')[1]) - 1, Number(utcDate.split('T')[0].split('-')[2]), (Number(utcDate.split('T')[1].split(':')[0]) + Number(offsetHours)), (Number(utcDate.split('T')[1].split(':')[1]) + Number(offsetMinutes)),0));

function z(n){return (n < 10? '0' : '') + n;};

var currentDateString = currentDate.getUTCFullYear() + '-' + z(currentDate.getUTCMonth() + 1) + '-' + z(currentDate.getUTCDate());

So above logic about creating UTC date and then adding number of hours and minutes to it to get desired date and time in UTC timezone. So virtually it's UTC date and time but since we added offset it will show you local date and time.

Hope this helps you.



Wednesday, June 15, 2016

Android Identify Notification Tap and Go To Particular Fragment In App

Hello,

Recently in one of my project there was a requirement to go to certain section of app as soon as user taps on particular notification in Android top bar. In this blog I am going to mention how to do this.

First of all you have to properly create notification object.

private static void generateNotification(Context context, String message, String type, String date) {

int icon = R.drawable.icon;

long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
notification.defaults = Notification.DEFAULT_SOUND;
String title = context.getString(R.string.app_name);

Intent notificationIntent = new Intent(context.getApplicationContext(),
MyActivity.class);
notificationIntent.putExtra("msg", message);
notificationIntent.putExtra("type", type);
notificationIntent.putExtra("date", date);

notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, notificationIntent, 0);
notification.contentIntent = contentIntent;

// set intent so it does not start a new activity

PendingIntent intent = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}

As you can see in above code we have created notificationIntent where I have specified My fragment activity and put all the params we get in notification as extra in intent. No go to your FragmentActivity class and add following code in onCreate method.


onNewIntent(getIntent()); 

And added following code in in your activity

@Override
public void onNewIntent(Intent intent){
    Bundle extras = intent.getExtras();
    if(extras != null){
        if(extras.containsKey("msg"))
        {
            // extract the extra-data in the Notification
            String msg = extras.getString("msg");
            if(isConsiderNewIntent == true){
            Log.v("GCM","GCM message is on new intent"+msg);
            String type = intent.getStringExtra("type");
            String date = intent.getStringExtra("date");
            //check type of message here and go to certain fragment.
            }
        }
    }
}

Hope this helps you.

Magento 2.0 Products API Get all the Details Of Products.

Hello,

It's been long since I have worked on Magento and published a blog on it. But recently my team was stuck in Magento REST Products API so I have to look into it. Basically the problem was

V1/categories/:categoryId/products API.

This API gives following result in an array.

{
     "sku": "Cotton"
     "position": 10001
     "category_id": "2"
}

Now that's little bit weird as there are no other info of products like product name, description etc. So to get this info we have to use other API which is.


V1/products/:sku

But practically that is not a solution. As we may have n number of products so we can call details API n number of times. So what to do in this case. I have spent almost couple of hours on this but could not get any solution so finally this is what I did.


I used SOAP V1/categories/:categoryId/products API in other PHP file go get array of SKUs and loop through an array and formed following strings of SKUs.

sku1,sku2,sku3,sku4,sku5

Now I used SOAP V1/products API will following search criteria.

V1/products?searchCriteria[filter_groups][0][filters][0][field]=sku&searchCriteria[filter_groups][0][filters][0][value]=sku1,sku2, sku3,sku4,sku5&searchCriteria[filter_groups][0][filters][0][condition_type]=in

As you can see above I used filed SKU in search criteria , passed all the SKU I need in comma separated format and used condition IN.

But wait there was another problem,  After calling above API, I did not get any result. I used few different tricks like

[sku1,sku2,sku3,sku4,sku5]

['sku1','sku2','sku3','sku4','sku5']

'sku1','sku2','sku3','sku4','sku5'

But nothing worked. Again I tried to find solution for sometime ad found solution in Magento 2 GitHub repo.

Please check this link.

https://github.com/magento/magento2/commit/65819d2f61a63e4fa9fc978220f8662ee5472791

This problem is going to be fixed in next release but we could not wait so here I updated Magento code myself.

Open the following file.

lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php

Go to line no 2792

and add following code.

if (($key == 'in' || $key == 'nin') && is_string($value)) {
$value = explode(',', $value);
}

That's it and now run following API.

V1/products?searchCriteria[filter_groups][0][filters][0][field]=sku&searchCriteria[filter_groups][0][filters][0][value]=sku1,sku2, sku3,sku4,sku5&searchCriteria[filter_groups][0][filters][0][condition_type]=in


It should give all the details of mentioned SKU. Hope this helps you.