Programmatically determine the correct response filter key
Commerce also provides a mechanism for programmatically determining the response filter key to pass in a REST call, allowing you to avoid hard coding it into the widget itself.
The programmatic mechanism for determining which response filter key to pass in a REST request has several parts, as follows:
- A context object that is instantiated in the widget’s JavaScript file.
- A filter map that is defined in an application-level JavaScript file.
- The
CCStoreConfiguation
library.
The context object contains the data required for locating the correct response filter
key in the filter map. The widget instantiates the context object with the necessary
data and then passes it to the CCStoreConfiguration
library’s
getFilterToUse()
method, which locates the correct response filter
key in the filter map and returns it to the widget.
Enable programmatic filter key determination
You must enable programmatic filter key determination before you can use it. To do
so, create an application-level JavaScript module that lists the
CCStoreConfiguration
library as a dependency and includes the
following code:
define(
//-------------------------------------------------------------------
// DEPENDENCIES
//-------------------------------------------------------------------
['ccStoreConfiguration'],
//-------------------------------------------------------------------
// Module definition
//-------------------------------------------------------------------
function(CCStoreConfiguration) {
'use strict';
return {
onLoad : function() {
CCStoreConfiguration.getInstance().enableFilter();
},
}
}
);
See Include Application-level JavaScript Modules for details on creating and uploading an application-level JavaScript module.
Understand the filter map
The filter map uses a prioritized structure of top-level objects and
nested sub-objects. CCStoreConfiguration
compares the data in the
context object to that prioritized structure when locating the key. The following
code sample shows the out-of-the-box filter map that Commerce uses. In it, the filter map sets the priorityList
variable to
["endpoint","page","identifier"]
, meaning that
CCStoreConfiguration
will first try to find a top-level object
that matches the endpoint in the context object, then it will search inside that
object for a matching page object, then it will search inside that object for a
matching identifier object. The following is an example:
define(
//-------------------------------------------------------------------
// DEPENDENCIES
//-------------------------------------------------------------------
['ccStoreConfiguration'],
//-------------------------------------------------------------------
// Module definition
//-------------------------------------------------------------------
function(CCStoreConfiguration) {
'use strict';
return {
onLoad : function() {
console.log("Loading Application Level JS");
var priorityList = ["endpoint","page","identifier"];
var newFilterMap = {
"getCollection":{
"megaMenuNavigation": {"ccFilterConfigKey": "categoryNavData"},
"categoryNavigation": {"ccFilterConfigKey": "categoryNavData"}
},
"listProducts":{
"productListingData": {"ccFilterConfigKey": "PLPData"},
"collectionWidget": {"ccFilterConfigKey": "collectionData"},
"getProductData": {"ccFilterConfigKey": "productData"},
"getProductDataAndRedirect": {"ccFilterConfigKey": "productData"}
}
};
CCStoreConfiguration.getInstance().updateFiltersToUse(newFilterMap);
},
}
}
);
The top-level objects in the out-of-the-box filter map correspond to endpoints and
their sub-objects correspond to identifiers. In other words,
getCollection
and listProducts
represent
endpoints and their children (megaMenuNavigation
,
categoryNavigation
, productListingData
, and so
on) represent identifiers. (Note that the getCollection
and
listProducts
endpoints return data that is page-independent so,
even though the priority list includes page, page objects are not defined for these
two endpoints in the out-of-the-box filter map.)
To understand how CCStoreConfiguration
compares the contents of a
context object to the filter map, we will compare the following context object to
the out-of-the-box filter map:
var contextObj = {};
contextObj["endpoint"] = "getCollection";
contextObj["identifier"] = "categoryNavigation";
When considering this context object, CCStoreConfiguration
first looks for a matching endpoint among the top-level objects in the filter map (because endpoint is first in the priority list). In this case, CCStoreConfiguration
finds the getCollection
top-level object. Next, CCStoreConfiguration
looks for a matching page
sub-object within the getCollection
top-level object (because page is second in the priority list). The context object does not have page data, however, so CCStoreConfiguration
moves on to find the next piece of data in the priority list, which is identifier
. The thing to note here is that CCStoreConfiguration
continues to look for the next piece of data in the current object. In other words, it looks for a categoryNavigation
sub-object in the getCollection
top-level object. When CCStoreConfiguration
finds the categoryNavigation
sub-object, it sees that the object has a ccFilterConfigKey
defined for it. CCStoreConfiguration
retrieves this filter key, categoryNavData
, and returns it to the widget.
You can set your priority list and the object structure of your filter map in any way that makes sense for your implementation and then define context objects in your widgets that use that updated structure. However, keep in mind that the out-of-the-box filters, and the widgets that use them, may be affected by changes you make and may need modifications as a result.
Create a context object and use it to retrieve the response filter key
To create a context object and use it to retrieve a response filter key, add code similar to the following to the widget’s JavaScript file. Note that you must also add a dependency on the CCStoreConfiguration
library. The following is an example:
// Add the CCStoreConfiguration library as a dependency for this widget
// Create the context object and populate it
var contextObj = {};
contextObj["endpoint"] = "endpoint-name";
contextObj["identifier"] = "identifier-in-filter-map";
// Call the getFilterToUse method to retrieve the response filter key
var filterKey = CCStoreConfiguration.getInstance().getFilterToUse(contextObj);
// Add the filterKey to the data passed with the REST call
if (filterKey) {
data["filterKey"] = filterKey;
}
//Make the REST call
ccRestClient.request(url, data,
this.successFunc.bind(this),
this.errorFunc.bind(this));
}
Add a new response filter key to the out-of-the-box filter map
The following code sample creates new identifiers in the out-of-the-box filter map for calls made to the getCollection
and productListing
endpoints. The new identifier for the getCollection
endpoint is customIdentifer1
and the response filter key that is returned for it is customFilterKey1
. The new identifier for the productListing
endpoint is customIdentifer2
and the response filter key that is returned for it is customFilterKey2
. The following is an example:
define(
//-------------------------------------------------------------------
// DEPENDENCIES
//-------------------------------------------------------------------
['ccStoreConfiguration'],
//-------------------------------------------------------------------
// Module definition
//-------------------------------------------------------------------
function(CCStoreConfiguration) {
'use strict';
return {
onLoad : function() {
console.log("Loading Application Level JS");
var priorityList = ["endpoint","page","identifier"];
var newFilterMap = {
"getCollection":{
"megaMenuNavigation": {"ccFilterConfigKey": "categoryNavData"},
"categoryNavigation": {"ccFilterConfigKey": "categoryNavData"},
"customIdentifier1": {"ccFilterConfigKey": "customFilterKey1"}
},
"listProducts":{
"productListingData": {"ccFilterConfigKey": "PLPData"},
"collectionWidget": {"ccFilterConfigKey": "collectionData"},
"getProductData": {"ccFilterConfigKey": "productData"},
"getProductDataAndRedirect": {"ccFilterConfigKey": "productData"},
"customIdentifier2": {"ccFilterConfigKey": "customFilterKey2"}
}
};
CCStoreConfiguration.getInstance().updateFiltersToUse(newFilterMap);
},
}
}
);
Note that, when you override the filter map, the top-level objects you define completely replace any existing top-level objects. In other words, if you created a new filter map that looked as follows:
// This code overwrites the getCollection top-level object entirely
var newFilterMap = {
"getCollection":{
"customIdentifier1": {"ccFilterConfigKey": "customFilterKey1"}
},
};
You would lose the megaMenuNavigation
and categoryNavigation
identifiers defined out of the box for the getCollection
top-level object. However, the listProducts
top-level object would remain unchanged because no new top-level object definition for it has been introduced. For this reason, you should be careful to include the default identifiers, shown earlier, along with any new identifiers you create unless you explicitly intend to overwrite them.
Use defaults in the filter map
The filter map supports the concept of defaults at each object level. When
CCStoreConfiguration
cannot find a match for a piece of data in
the context object, it looks for a default. If it finds a default, it searches
within that default object’s children for the next piece of data in the priority
list. If it cannot find a match or a default, it will not return a response filter
key.
The concept of default objects can exist at any level in a filter map. For example,
consider this filter map that sets its priority list to
["endpoint","page","identifier","viewport"]:
var newFilterMap = {
"endpoint1": {
"page1":{"cc-filter-config-key": "key1"},
"page2":{"cc-filter-config-key": "key2"},
"page3":{
"identifier1":{"cc-filter-config-key": "key3"},
"identifier2":{"cc-filter-config-key": "key4"},
"cc-filter-config-key": "key11",
"default":{
"viewport1":{"cc-filter-config-key": "key5"},
"viewport2":{"cc-filter-config-key": "key6"},
"default":{"cc-filter-config-key": "key7"}
}
},
"cc-filter-config-key": "key8",
"default":{
"identifier1":{"cc-filter-config-key": "key9"},
"default":{"cc-filter-config-key": "key10"}
}
}
};
The following table lists a variety of sample context objects and the response filter key that would be returned for them based on this filter map:
Context Object Data | Filter Key Returned |
---|---|
endpoint1 | key8 |
endpoint1, page1 | key1 |
endpoint1, page3 | key11 |
endpoint1, page3, identifier1 | key3 |
endpoint1, page3, identifier2 | key4 |
endpoint1, page1, identifier3 | key1 |
endpoint1, page3, identifier3, viewport1 | key5 |
endpoint1, page3, identifier3, viewport3 | key7 |
endpoint1, page4 | null |
endpoint1, page4, identifier1 | key9 |
endpoint1, page4, identifier2 | key10 |
endpoint1, page1, identifier1 | key1 |