Go code can be included in your component with in a <script type="application/x-go">
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">
If you want to do this, the suggested naming convention is
For root.vugu, you could place your corresponding Go code in
For some-component.vugu you could place your corresponding Go code in
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:
- <div class="demo">
- <div vg-if='data.isLoading'>Loading...</div>
- <div vg-if='len(data.bpi.BPI) > 0'>
- <div>Updated: <span vg-html='data.bpi.Time.Updated'></span></div>
- <ul>
- <li vg-for='data.bpi.BPI'>
- <span vg-html='key'></span> <span vg-html='fmt.Sprint(value.Symbol, value.RateFloat)'></span>
- </li>
- </ul>
- </div>
- <button @click="data.HandleClick(event)">Fetch Bitcoin Price Index</button>
- </div>
- <script type="application/x-go">
- import "encoding/json"
- import "net/http"
- import "log"
- type RootData struct {
- bpi bpi
- isLoading bool
- }
- type bpi struct {
- Time struct { Updated string `json:"updated"` } `json:"time"`
- BPI map[string]struct { Code string `json:"code"`; Symbol string `json:"symbol"`; RateFloat float64 `json:"rate_float"` } `json:"bpi"`
- }
- func (data *RootData) HandleClick(event *vugu.DOMEvent) {
- data.bpi = bpi{}
- ee := event.EventEnv()
- go func() {
- ee.Lock()
- data.isLoading = true
- ee.UnlockRender()
- res, err := http.Get("https://api.coindesk.com/v1/bpi/currentprice.json")
- if err != nil {
- log.Printf("Error fetch()ing: %v", err)
- return
- }
- defer res.Body.Close()
- var newb bpi
- err = json.NewDecoder(res.Body).Decode(&newb)
- if err != nil {
- log.Printf("Error JSON decoding: %v", err)
- return
- }
- ee.Lock()
- defer ee.UnlockRender()
- data.bpi = newb
- data.isLoading = false
- }()
- }
- </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 tovg-if
a div, which then shows only during loading. (More below on howisLoading
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
usingvg-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 ofdata
(of type*RootData
). This call does not have to be to a methd ondata
, 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 useEventEnv.Lock()
to get an exclusive lock, andEventEnv.UnlockRender()
to release the lock and tell render loop that the page needs to be updated. See DOM Events for more info.