Skip to content

js struct tag - how does it work? #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
maddyblue opened this issue Oct 26, 2014 · 12 comments
Closed

js struct tag - how does it work? #114

maddyblue opened this issue Oct 26, 2014 · 12 comments

Comments

@maddyblue
Copy link

I'm working on reactjs bindings, but can't figure out how the struct tags work. I have:

type Class struct {
    DisplayName string           `js:"displayName"`
    Render      func() Component `js:"render"`
}
c := Class{
    DisplayName: "Player",
    Render: func() react.Component {
        return react.DIV
    },
}

Printing c in the js console, I get:

Object {$val: Object, DisplayName: "Player", Render: function, $key: function, $get: function}

I expected it to have members displayName and render due to the struct tags. Am I missing something?

@neelance
Copy link
Member

Your struct needs to have a field with the type js.Object. The field may be anonymous.

@maddyblue
Copy link
Author

Doesn't appear to help:

type Class struct {
    o js.Object // (I also tried embedding this, omitting the o name)
    DisplayName string           `js:"displayName"`
    Render      func() Component `js:"render"`
}

Yields:

Object {DisplayName: "Player", Render: function}

and (in the embedded case):

Object {"": null, DisplayName: "Player", Render: function}

@maddyblue
Copy link
Author

I tried removing Render to see if the Component thing mattered, but results were the same with just DisplayName.

@neelance
Copy link
Member

I guess what you want is something like this:

package main

import "github.com/gopherjs/gopherjs/js"

type Class struct {
    js.Object
    DisplayName string `js:"displayName"`
    Render      func() `js:"render"`
}

func main() {
    c := Class{Object: js.Global.Get("Object").New()}
    c.DisplayName = "Player"
    c.Render = func() {
        println("Render called!")
    }
    println(c.Object)
}

Output:

{ displayName: 'Player', render: [Function] }

The js tags are still in a rough state. Please feel free to share any ideas that you have on them.

@maddyblue
Copy link
Author

When I do that (use the .Get("Object").New() constructor and pass c.Object), it passes an empty {}, even though DisplayName and Render are set:

c.Object: Object {}
c: Object {$val: Object, Object: Object, DisplayName: "Player", Render: function, $key: function…}

I need to pass a javascript object with displayName and render to an external javascript library I don't control. Is there a better way to do this?

[Update:] I tried your code and it works fine, so I must be doing something wrong. I'll research why mine isn't working how it looks like it should and post a new comment here.

@maddyblue
Copy link
Author

It appears that one must not set other struct members other than the js.Object at var init time, but instead set them as individual statements. This is strange, and it's not obvious why one needs js.Object at all for this to happen.

@dmitshur
Copy link
Member

js.Object is a reference to the actual JavaScript-world object.

The js tags in struct fields, as far as I understand them, are just a shortcut/convenience thing that let you achieve effectively this:

type Class struct {
    js.Object
}

func (c *Class) DisplayName() string {
    return c.Object.Get("displayName").Str()
}

func (c *Class) SetDisplayName(displayName string) {
    c.Object.Set("displayName", displayName)
}

But in a shorter form:

type Class struct {
    js.Object
    DisplayName string `js:"displayName"`
}

Basically, getting or setting a struct field with a js tag effectively gets/sets the underlying javascript object (the js.Object) field.

@neelance
Copy link
Member

neelance commented Nov 2, 2014

@shurcooL Exactly, that's a very good explanation.

@Archs
Copy link
Contributor

Archs commented Jan 30, 2015

Is this means that the struct literal in gopherjs won't work?

But struct literal is a powerful declarative way to do some initialization. Is there some way to make it workable?

@neelance
Copy link
Member

Hi @Archs , please include a link to an example of your issue on http://www.gopherjs.org/play/ .

@Archs
Copy link
Contributor

Archs commented Feb 2, 2015

Hi @neelance, I'm working on a gopherjs binding of Vue.js, a MVVM js library, which is quite like Angular.js but different.

Vuejs's initialization method takes a js object as parameter which contains a lot of fields. In rusco's vuejs example, he uses js.M to pass the configs to the JavaScript world, which is quite javascript like.

So I tried using a struct literal to pass the configs like this:

type VueOption struct {
    js.Object
    El   string `js:"el"`
    Data js.M   `js:"data"`
    Methods js.M `js:"methods"`
        ...
}

// init func
func New(opts VueOption ) *Vue {
    vm := vue.New(opts)
    return &Vue{
        Object: vm,
    }
}

// then initializing a vuejs instance
v := vue.New(vue.VueOption{
    El: "#demo",
    Data: js.M{
        "title": "todos",
        "todos": []js.M{
            js.M{
                "done":    true,
                "content": "Learn JavaScript",
            },
            js.M{
                "done":    false,
                "content": "Learn Vue.js",
            },
        },
    },
})

but it won't work. I have to use the js.M instead like this:

// init func
func New(opts js.M) *Vue {
    vm := vue.New(opts)
    return &Vue{
        Object: vm,
    }
}
// then initializing a vuejs instance
v := vue.New(js.M{
    "el": "#demo",
    "data": js.M{
        "title": "todos",
        "todos": []js.M{
            js.M{
                "done":    true,
                "content": "Learn JavaScript",
            },
            js.M{
                "done":    false,
                "content": "Learn Vue.js",
            },
        },
    },
})

The js.M way works just fine but Go's type system and go doc's reference utilities can't be fully utilized and hence the declarative style of doing initialization.

I think this relates to issue:#141 since the js tags in Go struct only serve as a setter/getter shortcuts, without direct access the struct fields can't be recognized by the Js world.

Is there some way to work around this?

@jskDr
Copy link

jskDr commented Feb 2, 2015

Hi, all.
In current version, which one is more stable between coffeescript and
pythonjs.
I believe that PythonJS will be more feasible than coffeescript because it
must be
perfectly compatible with Python except highly special cases.

On Mon, Feb 2, 2015 at 9:42 AM, Archs notifications@github.com wrote:

Hi @neelance https://github.com/neelance, I'm working on a gopherjs
binding of Vue.js https://github.com/Archs/js/tree/master/vue, a MVVM
js library, which is quite like Angular.js but different.

Vuejs's initialization method takes a js object as parameter which
contains a lot of fields. In rusco's vuejs example
https://github.com/rusco/vue, he uses js.M
https://github.com/rusco/vue/blob/master/js/app.go#L54 to pass the
configs to the JavaScript world, which is quite javascript like.

So I tried using a struct literal to pass the configs like this:

type VueOption struct {
js.Object
El string js:"el"
Data js.M js:"data"
Methods js.M js:"methods"
...
}
// init funcfunc New(opts VueOption ) *Vue {
vm := vue.New(opts)
return &Vue{
Object: vm,
}
}
// thenv := vue.New(vue.VueOption{
El: "#demo",
Data: js.M{
"title": "todos",
"todos": []js.M{
js.M{
"done": true,
"content": "Learn JavaScript",
},
js.M{
"done": false,
"content": "Learn Vue.js",
},
},
},
})

but it won't work. I have to use the js.M instead like this:

// init funcfunc New(opts js.M) *Vue {
vm := vue.New(opts)
return &Vue{
Object: vm,
}
}// thenv := vue.New(js.M{
"el": "#demo",
"data": js.M{
"title": "todos",
"todos": []js.M{
js.M{
"done": true,
"content": "Learn JavaScript",
},
js.M{
"done": false,
"content": "Learn Vue.js",
},
},
},
})

The js.M way works just fine but Go's type system and go doc's reference
utilities can't be fully utilized and hence the declarative style of doing
initialization.

I think this relates to issue:#141
#141 since the js tags in Go
struct only serve as a setter/getter shortcuts, without direct access the
struct fields can't be recognized by the Js world.

Is there some way to work around this?


Reply to this email directly or view it on GitHub
#114 (comment).

Best regards,
James Sungjin Kim, Ph.D.
Samsung Advanced Institute of Technology (SAIT)
Samsung. Electronics Co., LTD

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants