Closed enthus1ast closed 1 month ago
Any plans to add fragments to Nimja ?
I think you can use the self variable for this: https://github.com/enthus1ast/nimja?tab=readme-ov-file#self-variable
Circling back to this, is there any chance you can show an example of how Nimja can compile a partial template? I read the docs but I still can't figure out how to render just a partial/fragment of a larger Nimja template.
I am currently using Python for this, with the flask partial library, but I would love to move everything over to Nim/Nimja if possible.
Thank you!
@greenersharp can you show an example what you want to archive?
Maybe even with code from your jinja2 code.
When i look at the fragment library i think you can do the same with nimja.
You currently cannot bind a context to importnimja
(you can with compileTemplateFile).
But you can just define new variables in a scope
(which is like a nim block
).
And since child templates have access to the outer variables (in fact the same scoping rules like in nim apply)
this should just do it.
So for example:
foo
{% for entry in entries %}
{% scope %}
{% let user = entry.user %}
{% let another = entry.another %}
{% importnimja "templates/partials/_oneUser.nimja" %}
{% end %}
{% endfor %}
baa
The benefit of using scope is, that you do not pollute the outer template with vars.
In the above example it would not make much sense, because the iteration body leaves scope any how.
But in general using scope
works good for this and i use it quite often.
_oneUser.nimja
{# renders one user #}
{{ user.name }}
{{ another }}
And if you want to create a "one user" page:
oneUser.nimja
{% extends some/base.nimja %}
{% block content %}
{# get the user somehow #}
{% let user = getUserFromDb() %}
{% let another = getOtherFromDb() %}
{% importnimja "templates/partials/_oneUser.nimja" %}
{% endblock %}
Is this what you need?
Thanks for the reply!
Here is the python library I was referring to: https://github.com/sponsfreixes/jinja2-fragments
It's commonly used alongside HTMX to render small pieces of a larger template. The link above gives a simple example of using the render_block method to render one small piece of a larger template.
It really helps cut down the number of template files in a project.
@greenersharp have you seen my other message? Is that what you need?
ah i see:
return render_block("page.html.jinja2", "content", magic_number=42)
yeah i think this could actually be nice.
Awesome! The feature would pair really well with HTMX.
I am not 100% sure how it should behave though, but i'll have a closer look.
hey @greenersharp if you like you can test the change.
edit: templateFragment branch https://github.com/enthus1ast/nimja/tree/templateFragment
I'm still in the process of writing tests for it ( https://github.com/enthus1ast/nimja/blob/d9b7682d91e021608c5353392849d16538dd48ac/tests/basic/test_fragments.nim )
the usage:
you call compileTemplateStr
or compileTemplateFile
like normal,
but now you can specify blockToRender
then it should just render this one block.
proc foo(blockToRender: static string): string =
compileTemplateStr("""
BUG
{% block first %}first block{% endblock %}
{% block second %}second block{% endblock %}
BUG
""", blockToRender = blockToRender)
check "first block" == foo("first")
check "second block" == foo("second")
Ah btw, if it works for you, are you interested to write an "real world" example for this? For the example folder? Maybe even with htmx (if you can condense the stuff in a small self contained example).
Great, thank you so much, I'll definitely try and get a simple working example going
While doing this PR i also played with htmx (for the first time). And i like it.
If you write even a very simple example SPA, like a to-do app in vuejs or react, you end up with thousands of lines of boilerplate code.
With HTMX all that boilerplate code is gone. It's really refreshing.
And the nimja/htmx combo might very well be the fastest out there.
I'm traveling at the moment but I'll definitely work on the parital example !
On Mon, Sep 16, 2024, 8:32 PM David Krause @.***> wrote:
While doing this PR i also played with htmx (for the first time). And i like it.
— Reply to this email directly, view it on GitHub https://github.com/enthus1ast/nimja/issues/82#issuecomment-2353628614, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZABNLWOQVR4FY4ZSUSXXKDZW4P5XAVCNFSM6AAAAAAQME5FPGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNJTGYZDQNRRGQ . You are receiving this because you were mentioned.Message ID: @.***>
It works amazingly well. Thank you so much for adding this feature!
I'm new to nim and still learning, but does 'blocktorender' need to be a static string? it would be great if it could be mutable if possible.
Imagine a use case where the rendered block (if any) is conditional on a url query parameter, something like this:
let url = request.uri.parseUrl
var block = ""
if "block" in url.query:
block = url.query["block"]
request.respond(200, headers, tmplf("index.nimja",baseDir = getScriptDir(),blocktorender=block))
This way I only need to write request.respond
once, and I either leave blocktorender empty if I want the whole page rendered, or I set it to a string if I need a partial.
Right now my code looks like this:
if block:
request.respond(200, headers, tmplf("index.nimja",baseDir = getScriptDir(),blocktorender=block))
else:
request.respond(200, headers, tmplf("index.nimja",baseDir = getScriptDir()))
Thank you
Yes it's a static string, I don't think there is a way around this unfortunately. It needs to compile a fresh proc for you when you change the parameters. Then on runtime it's fast.
Nevertheless, I'll look into this problem.
I can imagine that a case statement could work, where you list all the routes explicitly.
Edit: and/or you could create a macro or template, that create the different routes for you.
https://htmx.org/essays/template-fragments/