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

Casting to a specific type or exposing an interface with HTML element functions #897

Closed
amlwwalker opened this issue Oct 3, 2023 · 12 comments

Comments

@amlwwalker
Copy link

I want to generate a go-app type, (say app.Div) from the string div. I believe that all functions like this have similar functions like

	app.Div().Body()
	app.A().Body()
	app.Section().Body()
	
	app.Div().Attr()
	...

Is there an interface that I can use to store a map of map[string]app.Interface and store "div":app.Div in there so that I can then populate whatever is returned? I can't find an interface that they are adhering to?

@mlctrez
Copy link
Contributor

mlctrez commented Oct 3, 2023

The closest would be app.UI which is a common interface to all of the html element interfaces.

i.e. app.Div() and app.A() are both app.UI

If you're looking for a common interface for the Body() method, there is not one, since each html element returns a it's own interface to allow method chaining.

package app

// HTMLA is the interface that describes a "a" HTML element.
type HTMLA interface {
	UI

	// Body set the content of the element.
	Body(elems ...UI) HTMLA
}

// HTMLDiv is the interface that describes a "div" HTML element.
type HTMLDiv interface {
	UI

	// Body set the content of the element.
	Body(elems ...UI) HTMLDiv
}

@amlwwalker
Copy link
Author

ok yep.
And is there a way to set the Body of a document? It seems that app.Body() does not have a Body() method. I am processing a load of components that I have in an []app.UI and I want to now append those as the body of the document however it seems this also is not possible?

@oderwat
Copy link
Sponsor Contributor

oderwat commented Oct 3, 2023

You can only add a single component inside of body. So you could add app.Div().Body(your elements) in the first component that gets mounted through the route.

@amlwwalker
Copy link
Author

Ok thanks I'll have to be very explicit for the goals I want then.
If it comes up in conversation an interface that defined the "standard" html things like attrs, class, id, data, body, style (and probably some others) for elements would be nice for the ones that have all those. Be good to be able to hold them and call those similar functions across them without having to be explicit about the type directly

@mlctrez
Copy link
Contributor

mlctrez commented Oct 5, 2023

the "standard" html things like attrs, class, id, data, body, style (and probably some others) for elements would be nice for the ones that have all those

Without breaking the contract of existing methods on each element type by removing the return value, there cannot be a common interface as mentioned earlier. Likewise, adding additional methods to meet a common interface would be confusing - there would be two differently named methods that do the same thing.

I want to generate a go-app type, (say app.Div) from the string div

and

store a map of map[string]app.Interface and store "div":app.Div in there so that I can then populate whatever is returned

This sounds to me like building go-app elements from json or similar. Instead of chaining calls to go-app typed elements, you want a simplified way instantiate elements without using method chaining? I inferred this from the two quotes so I could be way off.

{ 
  "div":{
    "class":"myClass",
    "id":"myId"
  }
}

passed to

func ElemFromJson(json string) app.UI {
	// get root, determine type
	e := app.Div()
        // call methods for id, body, etc
	return e
}

@amlwwalker
Copy link
Author

@mlctrez yes that is basically what I want. I actually want to (and am currently doing) parse an HTML template that builds go-app elements. I am using the golang standard html library to parse the html doc and recursively running through it replacing elements with go-app elements. It works great for instance if I have
<customsidebar> I can successfully swap this out for my go-app definition of a CustomSideBar. The issue comes when the html contains standard html tags like div, p, etc and there are alot of them. Currently I have to have a large switch/case to handle this and I was hoping to make it more generic.

But your example is the same principle yes, i.e json to elements hence why I was hoping to be able to have a generic interface. However I cant use app.UI as that doesn't have body/class etc on it so I can't call those on a generic type to populate those fields..

Thanks for support guys!

@oderwat
Copy link
Sponsor Contributor

oderwat commented Oct 12, 2023

@amlwwalker We wrote an HTML to go-app code converter (others did too, our one is proprietary, sorry) and I still think that there should be a possibility to compile these to WASM and load them as extension. I do wonder why you want to do that in the frontend, where you simply can add the raw HTML anyway?

@amlwwalker
Copy link
Author

amlwwalker commented Oct 12, 2023

I don't want to do it in the frontend @oderwat. I am attempting to build a sort of site-generator using go-app (at this point for my own education/enjoyment).
the HTML template -> go-app creator is so that the page layouts can be defined by non-go-programmers. Imagine my app is a terminal cli and reads in config files) - I have a bunch of standard elements and I want users to be able to define the layout then when the app starts it reads it in and uses that as the base layout.

Loading them via wasm as start would be cool too (esp as it allows for more elements to be added without recompiling) but for now I am just trying to make it straight forward to define the layout from HTML and then the elements are compiled into the app that are available 🙂

Do you have a link to an open source HTML to go-app converter that could then be inspiration, or could you tell me the approach you took? Did you do a big switch case - just so I know the route I am taking is correct?

@oderwat
Copy link
Sponsor Contributor

oderwat commented Oct 12, 2023

@amlwwalker I think it was: https://github.com/pojntfx/html2goapp

@oderwat
Copy link
Sponsor Contributor

oderwat commented Oct 12, 2023

We made a tool that generates go-app code and understands TailwindCSS with a live preview. But it is more for HTML-wizards, so you can quickly design some component using HTML using TailwindCSS and then copy the generated go-app code into the real source code. The first thing and what the converter actually was created for was using it to translate large amounts of HTML pages (mostly template site examples) info go-app declarative code, to check if we actually can use go-app in production without writing a lot of manually code.

@oderwat
Copy link
Sponsor Contributor

oderwat commented Oct 12, 2023

Did you do a big switch case - just so I know the route I am taking is correct?

Kinda. We use golang.org/x/net/html for parsing and have a map that defines the types of attributes like "width", "onclick", "href", "selected" and so on. It does not check for being valid HTML at all and supports only the attributes that are "know". It also does not even use "jennifer" or another go code builder and simply assembles the code using strings. That is one of the reasons we do not publish it. It works quite good but is actually a bit rough. It does support SVG and creates code for that. Which was one of the major reasons to use it. You do not want to write that stuff by hand and I dislike to use raw HTML for that.

@amlwwalker
Copy link
Author

OK thanks this is interesting. I'm going to look through that link you posted as I want to call existing go-app elements I've created based on custom html elements as explained above. I think I can use this inspiration to parse the HTML and then maybe extrapolate the jennifer work to do a sort of if el.Type == "custom-type" then... return myCustomTypeFunction or something......

hopefully anyway 😂
Thanks for help, this is a great next step in my plans 😁

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

4 participants