How can I access DOM Element properties from Go WebAssembly? - go

I'm trying to extend the "Hello WebAssembly" example from https://github.com/golang/go/wiki/WebAssembly. As given, the example simply prints a message to the console. I wanted to add some code using syscall/js to replace the body element content.
The attempt below fails to build:
package main
import (
"fmt"
"syscall/js"
)
func main() {
fmt.Println("Hello, WebAssembly!") // original example
// I added
doc := js.Global().Get("document")
body := doc.Call("getElementById", "thebody")
body.innerHTML = "Dynamic Content"
}
When I try to build with $ env GOOS=js GOARCH=wasm go build -o main.wasm
I get :
./wasm.go:14:6: body.innerHTML undefined (type js.Value has no field or method innerHTML)
Not surprising when you think about it, but I don't see an example in the doc at https://godoc.org/syscall/js that explains how to get and set element properties.

To get the value of any property of some JavaScript object, use the Value.Get() method (you actually already used it when you accessed the document object by calling js.Global().Get("document")). Similarly, to set a value of a property, use Value.Set().
The name of the property whose value to get / set is simply a Go string value, "innerHTML" in your case. The value to be set may be many of Go values (e.g. string, integer numbers, floating point numbers, bool, slices, maps etc.), the js.ValueOf() function is used to obtain a js.Value() that will be set ultimately. In your case, you may simply use the Go string value "Dynamic Content".
doc := js.Global().Get("document")
body := doc.Call("getElementById", "thebody")
body.Set("innerHTML", "Dynamic Content")

Related

How to declare to variables of different datatypes in a single statement in Go [duplicate]

This question already has answers here:
Multiple variables of different types in one line in Go (without short variable declaration syntax)
(2 answers)
Closed 1 year ago.
I want to declare two variables of different datatypes(string and error) in a single statement in Go. I do not want to use the short declaration(:=) operator because I like specifying the type of the variable at declaration.
I am following a Go tutorial from the Go docs. I have a function called greetings.Hello() that I am calling from another module. The greetings.Hello() function looks like this:
package greetings
import (
"errors"
"fmt"
)
func Hello(name string) (string, error) {
// If no name was given, return an error with a message
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value
var message string = fmt.Sprintf("Welcome %v!", name)
return message, nil
}
So as you can see, this function returns two values(a string and an error). So ultimately, I would have to assign the result of this function to two variables in the caller. I am calling the greetings.Hello() function from a module named hello. The main function of the hello module's main package looks like this:
package main
import (
"fmt"
"log"
"creating_modules/greetings"
)
func main() {
log.SetPrefix("greetings: ")
log.SetFlags(0)
var message string, err error = greetings.Hello("")
if err !=nil {
log.Fatal(err)
}
fmt.Println(message)
}
The creating_modules/greetings is the greetings module that contains the function Hello(). Most of the gophers tackle it like this:
message, error := greetings.Hello()
But I want to declare the variables along with their datatypes in a single statement. Also the two variables should be assigned the return values of greetings.Hello(). The above mentioned main function of the hello module returns an error when it is run because of the incorrect assignment, referring to this line:
var message string, err error = greetings.Hello("")
The Go compiler returns this error when this code is run using go run:
.\hello.go:14:20: syntax error: unexpected comma at end of statement
This issue can simply be reproduced by copy-pasting the code above(note that the greetings module is a local module so you will need to set the reference path for go tools using go edit -replace)
Another thing to be noted is that my question is different from this question because that question is about declaring variables with the same data type in a single statement whereas mine is about declaring multiple variables with different data types in a single statement.
P.S i won't be surprised to know that Golang does not have this feature
declare the variables along with their datatypes in a single statement
Not possible
Supporting clause from the language spec under Variable declarations
If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first implicitly converted to its default type;
So something like below could work by not specifying either of the types, but you could very well use short variable declarations using := instead
var message, error = greetings.Hello()
But you can declare the variables explicitly with their type information and use the = assignment.
var message string
var err error
if message, err = greetings.Hello(""); err != nil {
log.Fatal(err)
}

Creating MS Word documents with Go OLE binding

I've been playing around and learning how to make Word docs programmatically. I know it can easily be done using pywin32. This simple snippet retrieves the default Visual Basic "code" inside the new Word doc.
import win32com.client
word = win32com.client.Dispatch("Word.Application")
word.Visible = True
document = word.Documents.Add()
document.VBProject.Name = "TEST"
wordModule = document.VBProject.VBComponents("ThisDocument") # WORKS
input()
You can then add VB code to wordModule.
I wanted to do the same using Golang. There is a OLE binding for Go, the code is on Github -> https://github.com/go-ole/go-ole
It's a bit less user friendly but I managed to make it work, except that I'm not able to retrieve the default VBComponents.
The default code resides in "ThisDocument" and can be retrieved with the simple python code document.VBProject.VBComponents("ThisDocument") except that, it doesn't work in Go...
You can see in the code below that I tried to get "ThisDocument" using multiple ways, without success. Each time, the error message is panic: Unknown name.
// +build windows
package main
import (
"fmt"
ole "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
func main() {
defer ole.CoUninitialize()
ole.CoInitialize(0)
unknown, _ := oleutil.CreateObject("Word.Application")
word, _ := unknown.QueryInterface(ole.IID_IDispatch)
oleutil.PutProperty(word, "Visible", true)
documents := oleutil.MustGetProperty(word, "Documents").ToIDispatch()
document := oleutil.MustCallMethod(documents, "Add").ToIDispatch()
vbproject := oleutil.MustGetProperty(document, "VBProject").ToIDispatch()
oleutil.PutProperty(vbproject, "Name", "TEST")
// oleutil.MustCallMethod(vbproject, "VBComponents", "ThisDocument").ToIDispatch() --> panic: Unknown name.
// oleutil.MustGetProperty(vbproject, "VBComponents", "ThisDocument").ToIDispatch() --> panic: Unknown name.
// vbcomponents := oleutil.MustGetProperty(vbproject, "VBComponents").ToIDispatch()
// oleutil.MustGetProperty(vbcomponents, "ThisDocument").ToIDispatch() --> panic: Unknown name.
var input string
fmt.Scanln(&input)
oleutil.PutProperty(document, "Saved", true)
oleutil.CallMethod(documents, "Close", false)
oleutil.CallMethod(word, "Quit")
word.Release()
}
Any ideas on why it doesn't work?
Thanks a lot.
Turns out "github.com/go-ole/go-ole" has a bug when using ForEach. VBComponets is a Collection, so you have to iterate as stated by Microsoft doc
Use the VBComponents collection to access, add, or remove components in a project. A component can be a form, module, or class. The VBComponents collection is a standard collection that can be used in a For...Each block.
This line -> https://github.com/go-ole/go-ole/blob/master/oleutil/oleutil.go#L106
should be replace by
newEnum, err := disp.CallMethod("_NewEnum")
Now it works as intended.

Is there a way to dynamically add cases to a golang type switch?

I have a simple type switch that I need to perform operations according to the type it receives. But I want to add methods to be run according to a certain type dynamically.
I have this method called "Register", in which I register a function to be executed for a certain reflect.Type T. These transformations will be stored in a map whose key is the actual type.
/*Register ...*/
func (bs *BaseStreamer) Register(
transform func (in interface{}) interface{},
T reflect.Type) {
_, ok := bs.transformations[T]
if ok {
log.Printf(
"Warning: Overriding method for type %s",
T.String()
)
}
bs.transformations[T] = transform
}
Now I want to iterate over this map and dynamically add cases to my TypeSwitch, so the right method will be executed for its respective type, and I don't know if this is even possible in go. I tried looking for it in the reflect package, but the only option there seems to do something similar to the select operation. Well, as I'm not dealing with channels here, I really only needed to add cases dynamically to my switch.
switch item := newItem.(type) {
// Here I'd like to iterate over my map
// and add cases for each pair key, value
// (type, function) i have on my map
default:
log.Printf("No transformation function registered for any of the types")
}
Is this even possible in go? Is there something similar to SelectCase from the reflect package?

Idiomatic way to initialise an empty string in Go

In Go you can initialise an empty string (in a function) in the following ways:
var a string
var b = ""
c := ""
As far as I know, each statement is semantically identical. Is one of them more idiomatic than the others?
You should choose whichever makes the code clearer. If the zero value will actually be used (e.g. when you start with an empty string and concatenate others to it), it's probably clearest to use the := form. If you are just declaring the variable, and will be assigning it a different value later, use var.
var a string
It's not immediately visible that it's the empty string for someone not really fluent in go. Some might expect it's some null/nil value.
var b = ""
Would be the most explicit, means everyone sees that it's a variable containing the empty string.
b := ""
The := assigment is so common in go that it would be the most readable in my opinion. Unless it's outside of a function body of course.
There isn't a right way to declare empty variables, but there are some things to keep in mind, like you can't use the := shortcut outside of a function body, as they can with var:
var (
name string
age int64
)
I find var name = "" to be the clearest indication that you're declaring an empty variable, but I like the type explicitness of var name string. In any case, do consider where you are declaring variables. Sometimes all at once outside the function body is appropriate, but often nearest to where you actually use it is best.
rob (Pike?) wrote on a mailthread about top-level declaration
At the top level, var (or const or type or func) is necessary: each item must be introduced by a keyword for ur-syntactic reasons related to recognizing statement boundaries. With the later changes involving semicolons, it became possible, I believe, to eliminate the need for var in some cases, but since const, type, and func must remain, it's not a compelling argument.
There is a certain ambiguity in "short-variable" declarations (using :=), as to whether the variable is declared or redeclared as outlined in the specs:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
There is absolutely no difference in the generated code (with the current compiler – Go 1.7.4), and also gometalinter does not complain for any of those. Use whichever you like.
Some differences:
You can only use the short variable declaration in functions.
With short variable declaration, you can create variables of multiple types in one line, e.g.
a, b := "", 0
The following 3 apps generate identical code:
a.go
package main
import "fmt"
func main() { var a string; fmt.Println(a) }
b.go
package main
import "fmt"
func main() { var a = ""; fmt.Println(a) }
c.go
package main
import "fmt"
func main() { a := ""; fmt.Println(a) }
To verify, build each (e.g. with go build -o a), and use diff on Linux to compare the executable binaries:
diff a b && diff a c
I try to stick to the short declaration for a couple of reasons.
It's shorter
Consistency
Allocates memory for maps, slices and pointers to structs and types.
Although var a string and a := "" are the same, b := []T{} and var b []T are not the same. When dealing with slices and maps the shorter declaration will not be nil. More often then not (especially with maps) I want allocated memory.
There are few situations where var will be needed, for instance, you are calling a function that will populate a property of a type.
var err error
foo.Name, err = getFooName()
Using := syntax in the above situation will error out since foo.Name is already declared.
just
*new(string)
It's only stuff in stackoverf related to empty strings in go. So it should be here

Struct field names starting with a string

I have a go struct and I need to work with one of the fields. However I am starting with a string. How do I case it to get the field itself.
package main
import "fmt"
func main() {
type Point struct{
x int
y int
}
pt := Point{x:2, y:3}
a := "x"
fmt.Printf("%s", pt.a)
}
Since a = "x" I am expecting pt.x = 2. Here's the error message it prints out. I am definitely starting with a string so I can't just remove the quotation marks.
$ go run point.go
# command-line-arguments
./point.go:14: pt.a undefined (type Point has no field or method a)
If you need to access a field whose name is given as a string, you have no choice but to use reflection. Go ain't Python. :-)
This blog has a nice explanation.
Here is the reflect package documentation.
But note that reflection should usually be used as a last resort only. It removes the static type safety and is detrimental for performance.
What are you really looking for? There may be a way to address your requirements without using reflection. For example, if you don't need methods attached to your struct, you could use map[string]int.

Resources