vapor-community / HTMLKit

Create and render HTML templates with HTMLKit
MIT License
403 stars 21 forks source link

Image component and optional context values #104

Open onepayclick opened 1 year ago

onepayclick commented 1 year ago

Hi, love the library, but I'm having an extremely hard time trying to display an image using an url that comes from an optional field from the model These are some scenarios that I'm facing image

I had to create a computed var to try to drill down the model and fetch the url or default to "" and still doesn't work

var profile_thumb_url: String {
    attributes.profile_thumb.data?.attributes.url ?? ""
}

image

If I try to use the whole path I get these scenarios image

And if I try to get fancy image

mattesmohr commented 1 year ago

Sorry, to hear. I hope, I can help.

Do you want to use the UI component 'image' or the HTML element 'image'?

and

Do you use TemplateValue or without?

onepayclick commented 1 year ago

Hi :)

yes I'm using a TemplateValue. I want to use the HTML element image "<img src..."

I just noticed that HTLMKitComponents.Image(source:) its just a wrapper around HTMLKit.Image().source(TemplateValue.rawValue) and I tried both but I'm not sure why the src property is empty when displaying the page :(

onepayclick commented 1 year ago

Just an update

I tried using a normal type instead of a TemplateValue just to be sure the issue was not at my side and the model was correctly populated image

and I was able to present the image using Image().source(profiles[0].attributes.profile_thumb.data.attributes.url) I had to force profiles[0] because I can't use normal arrays with ForEach, they need to be TemplateValues.

The problem could be somewhere in the unwrapping of .dynamic maybe

[Update]: Image(source:) body uses rawValue image

but TemplateValue rawValue returns an empty string if the value is .dynamic image

if you render the page using this function image it seems to package your value into the .dynamic case instead of .constant

I tried unpacking the .dynamic but it seems that it wraps the value in an HTMLContext and for the looks of it, and HTMLContext does not stores the value, but a key path to it

onepayclick commented 1 year ago

Btw, not sure it makes a difference here but I'm using Linux

onepayclick commented 1 year ago

I'm using this hack to repackage the value until we can find a solution

func makeConstant<Value>(_ value: Value) -> TemplateValue<Value> {
    return .constant(value)
}

but then I found another issue. The HTMLKitComponents Image type doesn't seem to have access to any of the HTMLKit methods like .style, .class, .height

image

This seems to be the case with other components too

mattesmohr commented 1 year ago

I am currently at work. I will look into it tonight, when I am at home.

mattesmohr commented 1 year ago

Hi :)

yes I'm using a TemplateValue. I want to use the HTML element image "<img src..."

I just noticed that HTLMKitComponents.Image(source:) its just a wrapper around HTMLKit.Image().source(TemplateValue.rawValue) and I tried both but I'm not sure why the src property is empty when displaying the page :(

If you want to use the HTML element 'image', then you should use just Image(). The component 'image' comes from the UI component library I am working on. That you able to use it, tells me, that you running against the main branch. If you do so, be aware that you might use implementations, wich could be work in progress and not meant for release yet.

I am currently working on an update of the documentation. The documentation will explain and extend the thought of the UI component library.

mattesmohr commented 1 year ago

Just an update

I tried using a normal type instead of a TemplateValue just to be sure the issue was not at my side and the model was correctly populated image

and I was able to present the image using Image().source(profiles[0].attributes.profile_thumb.data.attributes.url) I had to force profiles[0] because I can't use normal arrays with ForEach, they need to be TemplateValues.

The problem could be somewhere in the unwrapping of .dynamic maybe

[Update]: Image(source:) body uses rawValue image

but TemplateValue rawValue returns an empty string if the value is .dynamic image

if you render the page using this function image it seems to package your value into the .dynamic case instead of .constant

I tried unpacking the .dynamic but it seems that it wraps the value in an HTMLContext and for the looks of it, and HTMLContext does not stores the value, but a key path to it

Yup, you are on the right track. TemplateValue wraps the value behind a KeyPath. Thats why you can't use string interpolation for example. The .rawValue was more meant as an short-term hack, not really as long-term solution.

TemplateValue and the context handling need some love and I am already on it. But I want to release the documentation first, release into 2.8 and when everything goes as planned I want to work on it for 2.9.

mattesmohr commented 1 year ago

Btw, not sure it makes a difference here but I'm using Linux

Makes no difference :-)

mattesmohr commented 1 year ago

I'm using this hack to repackage the value until we can find a solution

func makeConstant<Value>(_ value: Value) -> TemplateValue<Value> {
    return .constant(value)
}

but then I found another issue. The HTMLKitComponents Image type doesn't seem to have access to any of the HTMLKit methods like .style, .class, .height

image

This seems to be the case with other components too

All the UI components come with a predefined CSS. Overriding the style is a discussion worth. I haven't thought about it. So if you use the components library, do you use the CSS file too? How did you get to manage it? I haven't released instructions yet :-)

onepayclick commented 1 year ago

Hi :) yes I'm using a TemplateValue. I want to use the HTML element image "<img src..." I just noticed that HTLMKitComponents.Image(source:) its just a wrapper around HTMLKit.Image().source(TemplateValue.rawValue) and I tried both but I'm not sure why the src property is empty when displaying the page :(

If you want to use the HTML element 'image', then you should use just Image(). The component 'image' comes from the UI component library I am working on. That you able to use it, tells me, that you running against the main branch. If you do so, be aware that you might use implementations, wich could be work in progress and not meant for release yet.

I am currently working on an update of the documentation. The documentation will explain and extend the thought of the UI component library.

Oh I'm using the deprecated Components repo, I saw that you moved it inside the HTMLKit library but I wanted to avoid targeting 'main' so I can keep a stable version.

All the UI components come with a predefined CSS. Overriding the style is a discussion worth. I haven't thought about it. So if you use the components library, do you use the CSS file too? How did you get to manage it? I haven't released instructions yet :-)

Yes I'm using the css files :) and I agree that having a fixed style instead of being able to call '.style' would be closer to SwiftUI and preferable. I used your example website to understand how you set it all up and did the same 😁

mattesmohr commented 1 year ago

Ah, that's sharp!

Didn't suspect someone will use the component library. But am happy, someone do. If you miss something (similar or in comparison to SwiftUI), feel free to open an issue.

mattesmohr commented 1 year ago

Ups, sorry. Wrong button.

onepayclick commented 1 year ago

Just an update :) Projecting a Value to a .constant TemplateValue like this

func makeConstant<Value>(_ value: Value) -> TemplateValue<Value> {
    return .constant(value)
}

will cause a bug where the page will not update the content after the database/backend is updated. I assume its because the page is cached and the .dynamic uses the keyPath to get the new data.

mattesmohr commented 1 year ago

I want to let you know, that I remove the context management. You won't have this issue anymore. You can read more about in #118. You can already use the 3.0.0-alpha.1 release, if you like. But keep in mind its still alpha.