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.