Latest news

How to Create Fly to Cart Feature In Magento 2

No comments

Quality improvements in eCommerce websites are essential to keep customers engaged in the online shopping experience. This post will introduce a new feature from Magento 2 to upgrade the current website: Fly To Cart.

Let’s begin

1/ What Is Fly To Cart Feature?

Just as you might imagine from its name, this feature will have the product chosen flown into the cart. Thus, the step of adding things to the shopping cart is now done within one single screen.

In the past, whenever we added a new thing in the cart, the site would then send us to the shopping cart page which is rather time-consuming. With this feature, fewer steps and less time are required as there are fewer pages to switch and it is easier to track how many products are already in the cart. 

Also, consumers do not have to check the cart again to ensure whether the products have been included in the purchase or not.

This feature also makes the online shopping experience more interesting. For young people (18-25), they will probably be excited to test this function on the site.

2/ Installation Guide

1. Need to override Magento_Catalog/js/catalog-add-to-cart.js file

create require js-config.js Vendor/Module/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {
            catalogAddToCart: 'Vendor_Module/js/catalog-add-to-cart'
        }
    }
};

2. add this content to Vendor_Module/js/catalog-add-to-cart.js

define([
    'jquery',
    'mage/translate',
    'underscore',
    'Magento_Catalog/js/product/view/product-ids-resolver',
    'jquery-ui-modules/widget'
], function ($, $t, _, idsResolver) {
    'use strict';

    $.widget('mage.catalogAddToCart', {
        options: {
            processStart: null,
            processStop: null,
            bindSubmit: true,
            minicartSelector: '[data-block="minicart"]',
            messagesSelector: '[data-placeholder="messages"]',
            productStatusSelector: '.stock.available',
            addToCartButtonSelector: '.action.tocart',
            addToCartButtonDisabledClass: 'disabled',
            addToCartButtonTextWhileAdding: '',
            addToCartButtonTextAdded: '',
            addToCartButtonTextDefault: '',
        },

        /** @inheritdoc */
        _create: function () {
            if (this.options.bindSubmit) {
                this._bindSubmit();
            }
        },

        /**
         * @private
         */
        _bindSubmit: function () {
            var self = this;

            if (this.element.data('catalog-addtocart-initialized')) {
                return;
            }

            this.element.data('catalog-addtocart-initialized', 1);
            this.element.on('submit', function (e) {
                e.preventDefault();
                self.submitForm($(this));
            });
        },

        /**
         * @private
         */
        _redirect: function (url) {
            var urlParts, locationParts, forceReload;

            urlParts = url.split('#');
            locationParts = window.location.href.split('#');
            forceReload = urlParts[0] === locationParts[0];

            window.location.assign(url);

            if (forceReload) {
                window.location.reload();
            }
        },

        /**
         * @return {Boolean}
         */
        isLoaderEnabled: function () {
            return this.options.processStart && this.options.processStop;
        },

        /**
         * Handler for the form 'submit' event
         *
         * @param {jQuery} form
         */
        submitForm: function (form) {
            this.ajaxSubmit(form);
        },

        /**
         * @param {jQuery} form
         */
        ajaxSubmit: function (form) {
            var self = this,
                productIds = idsResolver(form),
                formData;

            $(self.options.minicartSelector).trigger('contentLoading');
            self.disableAddToCartButton(form);
            formData = new FormData(form[0]);

            $.ajax({
                url: form.attr('action'),
                data: formData,
                type: 'post',
                dataType: 'json',
                cache: false,
                contentType: false,
                processData: false,

                /** @inheritdoc */
                beforeSend: function () {
                    if (self.isLoaderEnabled()) {
                        $('body').trigger(self.options.processStart);
                    }
                },

                /** @inheritdoc */
                success: function (res) {
                    var eventData, parameters;

                    $(document).trigger('ajax:addToCart', {
                        'sku': form.data().productSku,
                        'productIds': productIds,
                        'form': form,
                        'response': res
                    });

                    if (self.isLoaderEnabled()) {
                        $('body').trigger(self.options.processStop);
                    }

                    const miniCartElm = $(self.options.minicartSelector);
                    if (miniCartElm.length > 0) {
                        let productImage = form.closest('.product-item-info').find('img.product-image-photo').eq(0);
                        if (productImage.length === 0) {
                            productImage = form.closest('.column.main').find('.product.media img').eq(0);
                        }
                        if (productImage.length === 0) {
                            productImage = form.closest('tr.price-list-item').find('img.product-image-photo').eq(0);
                        }
                        if (productImage.length > 0) {
                            const productImageClone = productImage.clone()
                                .offset({
                                    top: productImage.offset().top,
                                    left: productImage.offset().left
                                })
                                .css({
                                    'opacity': '0.75',
                                    'position': 'absolute',
                                    'z-index': '9999',
                                    'width': 300,
                                    'height': 300
                                })
                                .appendTo($('body'));

                            productImageClone.removeClass();

                            productImageClone.animate({
                                'top': miniCartElm.offset().top + 10,
                                'left': miniCartElm.offset().left + 10,
                                'width': 0,
                                'height': 0
                            }, 700, 'easeInOutCubic', function () {
                                $(this).detach();
                            });

                            setTimeout(function () {
                                miniCartElm.find('.counter').effect('bounce', {
                                    times: 1
                                }, 200);
                            }, 700);
                        }
                    }

                    if (res.backUrl) {
                        eventData = {
                            'form': form,
                            'redirectParameters': []
                        };
                        // trigger global event, so other modules will be able add parameters to redirect url
                        $('body').trigger('catalogCategoryAddToCartRedirect', eventData);

                        if (eventData.redirectParameters.length > 0 &&
                            window.location.href.split(/[?#]/)[0] === res.backUrl
                        ) {
                            parameters = res.backUrl.split('#');
                            parameters.push(eventData.redirectParameters.join('&'));
                            res.backUrl = parameters.join('#');
                        }

                        self._redirect(res.backUrl);

                        return;
                    }

                    if (res.messages) {
                        $(self.options.messagesSelector).html(res.messages);
                    }

                    if (res.minicart) {
                        $(self.options.minicartSelector).replaceWith(res.minicart);
                        $(self.options.minicartSelector).trigger('contentUpdated');
                    }

                    if (res.product && res.product.statusText) {
                        $(self.options.productStatusSelector)
                            .removeClass('available')
                            .addClass('unavailable')
                            .find('span')
                            .html(res.product.statusText);
                    }
                    self.enableAddToCartButton(form);
                },

                /** @inheritdoc */
                error: function (res) {
                    $(document).trigger('ajax:addToCart:error', {
                        'sku': form.data().productSku,
                        'productIds': productIds,
                        'form': form,
                        'response': res
                    });
                },

                /** @inheritdoc */
                complete: function (res) {
                    if (res.state() === 'rejected') {
                        location.reload();
                    }
                }
            });
        },

        /**
         * @param {String} form
         */
        disableAddToCartButton: function (form) {
            var addToCartButtonTextWhileAdding = this.options.addToCartButtonTextWhileAdding || $t('Adding...'),
                addToCartButton = $(form).find(this.options.addToCartButtonSelector);

            addToCartButton.addClass(this.options.addToCartButtonDisabledClass);
            addToCartButton.find('span').text(addToCartButtonTextWhileAdding);
            addToCartButton.attr('title', addToCartButtonTextWhileAdding);
        },

        /**
         * @param {String} form
         */
        enableAddToCartButton: function (form) {
            var addToCartButtonTextAdded = this.options.addToCartButtonTextAdded || $t('Added'),
                self = this,
                addToCartButton = $(form).find(this.options.addToCartButtonSelector);

            addToCartButton.find('span').text(addToCartButtonTextAdded);
            addToCartButton.attr('title', addToCartButtonTextAdded);

            setTimeout(function () {
                var addToCartButtonTextDefault = self.options.addToCartButtonTextDefault || $t('Add to Cart');

                addToCartButton.removeClass(self.options.addToCartButtonDisabledClass);
                addToCartButton.find('span').text(addToCartButtonTextDefault);
                addToCartButton.attr('title', addToCartButtonTextDefault);
            }, 1000);
        }
    });

    return $.mage.catalogAddToCart;
});

You can see this is code for fly to cart feature: 

const miniCartElm = $(self.options.minicartSelector);
if (miniCartElm.length > 0) {
    let productImage = form.closest('.product-item-info').find('img.product-image-photo').eq(0);
    if (productImage.length === 0) {
        productImage = form.closest('.column.main').find('.product.media img').eq(0);
    }
    if (productImage.length === 0) {
        productImage = form.closest('tr.price-list-item').find('img.product-image-photo').eq(0);
    }
    if (productImage.length > 0) {
        const productImageClone = productImage.clone()
            .offset({
                top: productImage.offset().top,
                left: productImage.offset().left
            })
            .css({
                'opacity': '0.75',
                'position': 'absolute',
                'z-index': '9999',
                'width': 300,
                'height': 300
            })
            .appendTo($('body'));

        productImageClone.removeClass();

        productImageClone.animate({
            'top': miniCartElm.offset().top + 10,
            'left': miniCartElm.offset().left + 10,
            'width': 0,
            'height': 0
        }, 700, 'easeInOutCubic', function () {
            $(this).detach();
        });

        setTimeout(function () {
            miniCartElm.find('.counter').effect('bounce', {
                times: 1
            }, 200);
        }, 700);
    }
}

3/ Example

If you still find it hard to imagine how this feature works, check out this website: Banana. As you click the “Add to cart” button, the product will fly into the cart symbol on the page header.

A reminder to confirm the details of the order you have just made also appear so that you can see what you have put in the cart.

Wrapping Up

While this function sounds rather simple, its benefits to the website are hard to deny and they could enhance the shopping experience for online users.

Don’t hesitate to contact us to get the best-upgraded features to your website.

Leave a comment below if you find this post helpful!

Giang LeHow to Create Fly to Cart Feature In Magento 2

Leave a Reply

Your email address will not be published. Required fields are marked *