Go code can be included in your component with in a <script type="application/x-go"> tag. This code is copied from your .vugu file into the resulting code generated .go file. It is the appropriate place to include structs, methods and imports needed by your component.

Tip: Script Tag Alternative

Because Go packages impose few limits on which code may be put into which file, you are not required to use a <script type="application/x-go"> tag and it works just as well to place this code in a separate file.

If you want to do this, the suggested naming convention is component-name-data.go.

For root.vugu, you could place your corresponding Go code in root-data.go.

For some-component.vugu you could place your corresponding Go code in some-component-data.go

For every component there are two structs which must be defined. One which implements ComponentType, and one which is the "data" for your component. If you do not define them in your Go code block the code generator will output empty structs and missing methods for you (as a convenience to make it easy to rapidly create simple components).

Most components will use the Go code block to, aside from adding import statements, define the data struct for their component and add any needed methods to it.

In writing Go code blocks in your components, it is important to observe the following naming conventions:

  • component-name.vugu results in a code generated file called component-name.go in the same directory
  • component-name.vugu implies a struct called ComponentName which corresponds to the type of the component, and a struct called ComponentNameData, which is the data for each instance of the component.
  • ComponentNameData is normally where you want to add data and methods.

Let's take a look at a working example of a component that makes more use of the Go code section and see all of this work together. This example shows a button which, when clicked, will cause the browser to fetch data from the CoinDesk Bitcoin Price Index API, parse the result, and display it.

root.vugu:

  1. <div class="demo">
  2. <div vg-if='data.isLoading'>Loading...</div>
  3. <div vg-if='len(data.bpi.BPI) > 0'>
  4. <div>Updated: <span vg-html='data.bpi.Time.Updated'></span></div>
  5. <ul>
  6. <li vg-for='data.bpi.BPI'>
  7. <span vg-html='key'></span> <span vg-html='fmt.Sprint(value.Symbol, value.RateFloat)'></span>
  8. </li>
  9. </ul>
  10. </div>
  11. <button @click="data.HandleClick(event)">Fetch Bitcoin Price Index</button>
  12. </div>
  13.  
  14. <script type="application/x-go">
  15. import "encoding/json"
  16. import "net/http"
  17. import "log"
  18.  
  19. type RootData struct {
  20. bpi bpi
  21. isLoading bool
  22. }
  23.  
  24. type bpi struct {
  25. Time struct { Updated string `json:"updated"` } `json:"time"`
  26. BPI map[string]struct { Code string `json:"code"`; Symbol string `json:"symbol"`; RateFloat float64 `json:"rate_float"` } `json:"bpi"`
  27. }
  28.  
  29. func (data *RootData) HandleClick(event *vugu.DOMEvent) {
  30.  
  31. data.bpi = bpi{}
  32.  
  33. ee := event.EventEnv()
  34.  
  35. go func() {
  36.  
  37. ee.Lock()
  38. data.isLoading = true
  39. ee.UnlockRender()
  40.  
  41. res, err := http.Get("https://api.coindesk.com/v1/bpi/currentprice.json")
  42. if err != nil {
  43. log.Printf("Error fetch()ing: %v", err)
  44. return
  45. }
  46. defer res.Body.Close()
  47.  
  48. var newb bpi
  49. err = json.NewDecoder(res.Body).Decode(&newb)
  50. if err != nil {
  51. log.Printf("Error JSON decoding: %v", err)
  52. return
  53. }
  54.  
  55. ee.Lock()
  56. defer ee.UnlockRender()
  57. data.bpi = newb
  58. data.isLoading = false
  59.  
  60. }()
  61. }
  62.  
  63. </script>
  • Since this example lives in root.vugu, the data struct is called RootData. (And for example in a component in file sample-comp.vugu, this would be SampleCompData.) This is where a component's instance data is stored.
  • On RootData we have a variable called isLoading of type bool. This provides a simple way to vg-if a div, which then shows only during loading. (More below on how isLoading is updated.)
  • A struct bpi is defined for the data we're getting from the API call. This makes it easy to read and display. Remember, components are converted to regular Go code, and heeding the fact that your code runs in the browser, many of the usual approaches you would do in any Go program apply here.
  • We're looping over one of the members of bpi using vg-for in our markup to display each individual item returned.
  • A handler for the DOM click event is enabled with @click. Notice that the method it calls is a member of data (of type *RootData). This call does not have to be to a methd on data, but this is the most common case.
  • When the click handler is invoked, we start a goroutine to fetch data from the server in the background. It is important we don't block here and return from this method quickly.
  • The EventEnv is used to synchronize access to data, and works well from goroutines. When we modify any information on data or that could potentially have concurrency issues, you can use EventEnv.Lock() to get an exclusive lock, and EventEnv.UnlockRender() to release the lock and tell render loop that the page needs to be updated. See DOM Events for more info.