Skip to content

Latest commit

 

History

History
195 lines (149 loc) · 7.84 KB

File metadata and controls

195 lines (149 loc) · 7.84 KB

BigCommerce Multi-Child Products

Provides a way to change default required options layout on product page into a table of all available combined options.

Getting Started

First, add the package (for example using npm) with npm install bigcommerce-multi-child-products.

Then, on your (custom) product template create or use a <div> element (we use the CSS class js-multichild but can be anyone you want) which is going to be used as the container for the Vuejs component.

On the product template you can also hide (or remove) the Add to Cart button since the component adds its own in order to add to cart more than one product at a time.

Also, on your (custom) template you can add a CSS class like js-multichild-product-view on your productView <div> element in order to pass it as the scope for the VueJs component.

Now on product.js file you can import the package passing the scope which is a jQuery object (since jQuery is already imported by BigCommerce). Also, you need to pass the context object with product options and product_id (injected from your template) along with all text that can be injected from your language file through your template. Later we'll show an example of how to inject this data but for now, these are the language properties to be passed to the context object:

  • langCurrencyToken -> this comes from settings.money.currency_token
  • langSelectItems
  • langProductCode
  • langItemName
  • langQty
  • langPrice
  • langAdd
  • langTotal
  • langAddToCart
  • langAddingToCart
  • langOutOfStock

Last, you need to remove the default way BigCommerce render options, which is inside <div data-product-option-change> element. Do not remove this element tho, since this is needed by BigCommerce (it listens for options changes which are not needed here).

These are the steps to start, please check the example below to enlight more these steps.

Prerequisites

Nodejs v10+ (we assume you have installed something like nvm for changing Node versions).

Have a valid .stencil file as documented here.

Example

Once installed the package, we add the text on the language file like this (en.json):

{
    ...,
    "multichild_product": {
        "select_items": "Select items you wish to purchase, then Add to Cart:",
        "product_code": "Product Code",
        "item_name": "Item Name",
        "price": "Price",
        "qty": "Qty",
        "add": "Add",
        "total": "Total:",
        "add_to_cart": "Add to Cart",
        "adding_to_cart": "Adding to Cart...",
        "out_of_stock": "Out of Stock"
    }
}

We need to inject this text into the context object, one way to do this is to create a template like template/components/custom/product/multichild-product-lang.html

{{inject 'langCurrencyToken' settings.money.currency_token}}
{{inject 'langSelectItems' (lang 'multichild_product.select_items')}}
{{inject 'langProductCode' (lang 'multichild_product.product_code')}}
{{inject 'langItemName' (lang 'multichild_product.item_name')}}
{{inject 'langPrice' (lang 'multichild_product.price')}}
{{inject 'langQty' (lang 'multichild_product.qty')}}
{{inject 'langAdd' (lang 'multichild_product.add')}}
{{inject 'langTotal' (lang 'multichild_product.total')}}
{{inject 'langAddToCart' (lang 'multichild_product.add_to_cart')}}
{{inject 'langAddingToCart' (lang 'multichild_product.add_to_cart')}}
{{inject 'langOutOfStock' (lang 'multichild_product.out_of_stock')}}

Now, we add this into our (custom) template and inject options and product_id, for example template/components/custom/product/multichild-product-view.html. We strip the content that remains the same on a "normal" productView template:

{{> components/custom/product/multichild-product-lang }}

<div class="productView js-multichild-product-view">
    ...

    <section class="productView-details">
        <div class="productView-product">
            <h1 class="productView-title" {{#if schema}}itemprop="name"{{/if}}>Test view {{product.title}}</h1>
            ...
        </div>
    </section>

    <section class="productView-images" data-image-gallery>
        ...
    </section>

    <section class="productView-details">
        <div class="productView-options">
            {{#if product.release_date }}
                <p>{{product.release_date}}</p>
            {{/if}}
            <form class="form" method="post" action="{{product.cart_url}}" enctype="multipart/form-data" data-cart-item-add>
                <input type="hidden" name="action" value="add">
                <input type="hidden" name="product_id" value="{{product.id}}"/>
                    {{#each product.customizations}}
                        {{{dynamicComponent 'components/products/customizations'}}}
                    {{/each}}

                <div class="js-multichild">
                    {{inject 'options' product.options}}
                    {{inject 'product_id' product.id}}
                </div>

                <div data-product-option-change style="display:none;">
                    <!-- This content is removed -->
                </div>
                ...
            </form>
            {{#if settings.show_wishlist}}
                {{> components/common/wishlist-dropdown}}
            {{/if}}
        </div>
        {{> components/common/share}}
        {{{snippet 'product_details'}}}
    </section>

    <article class="productView-description"{{#if schema}} itemprop="description"{{/if}}>
        ...
    </article>
</div>

If we want to show our own free shipping section, let's say, we have on our normal template the next free shipping element:

    {{#if product.shipping}}
        {{#if product.shipping.price.value '==' 0}}
            <div class="product-free-shipping">
                <img src="{{cdn 'icons/product-badge-free-shipping.svg'}}" alt="{{lang 'products.shipping_free'}}" class="product-free-shipping-badge">
            </div>
        {{/if}}
    {{/if}}

With the class name .product-free-shipping we tell the widget to render the free shipping element. The SVG inside points to /content/icons/product-badge-free-shipping.svg which is the same as in the normal shipping template above. This is just in case you want to render a free shipping inside the widget as shown in the example below.

Lastly, on product.js we import and use the package:

/*
 Import all product specific js
 */
import $ from 'jquery';
import PageManager from './page-manager';
import Review from './product/reviews';
import collapsibleFactory from './common/collapsible';
import ProductDetails from './common/product-details';
import videoGallery from './product/video-gallery';
import { classifyForm } from './common/form-utils';

export default class Product extends PageManager {
    onReady() {
        ...

        if (document.querySelector('.js-multichild-product-view')) {
            import('bigcommerce-multi-child-products')
                .then(multichild => multichild.default($('.js-multichild-product-view'), this.context));
        }
    }

    ...
}

That's it, you should be able to use the VueJs component

This is how a normal product page can look:

and this is how it looks with our custom template applied (styling can be inside the normal productView.scss file).

Notes

When clicking the Add to Cart button, customer is redirected to the Cart page since there is no easy way to show the added products on the cart preview popup.

Authors

  • Hector Fernando Hurtado

License

This project is licensed under the MIT License - see the LICENSE file for details

alt text