Implement a for loop inside a Go template - go-templates

I am working in Go, and right now I need to print at least 20 options inside a select, so I need to use some kind of loop that goes from 0 to 20 (to get an index).
How can I use a for loop inside a Go template?
I need to generate the sequence of numbers inside the template. I don't have any array to iterate.
EDIT:
I need to get something like this:
<select>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
So, I need to do in the code something like:
<select>
{{for i := 1; i < 5; i++}}
<option value="{{i}}">{{i}}</option>
{{end}}
</select>
But, this doesn't work.

You can use range in templates as well. See https://golang.org/pkg/text/template/#hdr-Variables
Easiest option might be to just use a slice containing your options:
func main() {
const tmpl = `
<select>
{{range $val := .}}
<option value="{{$val}}">{{$val}}</option>
{{end}}
</select>
`
t := template.Must(template.New("tmpl").Parse(tmpl))
t.Execute(os.Stdout, []int{1, 2, 3})
}

Your best bet is to add an "Iterate" function to your func_map.
template.FuncMap{
"Iterate": func(count *uint) []uint {
var i uint
var Items []uint
for i = 0; i < (*count); i++ {
Items = append(Items, i)
}
return Items
},
}
Once you register your function map with text/template, you can iterate like this:
{{- range $val := Iterate 5 }}
{{ $val }}
{{- end }}
I don't know why this useful function isn't part of the default set of functions text/template provides. Maybe they'll add something similar in the future.

You can also use a channel to avoid building a slice:
funcMap := template.FuncMap{
"loop": func(from, to int) <-chan int {
ch := make(chan int)
go func() {
for i := from; i <= to; i++ {
ch <- i
}
close(ch)
}()
return ch
},
}
then:
{{range $x := loop 3 9 }}
Hey {{$x}}!
{{- end}}
See the full working example: https://go.dev/play/p/DP2WuROnCC9

Related

How to use the array of checkbox in ASP.NET Core Razor? [duplicate]

This question already has an answer here:
Calling function from generated button in Blazor [duplicate]
(1 answer)
Closed 2 years ago.
#for (int i = 0; i < values.Count; i++)
{
<input type="checkbox" #bind="values[i]" />
}
#code {
private List<bool> values = new List<bool>() { true, true, false };
}
Why did the following exception occur when I clicked the "checkbox" generated by the above code?
Unhandled exception rendering component: Index was out of range. Must be non-negative and less than the size of the collection.
What is the right way? Thanks a lot.
In your for loop you iterate over i. In each iteration, the value of i is increased by one. The value is not bound to let's say values[1] but to values[i] which is after the last iteration 3 for each element. 3 violates the array boundaries, hence the exception.
The underlying reason is that a lambda expression is used to make this binding. In this lambda expression i is not a value, but a reference. Have a look at this post for a similar example.
To prevent it, add a new variable inside the for loop to save the current value of i.
#for (int i = 0; i < values.Count; i++)
{
var temp = i;
<input type="checkbox" #bind="values[temp]" />
}
This is a result of C# behaviour.
You can use a foreach loop or capture the variable.
#for (int i = 0; i < values.Count; i++)
{
var iCopy = i;
<input type="checkbox" #bind="values[iCopy]" />
}

What does Dafny know about loops with a break?

I am used to loops
while Grd
invariant Inv
{ ..}
assert Inv && !Grd;
with out any break Dafny knows that Inv && ! Grd is true but:
Dafny does not check the loop invariant after a break; command. Hence
method tester(s:seq<int>) returns (r:int)
ensures r <= 0
{ var i:nat := |s|;
r := 0;
while (i > 0)
decreases i
invariant r == 0;
{ i := i -1;
if s[i]< 0 { r:= s[i]; break;}
}
// assert r == 0; // invariant dose not hold
}
method Main() {
var x:int := tester([1,-9,0]);
print x,"\n";
}
Clearly Dafny understands that the invariant no longer holds. Could anyone tell me what dafny actually knows.
If there are break statements, the condition after the loop is
the disjunction of Inv && !Grd and the conditions that hold at
the respective break statements.
Here's a more formal answer:
In the absence of any abrupt exits (like break) from a loop, the familiar
way to prove the Hoare triple
{{ P }}
while Grd
invariant Inv
{
Body
}
{{ Q }}
is to prove the following three conditions (I'm ignore termination):
Check that the loop invariant holds on entry to the loop:
P ==> Inv
Check that the loop invariant is maintained by the loop body:
{{ Inv && Grd }}
Body
{{ Inv }}
Check that the invariant and negated guard prove Q:
Inv && !Grd ==> Q
Let me rephrase conditions 1 and 2. To do that, I will start by
rewriting the while loop into a repeat-forever loop with breaks:
loop
invariant Inv
{
if !Grd {
break;
}
Body
}
(In other words, I'm using loop as while true.) Proof obligation 1 above
can now be rephrased as proving
{{ Inv }}
if !Grd {
break;
}
Body
{{ Inv }}
where you don't have to prove anything further along any path that reaches
a break.
Proof obligation 2 can be rephrased in a sort of dual way:
{{ Inv }}
if !Grd {
break;
}
Body
{{ break: Q }}
by which I mean you don't have to prove anything if you reach the end of ...Body,
but you do have to prove Q at any break.
What I just said also applies when Body contains other break statements. That's how Dafny treats loops (that is, condition 0 plus the rephrased conditions 1 and 2, plus termination checking).

Why doesn't the binding work with an array and a for loop in my example (blazor)?

I have a situation where I have a 0-n fields that may need to be populated. I accomplish that by trying to bind to List<double> in a for loop as such
#for (var i = 0; i < 3; i++)
{
<input type="text" #bind="TraineeValues[i]" />
}
The issue is that underlying list values don't seem to be updating.
Fiddle below
https://blazorfiddle.com/s/gfhw59v4
You need to create another variable inside the loop for getting the correct variable
#for (var i = 0; i < 3; i++)
{
var ii = i;
<input type="text" #bind="TraineeValues[ii]" />
}
Your for loop should contain a local variable like this:
#for (var i = 0; i < 3; i++)
{
var localVariable = i;
<input type="text" #bind="TraineeValues[localVariable]" />
}
This is standard C# behavior where your code has access to a variable and not to the value of the variable. You have to define a variable which is local to the for loop; that is, this variable is defined at each iteration of the loop, otherwise it's the same variable across all iterations, and your code is going to use the same value contained in the variable when the loop ends.
See also this...

Printing value of sql.NullString in Go template

I have fetched details from database where couple of column were of sql.NullString and sql.NullInt64 column.
Now, while I print them, after checking if it is Valid, it prints data in {3 true} format. I only want to print value 3 from it.
How can I achieve this?
Currently this is what, I am printing:
{{ range $value := .CatMenu }}
... // Other data
{{ $value.ParentID }} // This is sql.NullInt64 type
{{ end }}
sql.NullInt64 is a struct:
type NullInt64 struct {
Int64 int64
Valid bool // Valid is true if Int64 is not NULL
}
When printing struct values, the default formatting is what you currently see.
If you check if it is valid and non-nil prior, you can simply print the NullInt64.Int64 field only which holds the numerical value.
This is how you can do it:
{{ range $value := .CatMenu }}
... // Other data
{{ $value.ParentID.Int64 }} // This is sql.NullInt64 type
{{ end }}
See this simple example to test it:
vs := []*sql.NullInt64{
{3, true},
{2, true},
}
t := template.Must(template.New("").Parse(
"{{range .}}{{.Int64}}\n{{end}}",
))
if err := t.Execute(os.Stdout, vs); err != nil {
panic(err)
}
Output (try it on the Go Playground):
3
2

Are dynamic variables supported?

I was wondering if it is possible to dynamically create variables in Go?
I have provided a pseudo-code below to illustrate what I mean. I am storing the newly created variables in a slice:
func method() {
slice := make([]type)
for(i=0;i<10;i++)
{
var variable+i=i;
slice := append(slice, variablei)
}
}
At the end of the loop, the slice should contain the variables: variable1, variable2...variable9
Go has no dynamic variables.
Dynamic variables in most languages are implemented as Map (Hashtable).
So you can have one of following maps in your code that will do what you want
var m1 map[string]int
var m2 map[string]string
var m3 map[string]interface{}
here is Go code that does what you what
http://play.golang.org/p/d4aKTi1OB0
package main
import "fmt"
func method() []int {
var slice []int
for i := 0; i < 10; i++ {
m1 := map[string]int{}
key := fmt.Sprintf("variable%d", i)
m1[key] = i
slice = append(slice, m1[key])
}
return slice
}
func main() {
fmt.Println(method())
}
No; you cannot refer to local variables if you don’t know their names at compile-time.
If you need the extra indirection you can do it using pointers instead.
func function() {
slice := []*int{}
for i := 0; i < 10; i++ {
variable := i
slice = append(slice, &variable)
}
// slice now contains ten pointers to integers
}
Also note that the parentheses in the for loop ought to be omitted, and putting the opening brace on a new line is a syntax error due to automatic semicolon insertion after ++. makeing a slice requires you to pass a length, hence I don’t use it since append is used anyway.