Template multiple loop add , at end element miss behaviour

When I execute template and have multiple for loops I dont get desired behaviour. The template adds a , on last element instead of avoiding it on last element. example code: play.golang.org
Any ideas?

Desired output:
WITH data(name, email, title, sentences) AS (
VALUES
(‘TestName’, ‘test@gmail.com’, ‘Title1’, ARRAY[‘z1 Line 1’, ‘z1 1 Line 2’]),
(‘TestName’, ‘test@gmail.com’, ‘Title1’, ARRAY[‘z2 Line 1’, ‘z2 Line 2’]),
(‘TestName’, ‘test@gmail.com’, ‘Title1’, ARRAY[‘z3 Line 1’, ‘z3 Line 2’])
)

    package main

import (
	"html/template"
	"os"
)

func main() {
	type Account struct {
		Name  string
		Email string
	}

	type Sentence struct {
		Text string
	}
	type Object struct {
		Sentences []Sentence
	}
	type List struct {
		Account Account
		Name    string
		Objects     []Object
	}

	var list []List
	account := Account{Name: "TestName", Email: "test@gmail.com"}
	l1 := List{Account: account, Name: "Title1", Objects: []Object{Object{Sentences: []Sentence{Sentence{"z1 Line 1"}, Sentence{"z1 1 Line 2"}}}, Object{Sentences: []Sentence{Sentence{"z2 Line 1"}, Sentence{"z2 Line 2"}}}, Object{Sentences: []Sentence{Sentence{"z3 Line 1"}, Sentence{"z3 Line 2"}}}}}
	l2 := List{Account: account, Name: "Title2", Objects: []Object{Object{Sentences: []Sentence{Sentence{"z1 Line 1"}, Sentence{"z1 1 Line 2"}}}, Object{Sentences: []Sentence{Sentence{"z2 Line 1"}, Sentence{"z2 Line 2"}}}}}
	l3 := List{Account: account, Name: "Title3", Objects: []Object{Object{Sentences: []Sentence{Sentence{"z1 Line 1"}, Sentence{"z1 1 Line 2"}}}, Object{Sentences: []Sentence{Sentence{"z2 Line 1"}, Sentence{"z2 Line 2"}}}}}

	list = append(list, l1, l2, l3)
	const insert = `
	{{range .}}{{$accName := .Account.Name}}{{$accEmail := .Account.Email}}{{$listTitle := .Name}}
WITH data(name, email, title, sentences) AS (
		VALUES {{range $idx, $o := .Objects}}
			('{{$accName}}', '{{$accEmail}}', '{{$listTitle}}', ARRAY[{{range $i, $e := $o.Sentences}}{{if $i}}, {{end}}'{{$e.Text}}'{{end}}]){{if $idx}}, {{end}}{{end}}
)
	{{end}}
`
	t := template.Must(template.New("inserts").Parse(insert))

	// Execute the template for each recipient.
	err := t.Execute(os.Stdout, list)
	if err != nil {
		panic(err)
	}
}

Your issue is that in your inner range - {{range $i, $e := ...}} - you put the if statement as the first thing. In short, you are adding a comma for the previous entry if there was one, but when the index is 0 it won’t add a comma. If you look at your output you can see this because your first line of values does not have a comma at the end.

WITH data(name, email, title, sentences) AS (
		VALUES 
			('TestName', 'test@gmail.com', 'Title1', ARRAY['z1 Line 1', 'z1 1 Line 2'])  <<<< No comma
			('TestName', 'test@gmail.com', 'Title1', ARRAY['z2 Line 1', 'z2 Line 2']), 
			('TestName', 'test@gmail.com', 'Title1', ARRAY['z3 Line 1', 'z3 Line 2']), 
)

You can fix this by doing something similar to waht you did before - move the {{if $idx}}, {{end}} section of your code to right after your range for it and get rid of your current one.

{{range $idx, $o := .Objects}}{{if $idx}}, {{end}}   << add this part
			('{{$accName}}', '{{$accEmail}}', '{{$listTitle}}', ...

Full source (yours + my update) is here: https://play.golang.org/p/q3hp3tMgZy

1 Like

the , code was wrongly places after everything it should be added first. Updated: https://play.golang.org/p/sXQJsXrP9o

Previously:

VALUES {{range $idx, $o := .Objects}} <---- HERE
			('{{$accName}}', '{{$accEmail}}', '{{$listTitle}}', ARRAY[{{range $i, $e := $o.Sentences}}{{if $i}}, {{end}}'{{$e.Text}}'{{end}}]){{if $idx}}, {{end}}<----- MOVE{{end}}

fixed:

VALUES {{range $idx, $o := .Objects}}{{if $idx}}, {{end}}
 			('{{$accName}}', '{{$accEmail}}', '{{$listTitle}}', ARRAY[{{range $i, $e := $o.Sentences}}{{if $i}}, {{end}}'{{$e.Text}}'{{end}}]){{end}}

Thank joncalhoun I was kind of blinded by the obvious :blush:

2 Likes

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