vugu / vugu

Vugu: A modern UI library for Go+WebAssembly (experimental)
https://www.vugu.org
MIT License
4.8k stars 175 forks source link

Toggle example code doesn't work with initial value passed from parent component #212

Open Nuxij opened 2 years ago

Nuxij commented 2 years ago

Describe the bug Toggle example code works as a component, but only if you don't try to set "Show" from the parent component during inclusion. When you do try to pass a "default", the c.Show will always keep that value and never actually toggle.

Software Versions Vugu version: v0.3.4 Go version: 1.16.3 windows/amd64 Browser and version: Chrome 92

To Reproduce Create Toggle example as a component:

<div>
    <button @click='c.Switch(event)'>Toggle me Silly</button>
    <div vg-if='c.Show'>I am here!</div>
</div>

<script type="application/x-go">
import "log"
type Toggle struct {
    Show bool `vugu:"data"`
}
func (c *Toggle) Switch(e vugu.DOMEvent) {
    c.Show = !c.Show
    log.Printf("Toggled! Show is now %t", c.Show)
}
</script>

Include it from Root and set an initial value for the Show variable.

<main:Toggle :Show=false></main:Toggle>

the Switch function will now fail to overwrite c.Show and just print the same message over and over again. For this repro it will repeat Toggled! Show is now true.

Expected behavior Show variable should initialise with the passed-in value and then toggle as normal.

Additional Notes If you don't pass a value for Show from the parent component, Switch() will work as expected. c.Show will get updated and the v-if will re-render as expected.

Nuxij commented 2 years ago

I tried EventEnv two ways but no dice.

  1. This caused a deadlock:
      func (c *Toggle) Switch(e vugu.DOMEvent) {
          ee := e.EventEnv()
          ee.Lock()
          c.Show = !c.Show
          ee.UnlockRender()
          log.Printf("Toggled! Show is now %t", c.Show)
      }
  2. This produced no difference whatsoever
    func (c *Toggle) Switch(e vugu.DOMEvent) {
        go func() {
            ee := e.EventEnv()
            ee.Lock()
            c.Show = !c.Show
            ee.UnlockRender()
            log.Printf("Toggled! Show is now %t", c.Show)
        }()
    }
Nuxij commented 2 years ago

I tried putting the switch logic directly in the click handler but no luck there either. In this form, the log message still prints the correct thing as if c.Show really had changed, but the v-if on the page doesn't change. (and then obviously c.Show somehow reverts ready for the next click of the button, making the log message repeat itself)

<div>
    <button @click='c.Show = !c.Show;c.Switch(event)'>Toggle me Silly</button>
    <div vg-if='c.Show'>I am here!</div>
</div>

<script type="application/x-go">
import "log"
type Toggle struct {
    Show bool `vugu:"data"`
}
func (c *Toggle) Switch(e vugu.DOMEvent) {
    log.Printf("Toggled! Show is now %t", c.Show)
}
</script>
Dadido3 commented 2 years ago

I think that behavior is to be expected. The show parameter is always overwritten when the virtual DOM is rebuilt.

The solution to this would be to add a DefaultShow parameter, and use the Init(ctx vugu.InitCtx) lifecycle callback to set c.Show = c.DefaultShow.

owenwaller commented 7 months ago

@bradleypeabody my gut feel is that we close this, as there seems to be a solution.

But, it still seems like this should just work without resorting to the component lifecycle.