Thursday 5 March 2020

Error when using ajax.js (Commerce) and JSON.parse

I found an issue today with the ajax.js file that comes with Sitecore Commerce in Sitecore 9.2.  

I was trying to get a third party js component (Chute) working in Sitecore which loads scripts dynamically, but the component wouldn't display any content.  This particular component displays images in either a carousel or grid.  But after the initial load nothing appeared except for an error in my browser console:

TypeError: data is null  ajax.js:  156:24


This same component worked without any issue, in a non-commerce environment.

After some investigations, it became apparent that the issue was down to the fact that somewhere in the Js files supplied with Commerce the standard JSON.parse function was replaced with a custom function. 

Unfortunately it was missing a null check inside the new function.  I know that as developer we all do this...  However, I wanted to highlight the issue, to save someone some grief when trying to figure out what is going on...

The file in question can be found in the Sitecore content tree here: /sitecore/media library/Base Themes/Commerce Services Theme/Scripts/ajax

Once you download the media content you will get a script called ajax.js.

The offending code @ line 156, can be found just after the JSON.parse equals statement in the block of code shown below:

(function (root, factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
      // use AMD define funtion to support AMD modules if in use
      define(['exports'], factory);
    } else if (typeof exports === 'object') {
      // to support CommonJS
      factory(exports);
    }

    // browser global variable
    var AjaxService = {};
    root.AjaxService = AjaxService;
    factory(AjaxService);
  })(this, function (AjaxService) {
    'use strict';

    // Hack >>
    // When debugging is on, Sitecore is returning extra information, we need to strip it from the JSON string
    var jsonParseRef = JSON.parse;

    JSON.parse = function (data) {

      var debugIndex = data.indexOf('<div title="Click here to view the profile."');
      if (debugIndex > 0) {
        data = data.substring(debugIndex, 0, debugIndex);
      }

      return jsonParseRef(data);
    };



You will see in the above function that JSON.parse is updated with a new function, unfortunately the data variable is not checked for null before being used.

Changing the JSON.parse function to: 

JSON.parse = function (data) {

      if(data==null)return null;

      var debugIndex = data.indexOf('<div title="Click here to view the profile."');

      if (debugIndex > 0) {
        data = data.substring(debugIndex, 0, debugIndex);
      }

      return jsonParseRef(data);
    };

Fixes the issue.

Hopefully this might help someone.