{"_id":"560b0a9a109fc70d00008d13","category":{"_id":"58105f548a4aed0f00d67536","__v":0,"project":"55a6e72e8cc73e0d00096635","version":"55a6e72f8cc73e0d00096638","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-10-26T07:46:28.684Z","from_sync":false,"order":11,"slug":"event-hooks","title":"Event Hooks"},"version":{"_id":"55a6e72f8cc73e0d00096638","project":"55a6e72e8cc73e0d00096635","hasReference":false,"__v":29,"hasDoc":true,"createdAt":"2015-07-15T23:05:19.125Z","releaseDate":"2015-07-15T23:05:19.125Z","categories":["55a6e7308cc73e0d00096639","55b7ed07aea7c8190058badb","5604567c0c78b00d0039b191","5605e6f23a93940d002b3e4a","5605f2bba4574a0d00811365","5605f309a4574a0d00811366","5608e3b98aedf50d0004cf8f","5608e4318aedf50d0004cf90","5608e6b5a7cc2f0d00d9754d","5608e6d331beb60d001b6560","5608f879a7cc2f0d00d97580","560b097887b71d0d000d3bd9","560b13cbafa0990d00979545","560b5cbec341310d00de2a01","560b5cd0c341310d00de2a02","566a35b81e08750d00a0c49b","566a3e8503b4b20d00d02a4a","567889d307bf6a0d0083edc8","569c8b7c15bb390d00db6f9d","56b254dc65ddf50d0076ba8f","57a8ebc4cdeea20e001d2a63","57e48a4000c8680e00fae6e7","5808216773557d0f00a1e428","58105ad54a8aa50f00aa4cba","58105bf298aea40f00afa3ba","58105f548a4aed0f00d67536","581061b898aea40f00afa3be","584b3de7e5f3a42300df6ef7","596839a75965d400155bb750"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"parentDoc":null,"project":"55a6e72e8cc73e0d00096635","__v":17,"user":"55a6caa022cfa321008e01d6","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-29T22:03:06.793Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"[block:html]\n{\n  \"html\": \"<A NAME=\\\"stencil-utils-ref\\\"></a>The following listings cover the Stencil functions that your client-side JavaScript can call outside Handlebars conventions:<br>\\n\\n<ul>\\n <li><a href=\\\"#API-js\\\">API [api.js]</a></li>\\n <li><a href=\\\"#Cart-API\\\">Cart API</a></li>\\n <li><a href=\\\"#Cookie\\\">Cookie Resource</a></li>\\n <li><a href=\\\"#Countries\\\">Countries Resource</a></li>\\n <li><a href=\\\"#ProdAttrib\\\">Product Attributes Resource</a></li>\\n <li><a href=\\\"#Product\\\">Product Resource</a></li>\\n <li><a href=\\\"#Search\\\">Search Resource</a></li>\\n</ul> \\n\\nThese functions help you set up asynchronous requests to modify the customer’s cart or storefront view. By using this abstraction library, you can gain more-granular control over themes’ presentation.\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Finding Example Code\",\n  \"body\": \"Examples on this page are from Stencil's Cornerstone base theme. The base path for all listed examples is: `/cornerstone/assets/js/theme/`.\"\n}\n[/block]\n\n[block:html]\n{\n  \"html\": \"<h2> <A NAME=\\\"API-js\\\"></a>API [api.js]</h2>\\n\\nThe <span class=\\\"inline-code\\\">api.getPage()</span> function allows you to add Ajax functionality to your themes.<br>\\n\\n<br> <span id=\\\"getpage\\\"> <b>getPage Signature</b> </span> <br>\\n\\nThe following statement passes <span class=\\\"inline-code\\\">url</span> and <span class=\\\"inline-code\\\">options</span> arguments to the <span class=\\\"inline-code\\\">api.getPage()</span> function:<br><p></p>\\n\\n<pre>utils.api.getPage(url, options, callback)\\n</pre><br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">url</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">URL to which you want to send a request (for example: localhost:4000/cart.php)</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">options</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Can contain <span class=\\\"inline-code\\\">template</span>, <span class=\\\"inline-code\\\"><a href=\\\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\\\">FormData</a></span> (for POST methods), <span class=\\\"inline-code\\\">params</span>&nbsp;(for GET methods), and/or <span class=\\\"inline-code\\\">config</span>. <br><br>    \\n      The <span class=\\\"inline-code\\\">template</span> option allows you to select a particular template, or an array of templates, for rendering one page. Each value must correspond to a file present in the theme's <span class=\\\"inline-code\\\">templates/components/</span> subdirectory. <br><br>\\n      The <span class=\\\"inline-code\\\">config</span> option can be used to pass extra resources, corresponding to attributes that are valid in a page's <a href=\\\"/docs/using-yaml-front-matter\\\">front matter</a>, as an object.\\n    </td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\nThe <span class=\\\"inline-code\\\">config</span> argument works like front matter: it encapsulates JSON. For a usage example of <span class=\\\"inline-code\\\">config</span>, see <NOBR><a href=\\\"/docs/remote-api-example\\\">Remote API Example</a></nobr>. <br><br>\\n\\n\\n<span id=\\\"getPageEx\\\"> <b>getPage Example</b> </span> <br>\\n\\nIn the following example (from <span class=\\\"inline-code\\\">common/faceted-search.js</span>), <span class=\\\"inline-code\\\">api.getPage()</span> is called to help execute an <span class=\\\"inline-code\\\">updateView()</span> function:<br><p></p>\\n\\n<pre>    updateView() {\\n        $(this.options.blockerSelector).show();\\n\\n        api.getPage(urlUtils.getUrl(), this.requestOptions, (err, content) => {\\n            $(this.options.blockerSelector).hide();\\n\\n            if (err) {\\n                throw new Error(err);\\n            }\\n\\n            // Refresh view with new content\\n            this.refreshView(content);\\n        });\\n    }</pre><p></p>\\n\\n\\n<h2> <A NAME=\\\"Cart-API\\\"></a>Cart API </h2>\\n\\nThe following functions allow your theme to work with cart contents in customized ways.<br><br>\\n\\n<b>itemAdd Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">itemAdd</span> function allows your code to add an item to the cart, with options:<br><p></p>\\n\\n<pre>utils.api.cart.itemAdd(<a href=\\\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\\\">FormData</a>, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\"><A NAME=\\\"CartAPI-FormData\\\"></a>formData</td>\\n    <td class=\\\"\\\"><a href=\\\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\\\">FormData</a> object </td>\\n    <td class=\\\"\\\">Contains all details about the added item and its product options</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<span id=\\\"itemAddEx\\\"> <b>itemAdd Example</b> </span> <br>\\n\\n<span class=\\\"inline-code\\\">itemAdd</span> is called at the head of the following example (from <span class=\\\"inline-code\\\">common/product-details.js</span>) to populate the cart:<br><p></p>\\n\\n<pre>        // Add item to cart\\n        utils.api.cart.itemAdd(new FormData(form), (err, response) => {\\n            const errorMessage = err || response.data.error;\\n\\n            $addToCartBtn\\n                .val(originalBtnVal)\\n                .prop('disabled', false);\\n\\n            this.$overlay.hide();\\n\\n            // Guard statement\\n            if (errorMessage) {\\n                // Strip the HTML from the error message\\n                const tmp = document.createElement('DIV');\\n                tmp.innerHTML = errorMessage;\\n\\n                return alert(tmp.textContent || tmp.innerText);\\n            }\\n\\n            // Open preview modal and update content\\n            if (this.previewModal) {\\n                this.previewModal.open();\\n\\n                this.updateCartContent(this.previewModal, response.data.cart_item.hash);\\n            } else {\\n                this.$overlay.show();\\n                // if no modal, redirect to the cart page\\n                this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);\\n            }\\n        }); </pre><br>\\n\\n\\n<b>itemUpdate Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">itemUpdate</span> function allows your code to update a specified cart item’s quantity:<br>\\n\\n<p></p><pre>utils.api.cart.itemUpdate(itemId, qty, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">itemId</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">The item’s ID</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">qty</td>\\n    <td class=\\\"\\\">Integer</td>\\n    <td class=\\\"\\\">The item’s quantity in the cart</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n<span id=\\\"itemUpdateEx\\\"> <b>itemUpdate  Example</b> </span> <br>\\n\\nIn the following example (from <span class=\\\"inline-code\\\">cart.js</span>), <span class=\\\"inline-code\\\">itemUpdate</span> is called just before the final if/else test for an empty cart:<br><p></p>\\n\\n<pre>    cartUpdate($target) {\\n        const itemId = $target.data('cart-itemid');\\n        const $el = $(`#qty-${itemId}`);\\n        const oldQty = parseInt($el.val(), 10);\\n        const maxQty = parseInt($el.data('quantity-max'), 10);\\n        const minQty = parseInt($el.data('quantity-min'), 10);\\n        const minError = $el.data('quantity-min-error');\\n        const maxError = $el.data('quantity-max-error');\\n        const newQty = $target.data('action') === 'inc' ? oldQty + 1 : oldQty - 1;\\n\\n        // Does not quality for min/max quantity\\n        if (newQty < minQty) {\\n            return alert(minError);\\n        } else if (maxQty > 0 && newQty > maxQty) {\\n            return alert(maxError);\\n        }\\n\\n        this.$overlay.show();\\n\\n        utils.api.cart.itemUpdate(itemId, newQty, (err, response) => {\\n            this.$overlay.hide();\\n\\n            if (response.data.status === 'succeed') {\\n                // if the quantity is changed \\\"1\\\" from \\\"0\\\", we have to remove the row.\\n                const remove = (newQty === 0);\\n\\n                this.refreshContent(remove);\\n            } else {\\n                $el.val(oldQty);\\n                alert(response.data.errors.join('\\\\n'));\\n            }\\n        });\\n    } </pre><br>\\n\\n\\n<b>itemRemove Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">itemRemove</span> function allows your code to remove items from the cart:<br>\\n\\n<p></p><pre>utils.api.cart.itemRemove(itemId, callback)</pre>\\n <br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">itemId</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">The item’s ID</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<span id=\\\"itemRemoveEx\\\"> <b>itemRemove Example</b> </span><br>\\n\\nIn the following example (from <span class=\\\"inline-code\\\">cart.js</span>), <span class=\\\"inline-code\\\">itemRemove</span> is called before the if/else test:<br><p></p>\\n\\n<pre>    cartRemoveItem(itemId) {\\n        this.$overlay.show();\\n        utils.api.cart.itemRemove(itemId, (err, response) => {\\n            if (response.data.status === 'succeed') {\\n                this.refreshContent(true);\\n            } else {\\n                alert(response.data.errors.join('\\\\n'));\\n            }\\n        });\\n    } </pre><br>\\n\\n\\n<b>update Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">update</span> function allows your code to update the set of items in the cart:<br>\\n\\n<p></p><pre>utils.api.cart.update(itemId, qty, callback)</pre>\\n\\n <br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">items</td>\\n    <td class=\\\"\\\">Array</td>\\n    <td class=\\\"\\\">The items in the cart</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>update Example</b><br>\\n\\nThe following example shows a call to <span class=\\\"inline-code\\\">update</span> within the <span class=\\\"inline-code\\\">itemUpdate</span> function:<br><p></p>\\n\\n<pre>    /**\\n    itemUpdate(itemId, qty, callback) {\\n        let callbackArg = callback;\\n        let items;\\n\\n        if (Array.isArray(itemId) && typeof qty === 'function') {\\n            callbackArg = qty;\\n            items = itemId;\\n        } else {\\n            items = [\\n                {\\n                    id: itemId,\\n                    quantity: qty,\\n                },\\n            ];\\n        }\\n\\n        this.update(items, (err, response) => {\\n            const emitData = {\\n                items,\\n                err,\\n                response,\\n            };\\n\\n            Hooks.emit('cart-item-update-remote', emitData);\\n            callbackArg(err, response);\\n        });\\n    } </pre><br>\\n\\n\\n<b>getItemGiftWrappingOptions Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">getItemGiftWrappingOptions</span> function allows your code to retrieve gift-wrapping options for the current cart item, in customized ways:<br><p></p>\\n\\n\\n<pre>utils.api.cart.getItemGiftWrappingOptions(itemId, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">itemId</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">The cart item</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>getItemGiftWrappingOptions Example</b> <br>\\n\\nThe following example (from <span class=\\\"inline-code\\\">cart.js</span>) calls <span class=\\\"inline-code\\\">getItemGiftWrappingOptions</span> to display gift-wrapping options in a modal:<br><p></p>\\n\\n<pre>    bindGiftWrappingEvents() {\\n        const modal = defaultModal();\\n\\n        $('[data-item-giftwrap]').on('click', (event) => {\\n            const itemId = $(event.currentTarget).data('item-giftwrap');\\n            const options = {\\n                template: 'cart/modals/gift-wrapping-form',\\n            };\\n\\n            event.preventDefault();\\n\\n            modal.open();\\n\\n            utils.api.cart.getItemGiftWrappingOptions(itemId, options, (err, response) => {\\n                modal.updateContent(response.content);\\n\\n                this.bindGiftWrappingForm();\\n            });\\n        });\\n    } </pre><br>\\n\\n\\n<b>submitItemGiftWrappingOption Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">submitItemGiftWrappingOption</span> function allows your code to handle the customer’s gift-wrapping selection for the current cart item:<br><p></p>\\n\\n<pre>utils.api.cart.submitItemGiftWrappingOption(itemId, qty, callback)</pre>\\n<br>\\n\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">itemId</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">The cart item</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>submitItemGiftWrappingOption Example</b> <br>\\n\\nThis commented example shows a simple call to <span class=\\\"inline-code\\\">submitItemGiftWrappingOption</span>:\\n\\n<pre>    /**\\n     * Submit giftwrapping options\\n     *\\n     * :::at:::param {String} itemId\\n     * @param {Function} callback\\n     */\\n    submitItemGiftWrappingOption(itemId, params, callback) {\\n        this.remoteRequest(`/gift-wrapping/${itemId}`, 'POST', { params }, callback);\\n    } </pre><br>\\n\\n\\n<b>getContent Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">getContent</span> function allows your code to display the cart contents in customized ways:<br>\\n\\n<p></p><pre>utils.api.cart.getContent(options, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\"><A NAME=\\\"getContent-options\\\"></a>options</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Template containing content and totals children</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n<span id=\\\"getContentEx\\\"> <b>getContent Examples</b> </span> <br>\\n\\nThe following example (from <span class=\\\"inline-code\\\">common/product-details.js</span>) a call to <span class=\\\"inline-code\\\">getContent</span>, set up by a prior call to <span class=\\\"inline-code\\\">getCartContent</span>:<br><p></p>\\n\\n<pre>    /**\\n     * Get cart contents\\n     *\\n     * @param {String} cartItemHash\\n     * @param {Function} onComplete\\n     */\\n    getCartContent(cartItemHash, onComplete) {\\n        const options = {\\n            template: 'cart/preview',\\n            params: {\\n                suggest: cartItemHash,\\n            },\\n            config: {\\n                cart: {\\n                    suggestions: {\\n                        limit: 4,\\n                    },\\n                },\\n            },\\n        };\\n\\n        utils.api.cart.getContent(options, onComplete);\\n    } </pre><p></p>\\n\\nThis example (from <span class=\\\"inline-code\\\">cart.js</span>) shows a call to <span class=\\\"inline-code\\\">getContent</span> within the <span class=\\\"inline-code\\\">refreshContent</span> function:<br><p></p>\\n\\n<pre>    refreshContent(remove) {\\n        const $cartItemsRows = $('[data-item-row]', this.$cartContent);\\n        const $cartPageTitle = $('[data-cart-page-title]');\\n        const options = {\\n            template: {\\n                content: 'cart/content',\\n                totals: 'cart/totals',\\n                pageTitle: 'cart/page-title',\\n                statusMessages: 'cart/status-messages',\\n            },\\n        };\\n\\n        this.$overlay.show();\\n\\n        // Remove last item from cart? Reload\\n        if (remove && $cartItemsRows.length === 1) {\\n            return window.location.reload();\\n        }\\n\\n        utils.api.cart.getContent(options, (err, response) => {\\n            this.$cartContent.html(response.content);\\n            this.$cartTotals.html(response.totals);\\n            this.$cartMessages.html(response.statusMessages);\\n\\n            $cartPageTitle.replaceWith(response.pageTitle);\\n            this.bindEvents();\\n            this.$overlay.hide();\\n\\n            const quantity = $('[data-cart-quantity]', this.$cartContent).data('cart-quantity') || 0;\\n\\n            $('body').trigger('cart-quantity-update', quantity);\\n        });\\n    } </pre><p></p> \\n\\nHere is a final example of a call to <span class=\\\"inline-code\\\">getContent</span>, from <span class=\\\"inline-code\\\">global/cart-preview.js</span>:<br><p></p>\\n\\n<pre>    $cart.on('click', (event) => {\\n        const options = {\\n            template: 'common/cart-preview',\\n        };\\n\\n        // Redirect to full cart page\\n        //\\n        // https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent\\n        // In summary, we recommend looking for the string 'Mobi' anywhere in the User Agent to detect a mobile device.\\n        if (/Mobi/i.test(navigator.userAgent)) {\\n            return event.stopPropagation();\\n        }\\n\\n        event.preventDefault();\\n\\n        $cartDropdown\\n            .addClass(loadingClass)\\n            .html($cartLoading);\\n        $cartLoading\\n            .show();\\n\\n        utils.api.cart.getContent(options, (err, response) => {\\n            $cartDropdown\\n                .removeClass(loadingClass)\\n                .html(response);\\n            $cartLoading\\n                .hide();\\n        });\\n    }); </pre><br>\\n\\n\\n<b><A NAME=\\\"getShippingQuotes\\\"></a>getShippingQuotes Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">getShippingQuotes</span> function allows your code to retrieve shipping-cost quotes for the cart’s contents. It returns <span class=\\\"inline-code\\\">shippingQuote</span> objects that contain IDs. You must follow <span class=\\\"inline-code\\\">getShippingQuotes</span> by calling <span class=\\\"inline-code\\\"><a href=\\\"#submitShippingQuotes\\\">submitShippingQuote</a></span> on a <span class=\\\"inline-code\\\">quoteId</span>:<br>\\n\\n<p></p><pre>utils.api.cart.getShippingQuotes(params, renderWith, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">params</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Contains country_id, state_id, and zip_code</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">template</td>\\n    <td class=\\\"\\\">String/  Array/ Object</td>\\n    <td class=\\\"\\\">The template to use for rendering</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>getShippingQuotes and submitShippingQuote Example</b> <br><p></p>\\n\\nThe following example (from <span class=\\\"inline-code\\\">cart/shipping-estimator.js</span>) shows calls to both <span class=\\\"inline-code\\\">getShippingQuotes</span> and <span class=\\\"inline-code\\\">submitShippingQuote</span>:<br><p></p>\\n\\n<pre>    bindEstimatorEvents() {\\n        const $estimatorContainer = $('.shipping-estimator');\\n        const $estimatorForm = $('.estimator-form');\\n\\n        $estimatorForm.on('submit', (event) => {\\n            const params = {\\n                country_id: $('[name=\\\"shipping-country\\\"]', $estimatorForm).val(),\\n                state_id: $('[name=\\\"shipping-state\\\"]', $estimatorForm).val(),\\n                city: $('[name=\\\"shipping-city\\\"]', $estimatorForm).val(),\\n                zip_code: $('[name=\\\"shipping-zip\\\"]', $estimatorForm).val(),\\n            };\\n\\n            event.preventDefault();\\n\\n            utils.api.cart.getShippingQuotes(params, 'cart/shipping-quotes', (err, response) => {\\n                $('.shipping-quotes').html(response.content);\\n\\n                // bind the select button\\n                $('.select-shipping-quote').on('click', (clickEvent) => {\\n                    const quoteId = $('.shipping-quote:checked').val();\\n\\n                    clickEvent.preventDefault();\\n\\n                    utils.api.cart.submitShippingQuote(quoteId, () => {\\n                        location.reload();\\n                    });\\n                });\\n            });\\n        }); </pre><br>\\n\\n<A NAME=\\\"submitShippingQuote\\\"></a> <b>submitShippingQuote Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">submitShippingQuote</span> function must be called after <span class=\\\"inline-code\\\"><a href=\\\"#getShippingQuotes\\\">getShippingQuote</a></span>, which returns <span class=\\\"inline-code\\\">shippingQuote</span> objects that contain IDs. The cart page renders the shipping quotes. When the user selects one of the quotes, this function sends that <span class=\\\"inline-code\\\">quoteId</span> to the backend:<br>\\n\\n<p></p><pre>utils.api.cart.submitShippingQuote(quoteId, callback)</pre>\\n\\n <br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">quoteId</td>\\n    <td class=\\\"\\\">Number</td>\\n    <td class=\\\"\\\">ID for a shipping quote returned by <span class=\\\"inline-code\\\"><a href=\\\"#getShippingQuotes\\\">getShippingQuotes</a></span></td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n(For sample code, please see <b>getShippingQuotes and submitShippingQuote Example</b>, above.)<br><br>\\n\\n\\n<b>applyCode Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">applyCode</span> function applies a coupon code or gift certificate to the cart:<br>\\n\\n<p></p><pre>utils.api.cart.applyCode(code, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">code</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">Alphanumeric representation of the coupon or gift-certificate code</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\nIn the following example (from <span class=\\\"inline-code\\\">cart.js</span>),  <span class=\\\"inline-code\\\">applyCode</span> is called before the final if/else test to apply a coupon code:<br><p></p>\\n\\n<pre>    bindPromoCodeEvents() {\\n        const $couponContainer = $('.coupon-code');\\n        const $couponForm = $('.coupon-form');\\n        const $codeInput = $('[name=\\\"couponcode\\\"]', $couponForm);\\n\\n        $('.coupon-code-add').on('click', (event) => {\\n            event.preventDefault();\\n\\n            $(event.currentTarget).hide();\\n            $couponContainer.show();\\n            $('.coupon-code-cancel').show();\\n            $codeInput.focus();\\n        });\\n\\n        $('.coupon-code-cancel').on('click', (event) => {\\n            event.preventDefault();\\n\\n            $couponContainer.hide();\\n            $('.coupon-code-cancel').hide();\\n            $('.coupon-code-add').show();\\n        });\\n\\n        $couponForm.on('submit', (event) => {\\n            const code = $codeInput.val();\\n\\n            event.preventDefault();\\n\\n            // Empty code\\n            if (!code) {\\n                return alert($codeInput.data('error'));\\n            }\\n\\n            utils.api.cart.applyCode(code, (err, response) => {\\n                if (response.data.status === 'success') {\\n                    this.refreshContent();\\n                } else {\\n                    alert(response.data.errors.join('\\\\n'));\\n                }\\n            });\\n        });\\n    } </pre><p></p>\\n\\n\\n<h2> <A NAME=\\\"Cookie\\\"></a>Cookie Resource</h2>\\n\\nThis resource allows you to override a browser’s default alert box for cookie notifications.<br><p></p>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">privacyMessage</td>\\n    <td class=\\\"\\\">Merchant-defined message informing customers of storefront’s cookie usage (e.g., to comply with E.U. notification requirement)</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>Cookie Examples:</b> <br><p></p>\\n\\nThe following commented example (from <span class=\\\"inline-code\\\">global/cookieNotification.js)</span> shows a call to <span class=\\\"inline-code\\\">utils.hooks.on('cookie-privacy-notification', (event, privacyMessage)</span> to help comply with European Union privacy requirements:<br><p></p>\\n\\n<pre>/**\\n * European websites must notify users of cookies to comply with European Union law.\\n * This will alert shoppers that this website uses cookies.\\n */\\nexport default function () {\\n    /*\\n    // Here you can override the default browser alert box by hooking to the 'cookie-privacy-notification' hook.\\n    utils.hooks.on('cookie-privacy-notification', (event, privacyMessage) => {\\n        // You can make your own custom modal or alert box appear in your theme using the privacyMessage provided\\n        myCustomAlert(privacyMessage);\\n\\n        // Call event.preventDefault() to prevent the default browser alert from occurring in stencil-utils\\n        event.preventDefault();\\n    });\\n    */\\n\\n    utils.hooks.on('cookie-privacy-notification', (event) => {\\n        event.preventDefault();\\n\\n        const $privacyDialog = $('.cookieMessage');\\n        $privacyDialog.show();\\n\\n        $('body').on('click', '[data-privacy-accept]', () => {\\n            utils.hooks.emit('cookie-privacy-accepted');\\n            $privacyDialog.hide();\\n        });\\n    });\\n} </pre><p></p> \\n\\n\\n<h2> <A NAME=\\\"Countries\\\"></a>Countries Resources</h2>\\n\\nThese functions allow your theme or app to retrieve standardized country names, by numeric ID or by string.<br>\\n\\n<br><b>getById Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">getById</span> function retrieves standardized country names by numeric ID:<br>\\n\\n<p></p><pre>utils.api.countries.getById(countryId, callback)</pre>\\n\\n <br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">countryId</td>\\n    <td class=\\\"\\\">Number</td>\\n    <td class=\\\"\\\">Country code</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\nThe following example a call to <span class=\\\"inline-code\\\">getById</span>, followed by a call to the <span class=\\\"inline-code\\\">getByName</span> function (described below):<br><p></p>\\n\\n<pre>    /**\\n     *\\n     * Get country data by id wrapper\\n     *\\n     * @param {Number} id\\n     * @param {Function} callback\\n     */\\n    getById(id, callback) {\\n        const url = this.endpoint + id;\\n\\n        this.remoteRequest(url, 'GET', {}, callback);\\n    }\\n\\n    /**\\n     * Get country data by country name\\n     * @param name\\n     * @param callback\\n     */\\n    getByName(name, callback) {\\n        const url = this.endpoint + name;\\n\\n        this.remoteRequest(url, 'GET', {}, callback);\\n    }\\n}\\n </pre><br>\\n\\n\\n<b>getByName Signature</b><br>\\n\\nThe <span class=\\\"inline-code\\\">getByName</span> function retrieves states by country name, and returns an array of states that can be used in the callback:<br>\\n\\n<p></p><pre>utils.api.countries.getByName(countryName, callback)</pre>\\n\\n <br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">countryName</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">Country name</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\nIn the following example (from <span class=\\\"inline-code\\\">common/state-country.js</span>, <span class=\\\"inline-code\\\">getByName</span> is called after the initial if test:<br><p></p>\\n\\n<pre>    $('select[data-field-type=\\\"Country\\\"]').on('change', (event) => {\\n        const countryName = $(event.currentTarget).val();\\n\\n        if (countryName === '') {\\n            return;\\n        }\\n\\n        utils.api.country.getByName(countryName, (err, response) => {\\n            if (err) {\\n                alert(context.state_error);\\n\\n                return callback(err);\\n            }\\n\\n            const $currentInput = $('[data-field-type=\\\"State\\\"]');\\n\\n            if (!_.isEmpty(response.data.states)) {\\n                // The element may have been replaced with a select, reselect it\\n                const $selectElement = makeStateRequired($currentInput, context);\\n\\n                addOptions(response.data, $selectElement, options);\\n                callback(null, $selectElement);\\n            } else {\\n                const newElement = makeStateOptional($currentInput, context);\\n\\n                callback(null, newElement);\\n            }\\n        });\\n    }); </pre><p></p> \\n\\n\\n<h2> <A NAME=\\\"ProdAttrib\\\"></a>Product Attributes Resource</h2>\\n\\nThe <span class=\\\"inline-code\\\">optionChange</span> function is fired when the customer selects a product option for the current cart item (for example, changing a shirt’s color from a default \\\"yellow\\\" to \\\"green\\\"):<br><br>\\n\\n<b>optionChange Signature</b><br>\\n\\n<p></p><pre>utils.api.productAttributes.optionChange(productId, params, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">params</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Contains a collection of IDs that map to product properties (color, size, etc.)</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">productId</td>\\n    <td class=\\\"\\\">Number</td>\\n    <td class=\\\"\\\">ID for this product</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\n<b>optionChange Examples</b><br>\\n\\nIn this example (from <span class=\\\"inline-code\\\">common/product-details.js</span>), <span class=\\\"inline-code\\\">optionChange</span> is called to update options in a Quick View modal:<br><p></p>\\n\\n<pre>        // Update product attributes. If we're in quick view and the product has options, then also update the initial view in case items are oos\\n        if (_.isEmpty(productAttributesData) && hasOptions) {\\n            const $productId = $('[name=\\\"product_id\\\"]', $form).val();\\n\\n            utils.api.productAttributes.optionChange($productId, $form.serialize(), (err, response) => {\\n                const attributesData = response.data || {};\\n\\n                this.updateProductAttributes(attributesData);\\n                this.updateView(attributesData);\\n            });\\n        } else {\\n            this.updateProductAttributes(productAttributesData);\\n        } </pre><p></p>\\n\\n\\nIn this example (from <span class=\\\"inline-code\\\">cart.js</span>), <span class=\\\"inline-code\\\">optionChange</span> is called before the final if test:<br><p></p>\\n\\n<pre>    cartEditOptions(itemId) {\\n        const modal = defaultModal();\\n        const options = {\\n            template: 'cart/modals/configure-product',\\n        };\\n\\n        modal.open();\\n\\n        utils.api.productAttributes.configureInCart(itemId, options, (err, response) => {\\n            modal.updateContent(response.content);\\n\\n            this.bindGiftWrappingForm();\\n        });\\n\\n        utils.hooks.on('product-option-change', (event, option) => {\\n            const $changedOption = $(option);\\n            const $form = $changedOption.parents('form');\\n            const $submit = $('input.button', $form);\\n            const $messageBox = $('.alertMessageBox');\\n            const item = $('[name=\\\"item_id\\\"]', $form).attr('value');\\n\\n            utils.api.productAttributes.optionChange(item, $form.serialize(), (err, result) => {\\n                const data = result.data || {};\\n\\n                if (err) {\\n                    alert(err);\\n                    return false;\\n                }  </pre><p></p>\\n\\n\\n<h2> <A NAME=\\\"Product\\\"></a>Product Resource</h2>\\n\\nThe <span class=\\\"inline-code\\\">product.getById</span> function allows your code to retrieve, and to present, detailed product information by product ID.<br>\\n\\n<br><b>getById Signature</b><br>\\n\\n<p></p><pre>utils.api.product.getById(productId, params, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">productId</td>\\n    <td class=\\\"\\\">Number</td>\\n    <td class=\\\"\\\">ID for this product</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">params</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Contains request options and/or presentation template</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody></table>\\n\\n\\nThe following example (from <span class=\\\"inline-code\\\">global/quick-view.js</span>) calls <span class=\\\"inline-code\\\">product.getById</span> to populate the Quick View modal:<br><p></p>\\n\\n<pre>    $('body').on('click', '.quickview', (event) => {\\n        event.preventDefault();\\n\\n        const productId = $(event.currentTarget).data('product-id');\\n\\n        modal.open({ size: 'large' });\\n\\n        utils.api.product.getById(productId, { template: 'products/quick-view' }, (err, response) => {\\n            modal.updateContent(response);\\n\\n            modal.$content.find('.productView').addClass('productView--quickView');\\n\\n            return new ProductDetails(modal.$content.find('.quickView'), context);\\n        });\\n    }); </pre><p></p>\\n\\n\\n<h2> <A NAME=\\\"Search\\\"></a>Search Resource</h2>\\n\\nThe <span class=\\\"inline-code\\\">search</span> function allows you to present a customized user interface for search results.<br>\\n\\n<br><b>search Signature</b><br>\\n\\n<p></p><pre>utils.api.search.search(query, params, callback)</pre>\\n<br>\\n\\n<table>\\n  <tbody><tr>\\n    <td class=\\\"\\\">Argument</td>\\n    <td class=\\\"\\\">Type</td>\\n    <td class=\\\"\\\">Description/Usage</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">query</td>\\n    <td class=\\\"\\\">String</td>\\n    <td class=\\\"\\\">Contains the customer’s search query</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">params</td>\\n    <td class=\\\"\\\">Object</td>\\n    <td class=\\\"\\\">Contains request options and/or presentation template</td>\\n  </tr>\\n  <tr>\\n    <td class=\\\"\\\">callback</td>\\n    <td class=\\\"\\\">Function</td>\\n    <td class=\\\"\\\">Asynchronous function call to handle the results</td>\\n  </tr>\\n</tbody>\\n</table>\"\n}\n[/block]\n**Code Example – Template as params**\n\nThe following example (from `/assets/js/theme/global/quick-search.js`) shows how to pass a template as the `search` function's `params` argument:\n\n```\nutils.api.search.search(searchQuery, { template: 'search/quick-results' }, (err, response) => {\n    if (err) {\n        return false;\n    }\n\n    $quickSearchResults.html(response);\n});\n```\n\nAs its `params` argument, the above example passes a \"quick results\" presentation template located in the theme's `templates/components/` subdirectory. (This convention is documented above for the [`getPage` function](#getpage)'s `options` argument.)\n\n\n**Code Example – Limit as params**\n\nThe following example shows how to pass a limit as the `search` function's `params` argument:\n\n```\nutils.api.search.search({searchQuery, limit: 5});\n```\n\nThe above instance passes a limit of five search results.","excerpt":"","slug":"stencil-utils-api-reference","type":"basic","title":"stencil-utils API Reference"}

stencil-utils API Reference


[block:html] { "html": "<A NAME=\"stencil-utils-ref\"></a>The following listings cover the Stencil functions that your client-side JavaScript can call outside Handlebars conventions:<br>\n\n<ul>\n <li><a href=\"#API-js\">API [api.js]</a></li>\n <li><a href=\"#Cart-API\">Cart API</a></li>\n <li><a href=\"#Cookie\">Cookie Resource</a></li>\n <li><a href=\"#Countries\">Countries Resource</a></li>\n <li><a href=\"#ProdAttrib\">Product Attributes Resource</a></li>\n <li><a href=\"#Product\">Product Resource</a></li>\n <li><a href=\"#Search\">Search Resource</a></li>\n</ul> \n\nThese functions help you set up asynchronous requests to modify the customer’s cart or storefront view. By using this abstraction library, you can gain more-granular control over themes’ presentation." } [/block] [block:callout] { "type": "warning", "title": "Finding Example Code", "body": "Examples on this page are from Stencil's Cornerstone base theme. The base path for all listed examples is: `/cornerstone/assets/js/theme/`." } [/block] [block:html] { "html": "<h2> <A NAME=\"API-js\"></a>API [api.js]</h2>\n\nThe <span class=\"inline-code\">api.getPage()</span> function allows you to add Ajax functionality to your themes.<br>\n\n<br> <span id=\"getpage\"> <b>getPage Signature</b> </span> <br>\n\nThe following statement passes <span class=\"inline-code\">url</span> and <span class=\"inline-code\">options</span> arguments to the <span class=\"inline-code\">api.getPage()</span> function:<br><p></p>\n\n<pre>utils.api.getPage(url, options, callback)\n</pre><br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">url</td>\n <td class=\"\">String</td>\n <td class=\"\">URL to which you want to send a request (for example: localhost:4000/cart.php)</td>\n </tr>\n <tr>\n <td class=\"\">options</td>\n <td class=\"\">Object</td>\n <td class=\"\">Can contain <span class=\"inline-code\">template</span>, <span class=\"inline-code\"><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\">FormData</a></span> (for POST methods), <span class=\"inline-code\">params</span>&nbsp;(for GET methods), and/or <span class=\"inline-code\">config</span>. <br><br> \n The <span class=\"inline-code\">template</span> option allows you to select a particular template, or an array of templates, for rendering one page. Each value must correspond to a file present in the theme's <span class=\"inline-code\">templates/components/</span> subdirectory. <br><br>\n The <span class=\"inline-code\">config</span> option can be used to pass extra resources, corresponding to attributes that are valid in a page's <a href=\"/docs/using-yaml-front-matter\">front matter</a>, as an object.\n </td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\nThe <span class=\"inline-code\">config</span> argument works like front matter: it encapsulates JSON. For a usage example of <span class=\"inline-code\">config</span>, see <NOBR><a href=\"/docs/remote-api-example\">Remote API Example</a></nobr>. <br><br>\n\n\n<span id=\"getPageEx\"> <b>getPage Example</b> </span> <br>\n\nIn the following example (from <span class=\"inline-code\">common/faceted-search.js</span>), <span class=\"inline-code\">api.getPage()</span> is called to help execute an <span class=\"inline-code\">updateView()</span> function:<br><p></p>\n\n<pre> updateView() {\n $(this.options.blockerSelector).show();\n\n api.getPage(urlUtils.getUrl(), this.requestOptions, (err, content) => {\n $(this.options.blockerSelector).hide();\n\n if (err) {\n throw new Error(err);\n }\n\n // Refresh view with new content\n this.refreshView(content);\n });\n }</pre><p></p>\n\n\n<h2> <A NAME=\"Cart-API\"></a>Cart API </h2>\n\nThe following functions allow your theme to work with cart contents in customized ways.<br><br>\n\n<b>itemAdd Signature</b><br>\n\nThe <span class=\"inline-code\">itemAdd</span> function allows your code to add an item to the cart, with options:<br><p></p>\n\n<pre>utils.api.cart.itemAdd(<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\">FormData</a>, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\"><A NAME=\"CartAPI-FormData\"></a>formData</td>\n <td class=\"\"><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/FormData\">FormData</a> object </td>\n <td class=\"\">Contains all details about the added item and its product options</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<span id=\"itemAddEx\"> <b>itemAdd Example</b> </span> <br>\n\n<span class=\"inline-code\">itemAdd</span> is called at the head of the following example (from <span class=\"inline-code\">common/product-details.js</span>) to populate the cart:<br><p></p>\n\n<pre> // Add item to cart\n utils.api.cart.itemAdd(new FormData(form), (err, response) => {\n const errorMessage = err || response.data.error;\n\n $addToCartBtn\n .val(originalBtnVal)\n .prop('disabled', false);\n\n this.$overlay.hide();\n\n // Guard statement\n if (errorMessage) {\n // Strip the HTML from the error message\n const tmp = document.createElement('DIV');\n tmp.innerHTML = errorMessage;\n\n return alert(tmp.textContent || tmp.innerText);\n }\n\n // Open preview modal and update content\n if (this.previewModal) {\n this.previewModal.open();\n\n this.updateCartContent(this.previewModal, response.data.cart_item.hash);\n } else {\n this.$overlay.show();\n // if no modal, redirect to the cart page\n this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);\n }\n }); </pre><br>\n\n\n<b>itemUpdate Signature</b><br>\n\nThe <span class=\"inline-code\">itemUpdate</span> function allows your code to update a specified cart item’s quantity:<br>\n\n<p></p><pre>utils.api.cart.itemUpdate(itemId, qty, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">itemId</td>\n <td class=\"\">String</td>\n <td class=\"\">The item’s ID</td>\n </tr>\n <tr>\n <td class=\"\">qty</td>\n <td class=\"\">Integer</td>\n <td class=\"\">The item’s quantity in the cart</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n<span id=\"itemUpdateEx\"> <b>itemUpdate Example</b> </span> <br>\n\nIn the following example (from <span class=\"inline-code\">cart.js</span>), <span class=\"inline-code\">itemUpdate</span> is called just before the final if/else test for an empty cart:<br><p></p>\n\n<pre> cartUpdate($target) {\n const itemId = $target.data('cart-itemid');\n const $el = $(`#qty-${itemId}`);\n const oldQty = parseInt($el.val(), 10);\n const maxQty = parseInt($el.data('quantity-max'), 10);\n const minQty = parseInt($el.data('quantity-min'), 10);\n const minError = $el.data('quantity-min-error');\n const maxError = $el.data('quantity-max-error');\n const newQty = $target.data('action') === 'inc' ? oldQty + 1 : oldQty - 1;\n\n // Does not quality for min/max quantity\n if (newQty < minQty) {\n return alert(minError);\n } else if (maxQty > 0 && newQty > maxQty) {\n return alert(maxError);\n }\n\n this.$overlay.show();\n\n utils.api.cart.itemUpdate(itemId, newQty, (err, response) => {\n this.$overlay.hide();\n\n if (response.data.status === 'succeed') {\n // if the quantity is changed \"1\" from \"0\", we have to remove the row.\n const remove = (newQty === 0);\n\n this.refreshContent(remove);\n } else {\n $el.val(oldQty);\n alert(response.data.errors.join('\\n'));\n }\n });\n } </pre><br>\n\n\n<b>itemRemove Signature</b><br>\n\nThe <span class=\"inline-code\">itemRemove</span> function allows your code to remove items from the cart:<br>\n\n<p></p><pre>utils.api.cart.itemRemove(itemId, callback)</pre>\n <br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">itemId</td>\n <td class=\"\">String</td>\n <td class=\"\">The item’s ID</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<span id=\"itemRemoveEx\"> <b>itemRemove Example</b> </span><br>\n\nIn the following example (from <span class=\"inline-code\">cart.js</span>), <span class=\"inline-code\">itemRemove</span> is called before the if/else test:<br><p></p>\n\n<pre> cartRemoveItem(itemId) {\n this.$overlay.show();\n utils.api.cart.itemRemove(itemId, (err, response) => {\n if (response.data.status === 'succeed') {\n this.refreshContent(true);\n } else {\n alert(response.data.errors.join('\\n'));\n }\n });\n } </pre><br>\n\n\n<b>update Signature</b><br>\n\nThe <span class=\"inline-code\">update</span> function allows your code to update the set of items in the cart:<br>\n\n<p></p><pre>utils.api.cart.update(itemId, qty, callback)</pre>\n\n <br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">items</td>\n <td class=\"\">Array</td>\n <td class=\"\">The items in the cart</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<b>update Example</b><br>\n\nThe following example shows a call to <span class=\"inline-code\">update</span> within the <span class=\"inline-code\">itemUpdate</span> function:<br><p></p>\n\n<pre> /**\n itemUpdate(itemId, qty, callback) {\n let callbackArg = callback;\n let items;\n\n if (Array.isArray(itemId) && typeof qty === 'function') {\n callbackArg = qty;\n items = itemId;\n } else {\n items = [\n {\n id: itemId,\n quantity: qty,\n },\n ];\n }\n\n this.update(items, (err, response) => {\n const emitData = {\n items,\n err,\n response,\n };\n\n Hooks.emit('cart-item-update-remote', emitData);\n callbackArg(err, response);\n });\n } </pre><br>\n\n\n<b>getItemGiftWrappingOptions Signature</b><br>\n\nThe <span class=\"inline-code\">getItemGiftWrappingOptions</span> function allows your code to retrieve gift-wrapping options for the current cart item, in customized ways:<br><p></p>\n\n\n<pre>utils.api.cart.getItemGiftWrappingOptions(itemId, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">itemId</td>\n <td class=\"\">String</td>\n <td class=\"\">The cart item</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<b>getItemGiftWrappingOptions Example</b> <br>\n\nThe following example (from <span class=\"inline-code\">cart.js</span>) calls <span class=\"inline-code\">getItemGiftWrappingOptions</span> to display gift-wrapping options in a modal:<br><p></p>\n\n<pre> bindGiftWrappingEvents() {\n const modal = defaultModal();\n\n $('[data-item-giftwrap]').on('click', (event) => {\n const itemId = $(event.currentTarget).data('item-giftwrap');\n const options = {\n template: 'cart/modals/gift-wrapping-form',\n };\n\n event.preventDefault();\n\n modal.open();\n\n utils.api.cart.getItemGiftWrappingOptions(itemId, options, (err, response) => {\n modal.updateContent(response.content);\n\n this.bindGiftWrappingForm();\n });\n });\n } </pre><br>\n\n\n<b>submitItemGiftWrappingOption Signature</b><br>\n\nThe <span class=\"inline-code\">submitItemGiftWrappingOption</span> function allows your code to handle the customer’s gift-wrapping selection for the current cart item:<br><p></p>\n\n<pre>utils.api.cart.submitItemGiftWrappingOption(itemId, qty, callback)</pre>\n<br>\n\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">itemId</td>\n <td class=\"\">String</td>\n <td class=\"\">The cart item</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<b>submitItemGiftWrappingOption Example</b> <br>\n\nThis commented example shows a simple call to <span class=\"inline-code\">submitItemGiftWrappingOption</span>:\n\n<pre> /**\n * Submit giftwrapping options\n *\n * @param {String} itemId\n * @param {Function} callback\n */\n submitItemGiftWrappingOption(itemId, params, callback) {\n this.remoteRequest(`/gift-wrapping/${itemId}`, 'POST', { params }, callback);\n } </pre><br>\n\n\n<b>getContent Signature</b><br>\n\nThe <span class=\"inline-code\">getContent</span> function allows your code to display the cart contents in customized ways:<br>\n\n<p></p><pre>utils.api.cart.getContent(options, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\"><A NAME=\"getContent-options\"></a>options</td>\n <td class=\"\">Object</td>\n <td class=\"\">Template containing content and totals children</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n<span id=\"getContentEx\"> <b>getContent Examples</b> </span> <br>\n\nThe following example (from <span class=\"inline-code\">common/product-details.js</span>) a call to <span class=\"inline-code\">getContent</span>, set up by a prior call to <span class=\"inline-code\">getCartContent</span>:<br><p></p>\n\n<pre> /**\n * Get cart contents\n *\n * @param {String} cartItemHash\n * @param {Function} onComplete\n */\n getCartContent(cartItemHash, onComplete) {\n const options = {\n template: 'cart/preview',\n params: {\n suggest: cartItemHash,\n },\n config: {\n cart: {\n suggestions: {\n limit: 4,\n },\n },\n },\n };\n\n utils.api.cart.getContent(options, onComplete);\n } </pre><p></p>\n\nThis example (from <span class=\"inline-code\">cart.js</span>) shows a call to <span class=\"inline-code\">getContent</span> within the <span class=\"inline-code\">refreshContent</span> function:<br><p></p>\n\n<pre> refreshContent(remove) {\n const $cartItemsRows = $('[data-item-row]', this.$cartContent);\n const $cartPageTitle = $('[data-cart-page-title]');\n const options = {\n template: {\n content: 'cart/content',\n totals: 'cart/totals',\n pageTitle: 'cart/page-title',\n statusMessages: 'cart/status-messages',\n },\n };\n\n this.$overlay.show();\n\n // Remove last item from cart? Reload\n if (remove && $cartItemsRows.length === 1) {\n return window.location.reload();\n }\n\n utils.api.cart.getContent(options, (err, response) => {\n this.$cartContent.html(response.content);\n this.$cartTotals.html(response.totals);\n this.$cartMessages.html(response.statusMessages);\n\n $cartPageTitle.replaceWith(response.pageTitle);\n this.bindEvents();\n this.$overlay.hide();\n\n const quantity = $('[data-cart-quantity]', this.$cartContent).data('cart-quantity') || 0;\n\n $('body').trigger('cart-quantity-update', quantity);\n });\n } </pre><p></p> \n\nHere is a final example of a call to <span class=\"inline-code\">getContent</span>, from <span class=\"inline-code\">global/cart-preview.js</span>:<br><p></p>\n\n<pre> $cart.on('click', (event) => {\n const options = {\n template: 'common/cart-preview',\n };\n\n // Redirect to full cart page\n //\n // https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent\n // In summary, we recommend looking for the string 'Mobi' anywhere in the User Agent to detect a mobile device.\n if (/Mobi/i.test(navigator.userAgent)) {\n return event.stopPropagation();\n }\n\n event.preventDefault();\n\n $cartDropdown\n .addClass(loadingClass)\n .html($cartLoading);\n $cartLoading\n .show();\n\n utils.api.cart.getContent(options, (err, response) => {\n $cartDropdown\n .removeClass(loadingClass)\n .html(response);\n $cartLoading\n .hide();\n });\n }); </pre><br>\n\n\n<b><A NAME=\"getShippingQuotes\"></a>getShippingQuotes Signature</b><br>\n\nThe <span class=\"inline-code\">getShippingQuotes</span> function allows your code to retrieve shipping-cost quotes for the cart’s contents. It returns <span class=\"inline-code\">shippingQuote</span> objects that contain IDs. You must follow <span class=\"inline-code\">getShippingQuotes</span> by calling <span class=\"inline-code\"><a href=\"#submitShippingQuotes\">submitShippingQuote</a></span> on a <span class=\"inline-code\">quoteId</span>:<br>\n\n<p></p><pre>utils.api.cart.getShippingQuotes(params, renderWith, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">params</td>\n <td class=\"\">Object</td>\n <td class=\"\">Contains country_id, state_id, and zip_code</td>\n </tr>\n <tr>\n <td class=\"\">template</td>\n <td class=\"\">String/  Array/ Object</td>\n <td class=\"\">The template to use for rendering</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<b>getShippingQuotes and submitShippingQuote Example</b> <br><p></p>\n\nThe following example (from <span class=\"inline-code\">cart/shipping-estimator.js</span>) shows calls to both <span class=\"inline-code\">getShippingQuotes</span> and <span class=\"inline-code\">submitShippingQuote</span>:<br><p></p>\n\n<pre> bindEstimatorEvents() {\n const $estimatorContainer = $('.shipping-estimator');\n const $estimatorForm = $('.estimator-form');\n\n $estimatorForm.on('submit', (event) => {\n const params = {\n country_id: $('[name=\"shipping-country\"]', $estimatorForm).val(),\n state_id: $('[name=\"shipping-state\"]', $estimatorForm).val(),\n city: $('[name=\"shipping-city\"]', $estimatorForm).val(),\n zip_code: $('[name=\"shipping-zip\"]', $estimatorForm).val(),\n };\n\n event.preventDefault();\n\n utils.api.cart.getShippingQuotes(params, 'cart/shipping-quotes', (err, response) => {\n $('.shipping-quotes').html(response.content);\n\n // bind the select button\n $('.select-shipping-quote').on('click', (clickEvent) => {\n const quoteId = $('.shipping-quote:checked').val();\n\n clickEvent.preventDefault();\n\n utils.api.cart.submitShippingQuote(quoteId, () => {\n location.reload();\n });\n });\n });\n }); </pre><br>\n\n<A NAME=\"submitShippingQuote\"></a> <b>submitShippingQuote Signature</b><br>\n\nThe <span class=\"inline-code\">submitShippingQuote</span> function must be called after <span class=\"inline-code\"><a href=\"#getShippingQuotes\">getShippingQuote</a></span>, which returns <span class=\"inline-code\">shippingQuote</span> objects that contain IDs. The cart page renders the shipping quotes. When the user selects one of the quotes, this function sends that <span class=\"inline-code\">quoteId</span> to the backend:<br>\n\n<p></p><pre>utils.api.cart.submitShippingQuote(quoteId, callback)</pre>\n\n <br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">quoteId</td>\n <td class=\"\">Number</td>\n <td class=\"\">ID for a shipping quote returned by <span class=\"inline-code\"><a href=\"#getShippingQuotes\">getShippingQuotes</a></span></td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n(For sample code, please see <b>getShippingQuotes and submitShippingQuote Example</b>, above.)<br><br>\n\n\n<b>applyCode Signature</b><br>\n\nThe <span class=\"inline-code\">applyCode</span> function applies a coupon code or gift certificate to the cart:<br>\n\n<p></p><pre>utils.api.cart.applyCode(code, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">code</td>\n <td class=\"\">String</td>\n <td class=\"\">Alphanumeric representation of the coupon or gift-certificate code</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\nIn the following example (from <span class=\"inline-code\">cart.js</span>), <span class=\"inline-code\">applyCode</span> is called before the final if/else test to apply a coupon code:<br><p></p>\n\n<pre> bindPromoCodeEvents() {\n const $couponContainer = $('.coupon-code');\n const $couponForm = $('.coupon-form');\n const $codeInput = $('[name=\"couponcode\"]', $couponForm);\n\n $('.coupon-code-add').on('click', (event) => {\n event.preventDefault();\n\n $(event.currentTarget).hide();\n $couponContainer.show();\n $('.coupon-code-cancel').show();\n $codeInput.focus();\n });\n\n $('.coupon-code-cancel').on('click', (event) => {\n event.preventDefault();\n\n $couponContainer.hide();\n $('.coupon-code-cancel').hide();\n $('.coupon-code-add').show();\n });\n\n $couponForm.on('submit', (event) => {\n const code = $codeInput.val();\n\n event.preventDefault();\n\n // Empty code\n if (!code) {\n return alert($codeInput.data('error'));\n }\n\n utils.api.cart.applyCode(code, (err, response) => {\n if (response.data.status === 'success') {\n this.refreshContent();\n } else {\n alert(response.data.errors.join('\\n'));\n }\n });\n });\n } </pre><p></p>\n\n\n<h2> <A NAME=\"Cookie\"></a>Cookie Resource</h2>\n\nThis resource allows you to override a browser’s default alert box for cookie notifications.<br><p></p>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">privacyMessage</td>\n <td class=\"\">Merchant-defined message informing customers of storefront’s cookie usage (e.g., to comply with E.U. notification requirement)</td>\n </tr>\n</tbody></table>\n\n\n<b>Cookie Examples:</b> <br><p></p>\n\nThe following commented example (from <span class=\"inline-code\">global/cookieNotification.js)</span> shows a call to <span class=\"inline-code\">utils.hooks.on('cookie-privacy-notification', (event, privacyMessage)</span> to help comply with European Union privacy requirements:<br><p></p>\n\n<pre>/**\n * European websites must notify users of cookies to comply with European Union law.\n * This will alert shoppers that this website uses cookies.\n */\nexport default function () {\n /*\n // Here you can override the default browser alert box by hooking to the 'cookie-privacy-notification' hook.\n utils.hooks.on('cookie-privacy-notification', (event, privacyMessage) => {\n // You can make your own custom modal or alert box appear in your theme using the privacyMessage provided\n myCustomAlert(privacyMessage);\n\n // Call event.preventDefault() to prevent the default browser alert from occurring in stencil-utils\n event.preventDefault();\n });\n */\n\n utils.hooks.on('cookie-privacy-notification', (event) => {\n event.preventDefault();\n\n const $privacyDialog = $('.cookieMessage');\n $privacyDialog.show();\n\n $('body').on('click', '[data-privacy-accept]', () => {\n utils.hooks.emit('cookie-privacy-accepted');\n $privacyDialog.hide();\n });\n });\n} </pre><p></p> \n\n\n<h2> <A NAME=\"Countries\"></a>Countries Resources</h2>\n\nThese functions allow your theme or app to retrieve standardized country names, by numeric ID or by string.<br>\n\n<br><b>getById Signature</b><br>\n\nThe <span class=\"inline-code\">getById</span> function retrieves standardized country names by numeric ID:<br>\n\n<p></p><pre>utils.api.countries.getById(countryId, callback)</pre>\n\n <br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">countryId</td>\n <td class=\"\">Number</td>\n <td class=\"\">Country code</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\nThe following example a call to <span class=\"inline-code\">getById</span>, followed by a call to the <span class=\"inline-code\">getByName</span> function (described below):<br><p></p>\n\n<pre> /**\n *\n * Get country data by id wrapper\n *\n * @param {Number} id\n * @param {Function} callback\n */\n getById(id, callback) {\n const url = this.endpoint + id;\n\n this.remoteRequest(url, 'GET', {}, callback);\n }\n\n /**\n * Get country data by country name\n * @param name\n * @param callback\n */\n getByName(name, callback) {\n const url = this.endpoint + name;\n\n this.remoteRequest(url, 'GET', {}, callback);\n }\n}\n </pre><br>\n\n\n<b>getByName Signature</b><br>\n\nThe <span class=\"inline-code\">getByName</span> function retrieves states by country name, and returns an array of states that can be used in the callback:<br>\n\n<p></p><pre>utils.api.countries.getByName(countryName, callback)</pre>\n\n <br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">countryName</td>\n <td class=\"\">String</td>\n <td class=\"\">Country name</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\nIn the following example (from <span class=\"inline-code\">common/state-country.js</span>, <span class=\"inline-code\">getByName</span> is called after the initial if test:<br><p></p>\n\n<pre> $('select[data-field-type=\"Country\"]').on('change', (event) => {\n const countryName = $(event.currentTarget).val();\n\n if (countryName === '') {\n return;\n }\n\n utils.api.country.getByName(countryName, (err, response) => {\n if (err) {\n alert(context.state_error);\n\n return callback(err);\n }\n\n const $currentInput = $('[data-field-type=\"State\"]');\n\n if (!_.isEmpty(response.data.states)) {\n // The element may have been replaced with a select, reselect it\n const $selectElement = makeStateRequired($currentInput, context);\n\n addOptions(response.data, $selectElement, options);\n callback(null, $selectElement);\n } else {\n const newElement = makeStateOptional($currentInput, context);\n\n callback(null, newElement);\n }\n });\n }); </pre><p></p> \n\n\n<h2> <A NAME=\"ProdAttrib\"></a>Product Attributes Resource</h2>\n\nThe <span class=\"inline-code\">optionChange</span> function is fired when the customer selects a product option for the current cart item (for example, changing a shirt’s color from a default \"yellow\" to \"green\"):<br><br>\n\n<b>optionChange Signature</b><br>\n\n<p></p><pre>utils.api.productAttributes.optionChange(productId, params, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">params</td>\n <td class=\"\">Object</td>\n <td class=\"\">Contains a collection of IDs that map to product properties (color, size, etc.)</td>\n </tr>\n <tr>\n <td class=\"\">productId</td>\n <td class=\"\">Number</td>\n <td class=\"\">ID for this product</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\n<b>optionChange Examples</b><br>\n\nIn this example (from <span class=\"inline-code\">common/product-details.js</span>), <span class=\"inline-code\">optionChange</span> is called to update options in a Quick View modal:<br><p></p>\n\n<pre> // Update product attributes. If we're in quick view and the product has options, then also update the initial view in case items are oos\n if (_.isEmpty(productAttributesData) && hasOptions) {\n const $productId = $('[name=\"product_id\"]', $form).val();\n\n utils.api.productAttributes.optionChange($productId, $form.serialize(), (err, response) => {\n const attributesData = response.data || {};\n\n this.updateProductAttributes(attributesData);\n this.updateView(attributesData);\n });\n } else {\n this.updateProductAttributes(productAttributesData);\n } </pre><p></p>\n\n\nIn this example (from <span class=\"inline-code\">cart.js</span>), <span class=\"inline-code\">optionChange</span> is called before the final if test:<br><p></p>\n\n<pre> cartEditOptions(itemId) {\n const modal = defaultModal();\n const options = {\n template: 'cart/modals/configure-product',\n };\n\n modal.open();\n\n utils.api.productAttributes.configureInCart(itemId, options, (err, response) => {\n modal.updateContent(response.content);\n\n this.bindGiftWrappingForm();\n });\n\n utils.hooks.on('product-option-change', (event, option) => {\n const $changedOption = $(option);\n const $form = $changedOption.parents('form');\n const $submit = $('input.button', $form);\n const $messageBox = $('.alertMessageBox');\n const item = $('[name=\"item_id\"]', $form).attr('value');\n\n utils.api.productAttributes.optionChange(item, $form.serialize(), (err, result) => {\n const data = result.data || {};\n\n if (err) {\n alert(err);\n return false;\n } </pre><p></p>\n\n\n<h2> <A NAME=\"Product\"></a>Product Resource</h2>\n\nThe <span class=\"inline-code\">product.getById</span> function allows your code to retrieve, and to present, detailed product information by product ID.<br>\n\n<br><b>getById Signature</b><br>\n\n<p></p><pre>utils.api.product.getById(productId, params, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">productId</td>\n <td class=\"\">Number</td>\n <td class=\"\">ID for this product</td>\n </tr>\n <tr>\n <td class=\"\">params</td>\n <td class=\"\">Object</td>\n <td class=\"\">Contains request options and/or presentation template</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody></table>\n\n\nThe following example (from <span class=\"inline-code\">global/quick-view.js</span>) calls <span class=\"inline-code\">product.getById</span> to populate the Quick View modal:<br><p></p>\n\n<pre> $('body').on('click', '.quickview', (event) => {\n event.preventDefault();\n\n const productId = $(event.currentTarget).data('product-id');\n\n modal.open({ size: 'large' });\n\n utils.api.product.getById(productId, { template: 'products/quick-view' }, (err, response) => {\n modal.updateContent(response);\n\n modal.$content.find('.productView').addClass('productView--quickView');\n\n return new ProductDetails(modal.$content.find('.quickView'), context);\n });\n }); </pre><p></p>\n\n\n<h2> <A NAME=\"Search\"></a>Search Resource</h2>\n\nThe <span class=\"inline-code\">search</span> function allows you to present a customized user interface for search results.<br>\n\n<br><b>search Signature</b><br>\n\n<p></p><pre>utils.api.search.search(query, params, callback)</pre>\n<br>\n\n<table>\n <tbody><tr>\n <td class=\"\">Argument</td>\n <td class=\"\">Type</td>\n <td class=\"\">Description/Usage</td>\n </tr>\n <tr>\n <td class=\"\">query</td>\n <td class=\"\">String</td>\n <td class=\"\">Contains the customer’s search query</td>\n </tr>\n <tr>\n <td class=\"\">params</td>\n <td class=\"\">Object</td>\n <td class=\"\">Contains request options and/or presentation template</td>\n </tr>\n <tr>\n <td class=\"\">callback</td>\n <td class=\"\">Function</td>\n <td class=\"\">Asynchronous function call to handle the results</td>\n </tr>\n</tbody>\n</table>" } [/block] **Code Example – Template as params** The following example (from `/assets/js/theme/global/quick-search.js`) shows how to pass a template as the `search` function's `params` argument: ``` utils.api.search.search(searchQuery, { template: 'search/quick-results' }, (err, response) => { if (err) { return false; } $quickSearchResults.html(response); }); ``` As its `params` argument, the above example passes a "quick results" presentation template located in the theme's `templates/components/` subdirectory. (This convention is documented above for the [`getPage` function](#getpage)'s `options` argument.) **Code Example – Limit as params** The following example shows how to pass a limit as the `search` function's `params` argument: ``` utils.api.search.search({searchQuery, limit: 5}); ``` The above instance passes a limit of five search results.