maxence-charriere/go-app

TypeError: import gojs:runtime.scheduleTimeoutEvent must be an object

rtrzebinski opened this issue · 13 comments

Hi, I'm back to my project and trying to run it locally, getting:

TypeError: import gojs:runtime.scheduleTimeoutEvent must be an object

The same codebase worked before, the only change is that I now use newer go version:

go version go1.23.0 darwin/arm64

I use go-app v9 and I see there is now v10 - would upgrading to go-app v10 fix my issue?

Thank you.

We are on v10 and use Go 1.23. I think updating to v10 for a project that is still worked on is mandatory anyway. You may want to check what I needed to do for the update here

thank you @oderwat trying to upgrade now

app.Window().AddEventListener does not exist now, do you know how this should be updated?

Yes, use the JS interoperation and create what you need with a proper release function (if needed):

func OnPaste(fn func(string)) func() {
	hFn := func(this app.Value, args []app.Value) any {
		event := args[0]
		clipboardData := event.Get("clipboardData")
		text := clipboardData.Call("getData", "text").String()
		fn(text)
		return nil
	}
	fo := app.FuncOf(hFn)
	app.Window().Call("addEventListener", "paste", fo)
	return fo.Release
}

Thank you!

An example of my code:

f = app.Window().AddEventListener("swiped-left", func(ctx app.Context, e app.Event) {
	c.handleBadAnswer()
})
c.unsubscribers = append(c.unsubscribers, f)

In v9 an "unsubscriber" f function was returned from AddEventListener() call so I could remove event listeners once view was switched (component unloaded I think). Is it possible in v10 as well?

I don't know any JS but checking here https://www.w3schools.com/jsref/met_document_addeventlistener.asp

And I can't see the possibility to unsubscribe from the event, do you have any idea?

The code I send you never gets "removed". It returns a release func for the go func but that was never called and will most likely crash if the element (which is the window here anyway) would get dismounted. So without testing it, I think a better implementation could be:

func OnPaste(element app.Value, fn func(string)) func() {
	if element == nil {
		element=app.Window()
	}
	hFn := func(this app.Value, args []app.Value) any {
		event := args[0]
		clipboardData := event.Get("clipboardData")
		text := clipboardData.Call("getData", "text").String()
		fn(text)
		return nil
	}
	fo := app.FuncOf(hFn)
	element.Call("addEventListener", "paste", fo)
	release := func() {
		element.Call("removeEventListener", "paste", fo)
		fo.Release()
	}
	return release
}

I did not test that at all. If you like to use that, please tell me if that worked. It should actually get an "app.Context", gets the value and make the func that is given to call fn(ctx,app.Event). I am not at the computer so I can't try how to make this. But it think it should work.

Thank you so much, it looks like it works (both addEventListener and removeEventListener).

Example:

	hFn := func(this app.Value, args []app.Value) any {
		event := args[0]

		// bind actions to keyboard shortcuts
		switch event.Get("code").String() {
		case "Space":
			if c.isAnswerVisible == true {
				c.handleNextExercise()
			} else {
				c.handleViewAnswer()
			}
		case "KeyV", "ArrowUp":
			c.handleViewAnswer()
		case "KeyG", "ArrowRight":
			c.handleGoodAnswer()
		case "KeyB", "ArrowLeft":
			c.handleBadAnswer()
		case "KeyN", "ArrowDown":
			c.handleNextExercise()
		}

		return nil
	}

	fo := app.FuncOf(hFn)

	app.Window().Call("addEventListener", "keyup", fo)

	c.unsubscribers = append(c.unsubscribers, func() {
		app.Window().Call("removeEventListener", "keyup", fo)
		fo.Release()
	})

I'll share my v10 update commit once completed and close the issue then with it.

I have some other issues but will create new tickets for those, thank you once again :)

I found an issue related to button mapping (I think).

A Learn component method handleNextExercise() can be triggered by both keyboard key press and button click:

func (c *Learn) handleNextExercise() {
	app.Log("handleNextExercise")
	c.isAnswerVisible = false
	c.exercise = c.memorizer.Next(c.exercise)
}

This handleNextExercise() should update the UI with c.isAnswerVisible = false.

When button is clicked it updates the UI.

When keyboard key is pressed it does not update the UI.

I see in logs the exactly same code is running (so key binding works fine), but only clicking the button in the browser updates the UI.

Can you think of the reason why? @oderwat

You most likely need to run the function inside the handler using a ctx.Dispatch(theFunc), so that the component knows that it needs to update. This is what go-app does with all the handlers that it implements on the components.

@oderwat Thank you, I tried to figure it out but I'm confused.

Which function I should run with ctx.Dispatch()?

Do you have any example?

If that helps this is my PR -> rtrzebinski/simple-memorizer-4#6

Here I'm adding an event listener -> https://github.com/rtrzebinski/simple-memorizer-4/blob/beecbfcbb6687a5b8250c416f85cdad00b26555e/internal/components/learn.go#L180

I tried this but it does not help (UI still not updated by key press):

rtrzebinski/simple-memorizer-4@9a97e53

@oderwat that worked, that you so much!

Closing this one, commit for the reference -> rtrzebinski/simple-memorizer-4@046c7aa

I have some other issues but I'll continue in another threads to keep them focused on a single concern.

@oderwat thank you for your help, without you I'd drop this project long time ago 🍺