Friday, February 28, 2014

JavaScript Simulate Touch Events on Phone to Mouse Events

Have you ever faced an issue that some of the JavaScript code for handling touch events  does not work on phone?

For example take an example of jQuery draggable. when you test it it does not work in mobile browser. The reason is, it binds and tracks mouse events while phone we don't have mouse events but we have touch events and that's why jQuery draggable will not work. Same way if you have some other old JavaScript framework which may not work on phone because of this issue. What if you have to use that framework or code and you can not change it because it's minified files? Here in this blog we will explain the solution for it. Basically we will simulate touch events to mouse events so this types of code works.

We will convert

touchstart => mousedown
touchmove => mousemove
touchend => mouseup

Check the following code.

function touchToMouseHandler(event) {
var touch = event.changedTouches[0];

var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent({
touchstart: "mousedown",
touchmove: "mousemove",
touchend: "mouseup"
}[event.type], true, true, window, 1,
touch.screenX, touch.screenY,
touch.clientX, touch.clientY, false,
false, false, false, 0, null);

touch.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}

function initHandlers() {
document.addEventListener("touchstart", touchToMouseHandler, true);
document.addEventListener("touchmove", touchToMouseHandler, true);
document.addEventListener("touchend", touchToMouseHandler, true);
document.addEventListener("touchcancel", touchToMouseHandler, true);
}


So here initHandlers function will add listers to touch events and function touchToMouseHandler will convert touch events to mouse events and simulate the action. Above code you can out in JS file on script tag in your html file and call the initHandlers function. With this above code you can use code with mouse events on phone browsers. Hope this helps you.

Sencha Touch List Accordion Layout (Expand and Collapse Sencha Touch List Item)

Hello,

Recently I was working on a project where we have a requirement to have accordion layout in Sencha Touch List items. Basically there are few items in list and user should be able to expand and collapse it by taping in respective list item. In this blog, we will see how to implement it.  First set fix item height for the list. For example,

{
       xtype: 'list',
       itemId: 'itemsList',
       id: 'itemsList',
       store: 'Items',
       itemHeight: 30,
       itemTpl:'<div style="overflow:hidden">Touch me to Expand Item {itemName}'+
                           '<div>'+
                                  '{itemDescription}'
                           '</div>'+
                    '</div>'
}

As you see in above code we have set height of item to 30 and set overflow to hidden so now you can have big texts as item description that will not be visible completely in collapsed mode. Now we have to add tap event for list in controller.

control: {
        '#itemsList': {
        itemtap: 'expandCollapseItemView'
        }
        }
And the function expandCollapseItemView in your controller.

expandCollapseItemView: function(list, index, target, record, event){
        var fromHeight = 0;
    var toHeight = 0;
    if(target.element.dom.clientHeight <= 30){
    fromHeight = 30;
    toHeight = 100;
     }else{
    fromHeight = 100;
    toHeight = 30;
     }
    Ext.Animator.run({
element: target.element,
duration: 500,
easing: 'ease-in',
preserveEndState: true,
from: {
height: fromHeight
},
to: {
height: toHeight
}
});
}

So if you check the above code we are identifying if we have expand or collapse based on client height of the item with the property target.element.dom.clientHeight. If height is less then or equal to 30 which is our item height for the list, we will expand the list item. After expanding list item the height will be 100 next time we will get clientHeight as 100 so we will collapse it to 30.

And we are running the animation with Ext.Animator.run and setting height from small to big or big to small.

With this you have expandable and collapsible list items.

Wednesday, February 5, 2014

Magento Get Cart Items - How to get the correct list?

Recently we were working on Magento project where we were building custom APIs for the Magento. One such API was to return the current items in current cart session. Now we know that Magento has various type of the products like simple product, Simple product with custom options, configurable product, bundle product etc and in our API we have to add support for all. Now here we have faced the issue with bundle products. As when we add a bundle product with cart, magento also adds selected simple products in cart session.

For example , you have a bundle product called A and it has associated product X, Y and Z. Customer has selected bundle product A and selected options X and Y. Magento will add three product in cart. One is A and other two are Y, Z.  So in our API when we were trying to get items in cart we were getting three items. That is wrong as user has only selected parent bundle product so we should only display it with the options selected. We used following code to get items.

$quote_id = $_REQUEST['quote_id'];
$cartsession = Mage::getSingleton('checkout/session')->getQuote();
foreach ($cartsession->getAllItems() as $item) {

}

So it was returning three items that is wrong. So initially we thought of removing those items from the collections. But then we may have this scenario. User has added bundle product A with X and Y. X product is also sellable independently. So if user has added it, we should display product A and product X in cart. So it was difficult to identify in collections. So what is the solution? After checking class definition of Mage_Sales_Model_Quote in app/code/core/Mage/Sales/Model/Quote.php , we found following two functions.

/**
     * Retrieve quote items array
     *
     * @return array
     */
    public function getAllItems()
    {
        $items = array();
        foreach ($this->getItemsCollection() as $item) {
            if (!$item->isDeleted()) {
                $items[] =  $item;
            }
        }
        return $items;
    }

    /**
     * Get array of all items what can be display directly
     *
     * @return array
     */
    public function getAllVisibleItems()
    {
        $items = array();
        foreach ($this->getItemsCollection() as $item) {
            if (!$item->isDeleted() && !$item->getParentItemId()) {
                $items[] =  $item;
            }
        }
        return $items;
    }

So there is only once difference here in both the function and that is the condition !$item->isDeleted() && !$item->getParentItemId() in second function. It filters the product based in parent id. So in our case product X and Y has parent id product A so that products were avoided. in list and we get only single bundle product. If the product X is added separately, it does not have any parent so it will be still visible in list.

So in short, to get the correct list of items in cart use getAllVisibleItems function if you have to support bundle products and configurable products. If you have only simple products and custom options you can use getAllItems function.

Most weird problem I have ever faced with JavaScript.

Recently I have faced a weird problem while working in a mobile web application. Application was built with HMTL/CSS/JavaScript. There was a screen where we were adding and removing HTML nodes dynamically with JavaScript. Here I have faced worst issue. When we remove HTML DIV node with JavaScript, it was still visible in DOM. Although it's removed but the DIV was still there. Although none of the events of DIV or Nodes inside DIV were working. There were few radio buttons inside it. If you tap on it, it does not work. That means elements are removed, but visually DIV was still there.

However it was working on other Android devices but was not working in Samsung Galaxy S4 with Android 4.3. It was not working in native internet application or Chrome in that device.

I was really surprised, as I have never faced such issue since I started working with JavaScript. And it's not a rocket science. Just the simple logic of removing the DIV with JavaScript and it did not work. See the code below.

var element = document.getElementById('modifier');
if(element){
          element.parentNode.removeChild(element);
}

As you can see, it's very simple code, first get element by id and remove it with parentNode. A standard JavaScript logic to remove HTML node. As we know it's  standard logic. W3Schools tutorial, also mention the same logic. Stack-overflow gives the same answer. Many JavaScript experts/bloggers have mentioned the same solution. But there was a issue, so how did I solve it.? See the code below.

var element = document.getElementById('modifier_');
if(element){
           var parentNode = element.parentNode;
           element.parentNode.removeChild(element);
           parentNode.innerHTML = parentNode.innerHTML;
}

This line  parentNode.innerHTML = parentNode.innerHTML does the magic. It's kind of refreshing the UI. It's really really stupid solution. But it solved this issue.

I don't know the reason why this issue was only on that device. So if you have any idea on this, please comment here. And if you ever encounter such issue, try using my solution.

Saturday, February 1, 2014

Create Simple MAC OSX application with WebView and Load URL in it

Hello,

In this blog post we will see how to create a simple MAC OSX application with webview, which loads a URL in webview. This types of application are very useful when you have nicely designed web application and you want to convert it to MAC OSX app. Using this approach, you don't have to create separate OSX application. To create this application , you will need Xcode. Open the Xcode and select "Create New xCode project". Select OS X -> Application - > Cocoa Application. It will show following window.

Enter product name, Organization Name, Company Identifier, Class Prefix of your choice and click on Next. It will ask for the location to save the project. Select the location and create project. Once the project is created, you will see following type of file stricture in Xcode.

It may be different for in you based on entered class prefix by you. After this open AppDelegate.h file. Add following line after line #import <Cocoa/Cocoa.h>

#import <WebKit/WebKit.h>

After this add following line after @property (assign) IBOutlet NSWindow *window;

@property (assign) IBOutlet WebView *webView;

Once done open MainMenu.xib file. Select window as displayed in following image and add webview as show in the following image.


After that we have to add IBOutlet for that Select App delegate from the right pane and Control + Drag from it to Webview. It will show context menu with Webview. Select the webview and it will add IBOutlet. See the following image.


Now we have to load URL in Webview. Open your AppDelegate.m file and find the applicationDidFinishLaunching function and add following code to it.

NSRect frame=[NSScreen mainScreen].frame ;
[self.window setFrame:frame display:YES animate:YES];

Above lines will open the window in fullscreen mode. 

NSURL *url = [NSURL URLWithString:@"http://davehiren.blogspot.com"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[[[self webView] mainFrame] loadRequest:urlRequest];
[self.window setContentView:self.webView];

Above lines will load the URL in webview. You can also set title of window with

[self.window setTitle:@"title"];

When you run the app you should see following screen.

That's it, your application is ready. You can change the URL the way you want.






What is Model View View Model (MVVM) pattern? Implement it with Knockout JS

Recently we tried our hands on PhoneJs, a JavaScript framework to build cross platform application. It usese jQuery and Knockout JS and it implements MVVM design pattern.

Model View View Model - MVVM is a design pattern to build an application. It was first introduced by Microsoft and it's widely used by Microsoft Silverlight and WPF (Windows Presentation Foundation) developers. We will not go in that detail But we will see how it is implemented with Knockout JS.

First lets see the elements of MVVM pattern

Model

Model represents the business entity. It's your application's stored data. Model just stores the data. It's independent of user interface. It does not handle how the data will behave and represented on user interface. In short it encapsulates application data. This data can be used by ViewModel. ViewModel can update/add/delete data. In Knockout JS any valid JavaScript object can represent Model.

For example : 

var person = {
      firstName: 'Hiren',
      lastName: 'Dave'
};

Above is the valid Knockout JS model. Also we can define datasource that fetch data from remote URL as Model.

View

View is the visual representation of model. However it does not interact with models directly. It just describes the format and events. It also defines the bindings for the data source. It pass on events to ViewModel and receive response from ViewModel. It's independent of business logic described in ViewModel. It updates it self when it receives data from ViewModel. With Knockout JS  View is the plain HTML file. For example.

<div> My name is <span data-bind="text: firstName" /> <span data-bind="text: lastName" /> </div>

ViewModel

ViewModel is special type of controller which that converts the data for the view. It passed command from Model to View and View to Model. It defines event handlers for the View. It converts model information to view information. It also exposes methods to maintain view's state, updates model based on view states and updates views for change in Model. For example,

ko.applyBindings(person);

Above code will tell View to apply binding and transfer person model to view. View will show the data from specific object properties as mentioned in View. In this case it is firstName and lastName.

This is how Knockout JS works.