Skip to content
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

Passing golang variables to javascript #944

Open
farhank3389 opened this issue Oct 1, 2024 · 9 comments
Open

Passing golang variables to javascript #944

farhank3389 opened this issue Oct 1, 2024 · 9 comments

Comments

@farhank3389
Copy link

I have a templ block defined like this:

templ test(teststring string) {
    <script>
        console.log({ "the value of teststring is " + teststring });
    </script>
}

However this does not work. The HTML it generates looks like this:


    <script>
        console.log({ "the value of teststring is " + teststring });
    </script>

I'm not sure if I'm doing something completely wrong here as this is my first time using templ. It seems to me that something like this should work. I had a look at the Using JavaScript with templ docs page and it says to not use the script template method of doing this, which does work for me. I'm not sure how I can do the same thing using script tags as the docs say.

@pharrisee
Copy link

pharrisee commented Oct 1, 2024

There is some documentation on passing server side data to client scripts:

https://templ.guide/syntax-and-usage/script-templates#pass-server-side-data-to-the-client-in-a-script-element

I also use a slightly different pattern on occasion, but tbh I'm not too happy with either way of doing it and much preferred the now deprecated script templates (https://templ.guide/syntax-and-usage/script-templates#script-templates):

templ test(teststring string) {
    <script teststring={teststring}>
        const teststring=document.currentScript.getAttribute("teststring");
        console.log({ "the value of teststring is " + teststring });
    </script>
}

@farhank3389
Copy link
Author

ah yeah that does look like what I need. And agreed, I prefer the script template method too.

@a-h
Copy link
Owner

a-h commented Oct 4, 2024

I can see why you like the script templates. There might be some middle ground to hit in the future, but need to control the scope of what we're working on in the short term - i.e. need to prioritise, and I think scripts are ... OK.

The problem with the script templates is really around how the initial design has boxed us in a bit. I don't think there's a clear way for us to expand on them to do async JS templates, add typescript, introduce formatting or LSP features etc. so it's more of a pause on progressing that feature direction than anything else.

Although... in August we did add a pretty cool new feature to it: ef4dde6

The need to pass variables from the Go world to the JS world won't go away, but I was looking at introducing templ variables directly into <script> tags instead. Combined with templ.Once which limits rendering of the block to once per HTTP request, it would provide all the same features, but fit better into the ecosystem.

However, I would need to find a way to slot Go variables into the JS code, by parsing the content, or using a helper function.

Just typing this out has put a new idea in my head.

type Data struct {
  X int `json:"x"`
  Y int `json:"y"`
}

templ Component(d Data) {
  <script type="text/javascript" data-templ-jsvar-name={ d }>
    alert(name.x * name.y)
  </script>
}

If there's a data-templ-jsvar-* attribute, templ could generate a JS closure that includes the -name as a variable, e.g.:

  <script type="text/javascript">
    let name = { x: 1, y: 3 };
    alert(name.x * name.y)
  </script>

However, that would mean that the variable wouldn't exist in the dev environment while you're coding, which might trigger linters, since they wouldn't know how to resolve the values.

templ could generate a JS file containing type definitions (classes?) for the data, e.g.: if you add an attribute for data-templ-jsvar-name it takes the name of the Go type (Data) and creates a JS class that matches in another file.

class Data {
  constructor(o) {
    //TODO: Get the data from a JSON variable in the attribute of the parent script tag.
    this.x = x;
    this.y = y;
  }
}
templ Component(d Data) {
  <script type="text/javascript" data-templ-jsvar-name={ d }>
    let d = new Data(this); // The Data class was auto-generated by templ.
    alert(d.x * d.y)
  </script>
}

Thoughts? @joerdav?

@gotzmann
Copy link

Just typing this out has put a new idea in my head.

Looks cool! Good to have the feature, just shorten the name of tag maybe? Like data-templ-let or something like this?

@nanvenomous
Copy link

Just going to humbly ask: please do not fully remove the script name() templ components until <script data-templ-let-name={} > tag variable are implemented.

I'm looking at a bit of a migration when this happens (maybe others?).
Data transfer go -> js is too useful of a feature.

@a-h
Copy link
Owner

a-h commented Nov 18, 2024

Stability is important. Would never want to break people's code.

@a-h
Copy link
Owner

a-h commented Nov 18, 2024

Also, if we really wanted to remove something, we'd likely add an automatic migration feature, plus keep the old method around for at least two Go release cycles.

@joerdav
Copy link
Collaborator

joerdav commented Nov 20, 2024

And also, I think we would want to make sure that it was desireable to migrate a way. The alternative should be a smoother experience, I don't think we want to force a move to a unfinished solution. Once we have a proper solution hopefully people will want to move to it because it is easier.

@dimmerz92
Copy link

I might just be oversimplifying in my head or not understanding the issues you are facing with the implementation, but could we perhaps just have script and async in templ?

I personally really like the templ script implementation as it is. Rather than shoving a bunch of functionality into script, just leave it as is for simple functions or sequences of instructions and add new constructs for other features like async or even typescript?

Maybe also just a hot take on my end or just ignorance, I feel like typescript isn't really a feature that is particularly useful.. I imagine most of us are just using scripts to ship js to the front end?

I'm also relatively new to web dev, so take this with a grain of salt and set me straight if I am wrong!

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

7 participants