stream_entry
stream_entry

Reputation: 55

Ranging over a struct containing slices of multiple structs in a template

I am attempting to pass a struct containing multiple slices of structs into a template. Is there a way to refactor the template so that I can display all the data with using only a single loop (so as to avoid copying and pasting for every single Stock struct that I have). I have tried passing in a 2d array and was unable to access the elements I needed and haven't been able to refactor the template to only one use loop myself.

The following code is a simplified version of what I'm working with.

package main

import (
    "fmt"
    "html/template"
    "os"
)

type Stock struct {
    BuyPrice  string
    SellPrice string
}

type StockPortfolio struct {
    StockA []Stock
    StockB []Stock
}

func main() {

    // Stocks aren't combined from the get-go because I have more
    // struct fields relating to each individial trading pair

    stockAUSD := Stock{
        BuyPrice:  "1.00 USD",
        SellPrice: "1.10 USD",
    }
    stockAEURO := Stock{
        BuyPrice:  "0.85 EUR",
        SellPrice: "0.94 EUR",
    }
    stockBUSD := Stock{
        BuyPrice:  "2.00 USD",
        SellPrice: "2.10 USD",
    }
    stockBEURO := Stock{
        BuyPrice:  "1.70 EUR",
        SellPrice: "1.88 EUR",
    }

    stockA := []Stock{stockAUSD, stockAEURO}
    stockB := []Stock{stockBUSD, stockBEURO}

    portfolio := StockPortfolio{stockA, stockB}

    tmpl := `
<table>
<tr>
    <td>Price A</td>
{{range .StockA}}
    <td>{{ .BuyPrice }}</td>
    <td>{{ .SellPrice }}</td>
{{end}}
</tr>
<tr>
    <td>Price B</td>
{{range .StockB}}
    <td>{{ .BuyPrice }}</td>
    <td>{{ .SellPrice }}</td>
{{end}}
</tr>
</table>
`
    t := template.Must(template.New("tmpl").Parse(tmpl))

    err := t.Execute(os.Stdout, portfolio)
    if err != nil {
        fmt.Println("executing template:", err)
    }
}

Upvotes: 1

Views: 692

Answers (1)

Daniel Sch&#252;tte
Daniel Sch&#252;tte

Reputation: 618

This template should do want you want; it ranges over your first and second slice and print all the stock information:

<html>
<body>
    <h1>All Stocks</h1>
    <table>
{{ range $key, $val := . }}
        <tr>
            <td>Portfolio Number: {{ $key }}</td>
        </tr>
        <tr>
            <td>Buy Price</td>
            <td>Sell Price</td>
        </tr>
{{ range $val2 := . }}
        <tr>
            <td>{{ $val2.BuyPrice }}</td>
            <td>{{ $val2.SellPrice }}</td>
        </tr>
{{ end }}
{{ end }}
    </table>
</body>
</html>

But this solution requires a little bit of restructuring. That is, a Portfolio is now a slice of slices of Stocks:

// Portfolio is a slice of slices of stocks
type Portfolio [][]Stock

....

stockA := []Stock{stockAUSD, stockAEURO}
stockB := []Stock{stockBUSD, stockBEURO}
portfolio := Portfolio([][]Stock{stockA, stockB}) // for illustrative purposes

....

This should give you a nicely formatted table without the necessity to manually loop over all Stocks.

Upvotes: 0

Related Questions