$scratch.Set outputting double quotes ("") when used in <script> tag

I have a layout which creates some dynamic javascript variable data using newScratch.

The problem is each call to the scratch’s Set method is outputting double quotes ("").

A simplified example, having:

{{ define "foot" }}

<script>

  A
  {{ $scratch := newScratch }}
  {{ $scratch.Set "greeting" "Hello" }}
  B

</script>

{{ end }} 

will actually output:

<script>

  A
  
  ""
  B

</script>

which is causing issues in my actual code:

{{ define "foot" }}

<script>

  {{- $constructorsData := slice -}}
  {{- range $constructor := sort $.Site.Data.constructors "name" -}}
    {{- $country := index $.Site.Data.countries $constructor.countryId -}}
    {{- $constructorData := newScratch -}}
    {{- $constructorData.Set "id" $constructor.id -}}
    {{- $constructorData.Set "name" $constructor.name -}}
    {{- $constructorData.Set "countryAlpha2Code" $country.alpha2Code -}}
    {{- $constructorData.Set "countryAlpha3Code" $country.alpha3Code -}}
    {{- $constructorData.Set "countryName" $country.name -}}
    {{- $constructorsData = $constructorsData | append ($constructorData.Values) -}}
  {{- end -}}
  var constructorsData = {{ $constructorsData }};

  ..
</script>

{{ end }}

as the var constructorsData = [..]; output in the generated page has a lot of "" prepended to it, making the javascript invalid.

Note I was experimenting a bit and when I just remove the opening <script> tag, the "" are not outputted anymore…

Am I doing something wrong here as I don’t understand why the ""s are outputted…?

1 Like

Note until now I was not having any issue without using a Scratch.

I currently have (which is working):

{{ define "foot" }}

<script>

  {{- $constructorsData := slice -}}
  {{- range $constructor := sort $.Site.Data.constructors "name" -}}
    {{- $country := index $.Site.Data.countries $constructor.countryId -}}
    {{- $constructorData := (dict "id" $constructor.id) -}}
    {{- $constructorData = merge $constructorData (dict "name" $constructor.name) -}}
    {{- $constructorData = merge $constructorData (dict "countryAlpha2Code" $country.alpha2Code) -}}
    {{- $constructorData = merge $constructorData (dict "countryAlpha3Code" $country.alpha3Code) -}}
    {{- $constructorData = merge $constructorData (dict "countryName" $country.name) -}}
    {{- $constructorsData = $constructorsData | append ($constructorData) -}}
  {{- end -}}
  var constructorsData = {{ $constructorsData }};

  ..
</script>

{{ end }}

I only wanted to replace all this dict merging by using a Scratch

you could write it like this

{{ `<script>` | safeHTML }}

  A
  {{ $scratch := newScratch }}
  {{ $scratch.Set "greeting" "Hello" }}
  B

{{ `</script>` | safeHTML }}

So Go Templates parser will not detect the <script> tag and not doing any escaping inside the tag.

2 Likes

Thanks it works! Now I’m wondering what the Go Templates engine does when detecting the <script> tag…

For future readers,
another simple solution is just to define the Scratch outside the <script> tag.

{{ define "foot" }}

{{- $constructorsData := slice -}}
{{- range $constructor := sort $.Site.Data.constructors "name" -}}
  {{- $country := index $.Site.Data.countries $constructor.countryId -}}
  {{- $constructorData := newScratch -}}
  {{- $constructorData.Set "id" $constructor.id -}}
  {{- $constructorData.Set "name" $constructor.name -}}
  {{- $constructorData.Set "countryAlpha2Code" $country.alpha2Code -}}
  {{- $constructorData.Set "countryAlpha3Code" $country.alpha3Code -}}
  {{- $constructorData.Set "countryName" $country.name -}}
  {{- $constructorsData = $constructorsData | append ($constructorData.Values) -}}
{{- end -}}

<script>
  var constructorsData = {{ $constructorsData }};
  ..
</script>

{{ end }}

Set returns an empty string, not double quotes, so the quotes comes from “somewhere else”.

You can try

{{- $scratch.Set “greeting” “Hello” -}}

To trim the newlines.

I would discourage following the accepted solution of trying to completely bypassing the template engine’s security model. The correct solution is to use safeJS.

<script>
{{ $scratch.Set "greeting" "Hello" | safeJS }}
</script>

I don’t recall why we do this, but Set returns an empty string. Bare strings are considered unsafe in a <script> context, so the template engine quotes and escapes the string for Javascript.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.