Access Model and Collection Data in a Child View

This tutorial describes how to add the detailed description of each item to a search results page. The detailed description of an item contains HTML that is typically only displayed on the product details page (PDP). But, in this tutorial, you learn how to develop an extension that displays item descriptions when a shopper is viewing items on the product list page (PLP).

Note:

The procedures in this tutorial require extensibility API classes that are only available with SuiteCommerce and SuiteCommerce Advanced 2020.2 and later releases. For more information, see the extensibility API reference.

Read the following sections to prepare for and then complete the tutorial:

contextData and contextDataRequest Properties

The key capabilities you are using in this tutorial are the contextData and contextDataRequest properties:

  • contextData is a property of every view, but it is only populated with data in some of those views.

  • contextDataRequest is a property available to views that are children of views with contextData. You can call contextDataRequest by passing in an array of types of data you want returned.

Views can return four types of objects and each view may support multiple object types. The object types that a view can return is specific to each view class. However, most views do not support requests.

When requests are supported and a data object is returned, its values are specific to the view instance. For example, if you are working on a product details page (PDP), contextData potentially supports requests for the product and item model. Whether contextData supports requests for both the product and item model, or just one of those models, depends on the particular product page the user is viewing.

The following table lists the parent view classes that have contextData properties and also lists the types of data that they can provide to child views.

contextData Object

Class Availability

Information Returned

category

Facets.Browse.View

The category model

item

ItemRelations.RelatedItem.View

Facets.ItemCell.View

ProductDetails.Base.View

The item model

itemlist

Facets.Browse.View

An object that contains the item collection

product

ProductDetails.Base.View

The parent model for a product, which also contains the item model

Keep in mind that the availability shown in the preceding table cascades, which means that you do not have to add your child view directly into the classes listed. If your child view has a parent, grandparent, and so on, that is listed in the preceding table, contextDataRequest will be available.

Important:

Remember that contextData is only populated with data in the view classes listed in the preceding table and in the child views of the listed view classes.

Practices to Avoid

When working with current releases of SuiteCommerce and SuiteCommerce Advanced, avoid the following practices when developing extensions.

Practice

Description

Do not add a child view by extending the childViews property.

In older SCA versions, it was common to extend the childViews property of a view and then add your view as an additional property. This practice works for older SCA versions that do not support the extensibility API, but it is not recommended for current SCA versions as it does not produce a sustainable and stable extension. This approach also requires adding the view as a dependency to your file, which is not permitted for core modules. For more information, see Extensibility Layer Safe Mode in the Extensions Subtab configuration property reference.

Avoid customizing the template in the theme

For sites that use a managed theme, you cannot customize any of the theme’s files. In general, you should not customize a theme’s template files to implement new pieces of functionality. When developing an extension like the one in this tutorial, the goal is to add new information into your site’s pages while leaving existing information intact. There is no reason to modify any existing code to facilitate that, including templates. Developing an extension like the one in this tutorial is the best way to ensure your customization remains stable across different sites and different versions.

Prerequisites

Before you can complete this tutorial, you need to:

To develop an extension to access model and collection data in a child view

  1. Expose the Field to the Relevant Field Set.

  2. Create the Extension Framework.

  3. Use the PLP component’s addChildViews() method in your entry point file to target an existing view into which you can inject your customized view. See Create the Entry Point File for instructions.

  4. Create a custom view using SCView that:

    1. Requests item context data from the parent view.

    2. Accesses the contextData object with contextDataRequest, passing the required field through to the template context.

    3. Conditionally renders the child view if, and only if, the shopper is viewing the page using the List display type.

    See Create the View File for instructions.

  5. Create the Template that renders the detailed description, which can include HTML.

  6. Test the Extension.

  7. Troubleshoot the Extension.

Expose the Field to the Relevant Field Set

Before you start to work with the code for this extension, you need to have the field you want included in the items API response. For this tutorial scenario, you are dealing with search results on a product list page (PLP) that use the (default) search field set. So, add a standard field called Detailed Description (storedetaileddescription) to the default search field set. To learn more about modifying field sets, see Define Field Sets.

After saving the field set and record, make sure you rebuild the search index.

Note:

The code samples provided in this tutorial assume you are working with the Detailed Description (storedetaileddescription) field described in the preceding paragraph. If you choose to work with a different standard or custom field, make sure you alter the code samples accordingly.

Create the Extension Framework

You can create an extension manually or by using the gulp extension:create command as described in Create a Baseline Extension. For this tutorial, create your extension manually as described in the following steps.

  1. Access the top-level extension development directory you created when you installed the extension developer tools.

  2. In the top-level extension development directory, unless it already exists, create a new directory named Workspace.

  3. In the Workspace directory, set up the folders for this extension so that they look like this:

    Workspace/
        CDRExample
            Modules/
               CDRExample/
                  JavaScript/
                  Templates/ 
    
  4. In the Workspace/CDRExample directory, create a manifest.json file and place the following code in that file.

    {
        "name": "CDRExample",
        "fantasyName": "Context Data Request Example",
        "vendor": "ExampleVendor",
        "version": "1.0.0",
        "type": "extension",
        "target": "SCA,SCS",
        "target_version": {
            "SCA": ">=20.2.0",
            "SCS": ">=20.2.0"
        },
        "description": "An example extension to demonstrate contextDataRequest",
        "skins": [],
        "templates": {
            "application": {
                "shopping": {
                    "files": [
                        "Modules/CDRExample/Templates/cdr_example.tpl"
                    ]
                }
            }
        },
        "javascript": {
            "entry_points": {
                "shopping": "Modules/CDRExample/JavaScript/CDRExample.js"
            },
            "application": {
                "shopping": {
                    "files": [
                        "Modules/CDRExample/JavaScript/CDRExample.js",
                        "Modules/CDRExample/JavaScript/CDRExample.View.js"
                    ]
                }
            }
        },
        "local_folder": "Workspace\\CDRExample"
    } 
    

Create the Entry Point File

To show the Detailed Description (storedetaileddescription) field, you need to render a view and template that have access to that information. To create that view, first you need to create an entry point file.

In the Workspace/CDRExample/Modules/CDRExample/JavaScript directory, create an entry point file named CDRExample.js that contains the following code.

define('CDRExample', [
    'CDRExample.View'
], function (
    CDRExampleView
) {
    'use strict';

    return {
        mountToApp: function mountToApp (container) {
            var PLP = container.getComponent('PLP');

            if (PLP) {
                PLP.addChildViews(PLP.PLP_VIEW, {
                    'ItemViews.Price': {
                        'CDRExample.View': {
                            childViewIndex: 0,
                            childViewConstructor: function () {
                                return new CDRExampleView({PLP: PLP})
                            }
                        }
                    } 
                })
            }
        }
    }
}) 

In the preceding code, notice that:

  • You are accessing the PLP (Product List Page) component. This is necessary because:

    • You want to use its addChildViews() method.

    • You want to access information it has on the current display type.

  • You add the child view using verbose syntax, addChildViews(), which accepts two view injection targets instead of the usual one.

    • The reason for this is you need to be as specific as possible. For example, there could be other instances of ItemsView.Price throughout your Commerce website, and you do not necessarily want to inject your new child view into those.

    • Therefore, you use the verbose method, addChildViews(), attached to a specific visual component (the PLP component) and pass in a reference of the main PLP view, which keeps things in scope. For more information about verbose syntax, see Add a Child View.

Create the View File

The view is where most of the work of the extension takes place. For this tutorial, use the SCView module in the view file that you create.

Note:

If you are developing for SuiteCommerce or SuiteCommerce Advanced 2020.2.0 or later, the view generated when you use the gulp extension:create command does not implement currently recommended API methods. Starting with the 2020.2 release, you should use SCView in your extensions instead of Backbone.View. SCView extends from Backbone.View, inheriting all its methods and properties. SCView also provides additional methods for Commerce site development. For more information, see the extensibility API reference.

In the Workspace/CDRExample/Modules/CDRExample/JavaScript directory, create a file named CDRExample.View.js that contains the following JavaScript:

define('CDRExample.View', [
    'SCView',
    'cdr_example.tpl'
], function (
    SCViewModule,
    cdr_example_tpl
) {
    'use strict';

    var SCView = SCViewModule.SCView;

    function CDRExampleView (options) {
        SCView.call(this, options);

        this.template = cdr_example_tpl;
        this.contextDataRequest = ['item'];
        this.displayType = options.PLP.getDisplay().id;
    }

    CDRExampleView.prototype = Object.create(SCView.prototype);
    CDRExampleView.prototype.constructor = CDRExampleView;

    CDRExampleView.prototype.render = function () {
        if (this.displayType == 'list') {
            SCView.prototype.render.call(this);
        }
    }

    CDRExampleView.prototype.getContext = function () {
        return {
            storedetaileddescription: this.contextData.item().storedetaileddescription
        }
    }

    return CDRExampleView
}) 

In the preceding JavaScript, notice the following details about the CDRExampleView function:

  • You are making a contextDataRequest for item data.

  • You are creating a custom displayType property that uses the PLP component’s getDisplay() method, which returns a data object about the user’s current display type.

After setting the view’s prototype and setting the constructor function, you override the view’s render property with a custom function.

Important:

The render property on SCView is protected, which means you are allowed to override it. Before overriding a property, check the API documentation to determine if it is permitted. Never override private properties in your customizations.

The override you are putting in place for render calls the parent class’s render property if, and only if, the display type ID that is passed in is list. This mechanism prevents the view from being rendered when other display types, like grid or table, are active.

Finally, in the getContext property, you create a function that defines the context object that is sent to the template. You can see that after implementing contextDataRequest in the constructor, it is here in this part of the code where you finally access the contextData.

The item() object is essentially a copy of the item model, which allows you to get the displayType property you want from it.

Create the Template

In the CDRExample/Modules/CDRExampleModule/Templates directory, create a template file named cdr_example.tpl. Put the following line in the file and then save it.

{{{storedetaileddescription}}} 

Notice that the preceding value is wrapped in triple curly braces—a feature of Handlebars that prevents HTML escaping.

In cases where you are certain that the HTML you are passing into the template is safe (that is, valid HTML from a trusted, secure source), you can tell Handlebars to interpret the stringified value as raw HTML. This has the effect of injecting the HTML directly into the template’s source.

Because you expect this field to always be HTML served straight from the item record stored in your NetSuite account, you can use the triple curly braces to prevent HTML escaping.

Test the Extension

Start your local server and then navigate to the local version of your Commerce website. For step-by-step instructions, see Test an Extension on a Local Server.

Visit a product list page and change the display type. When you view the grid and table displays, there is no change, as shown in the following screen shot.

Shows items in the table view of a product list page.

However, when you view the list display type, you should see the detailed description for each listed product:

Shows the results of the extension, which is a list view of a product list page that includes item descriptions.

Troubleshoot the Extension

If you encounter these errors, double-check the code for your extension as described in the following table.

Error

Potential Issue

contextData is undefined

Make sure you’ve added contextData to one of the views listed in the table in contextData and contextDataRequest Properties (or one of their child views). The contextData object is only available in specific scenarios and not every view will expose data this way.

Detailed Description (storedetaileddescription) field is undefined

Check the data received from the items API to make sure the storedetaileddescription field is there. If not, double-check these settings:

  • You added the field to the field set

  • You saved both the field set row and form, and also the website setup record

  • The data exists in the item record

  • You ran a search re-index

If all the settings are correct and the storedetaileddescription field is not included in the data received from the items API, perform a cache invalidation request for the relevant URL path. If necessary, you may need to invalidate the entire domain’s cache.

If you get this error and the storedetaileddescription field is included in the data received from the items API, log the object to the console and check for typos in the field name.

General Notices