Coveo for Sitecore 5 is now available!

Unexpected Token When Editing Page With SXA Components in Experience Editor

Sitecore SXA 1.8

Symptoms

When using the Experience Editor to modify an SXA page that contains the Coveo File Result Template component, Sitecore raises the following error:

Uncaught SyntaxError: Unexpected token <
    at proto.constructor._frameLoaded (2068651223329603235.JS:7416)
    at Object.resolveWith (2068651223329603235.JS:23)
    at w (2068651223329603235.JS:25)
    at XMLHttpRequest.d (2068651223329603235.JS:25)

Cause

When Sitecore loads the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file, it is not expecting a <script> element at the code location indicated below:

@if (Model.IsConfigured) {
    <div>
        @if (Html.Coveo().IsEditingInPageEditor()) {
            if (@Model.HasScript) {
                <div>Script Result Template</div>
            } else if (@Model.HasSource) {
                <div>File Result Template: @Model.Properties.Source</div>
            } else {
                <div>Undefined Result Template. Please configure the component.</div>
            }
            @Html.Partial(Partials.DEBUG_INFORMATION, Model)
        }
        <script id="@Model.Id"  <!-- Sitecore does not expect a script element here -->
                class="result-template"
                type="text/x-underscore-template"
               @foreach(var property in @Model.RawProperties) {
                   @:data-@(property.Key)='@(property.Value)'
               }>
            @if(@Model.HasScript) {
                @Html.Raw(@Model.Properties.Script)
            }
            @if(@Model.HasSource) {
                @Html.Partial(@Model.Properties.Source)
            }
        </script>
    </div>
}

This is an issue in Sitecore SXA.

Resolution

As part of case 516615, Sitecore has corrected the issue as follows:

  • The issue has been resolved in Sitecore SXA 1.8.
  • Sitecore has produced hotfixes for the following combinations of Sitecore and Sitecore SXA versions:
    • Sitecore Experience Accelerator 1.7 (rev. 180410) and Sitecore Experience Platform 9.0 rev. 171219 (9.0 Update-1)
    • Sitecore Experience Accelerator 1.7 Update 1 (rev. 180604) and Sitecore Experience Platform 9.0 rev. 171219 (9.0 Update-1)
    • Sitecore Experience Accelerator 1.7 Update 1 (rev. 180604) and Sitecore Experience Platform 9.0 rev. 180604 (9.0 Update-2)

In early October 2018, Coveo provided a workaround for this issue which consisted in having Coveo for Sitecore SXA users edit the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file (see Workaround).

In the October 2018 and November 2018 releases of Coveo for Sitecore 4.1 SXA, this workaround was actually applied directly in the Result Template.cshtml file provided in the packages.

From the February 2019 version of Coveo for Sitecore 4.1 SXA onwards, the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file will no longer contain the workaround script.

If your current environment is one of the aforementioned combinations of Sitecore and Sitecore SXA, proceed as follows:

  1. Ensure that the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file code does not include the workaround script.
  2. If the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file does include the workaround script, revert to the original /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file code, either by
    • removing the workaround code yourselves (see Cause section for the original Coveo File Result Template.cshtml code), or by
    • upgrading to the February 2019 or later version of Coveo for Sitecore 4.1 SXA, in which the /Areas/CoveoHiveSxa/Views/Result Templates/Coveo File Result Template.cshtml file will not include the workaround script.
  3. Apply the Sitecore hotfix for your environment.

Workaround

The workaround below should only be used if none of the solutions provided by Sitecore can be implemented (see Resolution section).

You can replace the code in the @if block above with the one below. In this workaround, the result template is initially loaded as a <div> element and subsequently replaced by the original <script> element using JavaScript code.

@if (Model.IsConfigured) {
<div>
        @if (Html.Coveo().IsEditingInPageEditor()) {
            if (@Model.HasScript) {
                <div>Script Result Template</div>
            } else if (@Model.HasSource) {
                <div>File Result Template: @Model.Properties.Source</div>
            } else {
                <div>Undefined Result Template. Please configure the component.</div>
            }
            @Html.Partial(Partials.DEBUG_INFORMATION, Model)
        }
        <div id="@Model.Id"
            @foreach(var property in @Model.RawProperties) {
                @:data-@(property.Key)='@(property.Value)'
            }>
            @if(@Model.HasScript) {
                @Html.Raw(@Model.Properties.Script)
            }
            @if(@Model.HasSource) {
                @Html.Partial(@Model.Properties.Source)
            }
        </div>
        <script>
            @* This workaround is to trick SXA into loading the result template as a div, then replace it as a script tag. *@
            setTimeout(function() {
                var originalElement = document.getElementById("@Model.Id");
                var scriptElement = document.createElement('script');
                scriptElement.id = originalElement.id;
                scriptElement.className = 'result-template';
                scriptElement.type = 'text/x-underscore-template';
                var key;
                for (key in originalElement.dataset) {
                    scriptElement.dataset[key] = originalElement.dataset[key];
                }
                @* Interpret this string as valid HTML. In other words, unescapes &gt;, &lt; and such. *@
                var textarea = document.createElement("textarea");
                textarea.innerHTML = originalElement.innerHTML;
                scriptElement.innerHTML = textarea.value;
                originalElement.parentNode.replaceChild(scriptElement, originalElement);
            }, 0);
        </script>
    </div>
}