th:replace doesn't work well with th:with in Thymeleaf - spring-boot

According to Thymeleaf docs
Fragments can include any th:* attributes. These attributes will be evaluated once the fragment is included into the target template (the one with the th:insert/th:replace attribute), and they will be able to reference any context variables defined in this target template.
My Fragment
<div th:fragment="link">
<a th:href="#{${url}}"><span th:inline="text">[[${text}]]</span></a>
</div>
This is how I include it.
<div th:replace="fragments/common :: link" th:with="url='www.google.com', text='Click Me'"></div>
The html i get
<a href="">
<span>null</span>
</a>
However the same works fine with th:include and gives me following HTML.
<a href="www.google.com">
<span>Click Me</span>
</a>
Why th:replace doesn't work while th:inlcude works fine?
NOTE: th:insert is out of scope because i am using Thymeleaf v2.1.5

The reason is that th:replace actually removes current tag so you lose every attribute you had there, but get all the attributes from fragment. And in your case this means that you never defined any th:with variable in the scope.th:include works the opposite way. You loose fragment tag, but keep everything defined in layout.
Consider this fragment:
<fragmenttag th:fragment="link" style="background-color: red">...</fragmenttag>
And layout:
<layouttag th:include="fragments/common :: link" style="font-size: 250%;"/>
<layouttag th:replace="fragments/common :: link" style="font-size: 250%;"/>
The result is:
<layouttag style="font-size: 250%;">Some Text</layouttag>
<fragmenttag style="background-color: red">Some Text</fragmenttag>
If you want to use th:replace, because you have some important attributes in fragment, you can define everything you need in some parent tag in layout.
<body th:with="url='www.google.com', text='Click Me'">
<div th:replace="fragments/common :: link" ></div>
</body>
You are referencing documentation in your post:
Fragments can include any th:* attributes. These attributes will be
evaluated once the fragment is included into the target template (the
one with the th:insert/th:replace attribute), and they will be able to
reference any context variables defined in this target template.
And i don't see any contradiction here, because this part of the documentation is about th:* attributes inside a fragment.
Fragments (th:fragment part) can include any th:* attributes.
And in your question you are talking about loosing th:* attributes defined in target template. But anyway, this part is quite strait that you perform inclusion logic first
These attributes will be evaluated once the fragment is included
There is nothing here that lets you assume that you will get everything you defined in target template or fragments main tag, because both of them can be replaced depending on witch inclusion strategy you are going to use (th:insert/th:replace).
So you defined th:with="url='www.google.com', text='Click Me'" attribute, but it was never included in the end result template because you selected th:replace inclusion strategy, so th:with attribute was never evaluated and you got no url and text variables in scope. No contradiction here.

Seems like a similar (not same) issue thank the one mentined in this post
As a workaround for this issue you can still use th:include and then remove the extra div by using th:remove="tag", something like:
<div th:include="fragments/common :: link" th:with="url='www.google.com', text='Click Me'" th:remove="tag"></div>

Related

Blade templating variable reference

I have a list of items which I want to render in the following way:
#foreach($campaignList as $campaign)
<div class="col-md-{{12/$columns}}">
#include('admin.includes.campaign_card',['campaign'=>$campaign,'link'=>true])
</div>
#endforeach
The admin.includes.campaign_card template (with debug)
#extends('admin.includes.base_campaign_card')
{{$campaign}} // Here the data is okay
#section('options')
{{$campaign}} //Here however I get the first item on each loop
#endsection
Basically the campaign object within the section remains the same when looping.
It seems that the issue is related to the fact that you can have just one section with a given name at a time.
There is way to force blade to rerender with #overwrite directive (which is not in the docs apparently) instead of #endsection.
Github comment

How to create a custom HTML div in Sphinx that isn't automatically nested within a subsubsection?

I'm using the wonderful Sphinx tool to create some documentation and I need to create a custom HTML div so that I can style it apart from Sphinx's other, automatically-created, divs.
This is possible to do using the container directive, but the problem is that if I use this directive below a subsubsection, it automatically nests the div created with the container directive within the subsubsection, like so:
<div id="automatically-created sphinx subsubsection">
...
<div id="my custom container"></div>
</div>
Whereas, I want:
<div id="automatically-created sphinx subsubsection">
...
</div>
<div id="my custom container"></div>
Is there any way to do this? Any help would be greatly appreciated!
Addendum:
One hacky way of potentially solving the problem is to create a new subsubsection so that Sphinx automatically places it on the same level as other subsubsections and then use CSS to hide its header etc. The problem with this approach, however, is that the new subsubsection automatically gets added to the sidebar in the RTD theme (which I'm using) and this is not what I want.
Untested. Try a super-hacky .. raw:: directive, where you would close the current section, then open a new unclosed <div>:
.. raw:: html
</div>
<div id="my custom container">
Then resume using reStructured text markup. This would "trick" Sphinx into thinking that the current section is still open and it would still add a closing </div> after the rest of your markup until it starts parsing the next section.

Handlebars template with "div" tag instead "script"

Actually the question is in the subj...
Is it possible to make handlebars template framework, to recognize templates within a div tag and not in script tag?
For example I would like to create template with this markup:
<style>
div.text-x-handlebars {display:none;}
</style>
<div class="text-x-handlebars-template">
<h2>I'm template</h2>
<p>{{welcomeMessage}}</p>
</div>
Yes you can put your templates in <div>s rather than <script>s, for example:
http://jsfiddle.net/ambiguous/RucqP/
However, doing so is fraught with danger. If you put your template inside a <div> then the browser will interpret it as HTML before you've filled it in; so, if your template's HTML isn't valid until after it has been filled in, the browser may attempt to correct it and make a mess of things. Also, if you have id attributes in your templates, then you will end up with duplicate ids (one in the template <div> and a repeat in the filled in template that you put in the DOM) and that will cause all sorts of strange and interesting bugs. The browser will also try to download any images inside the templates in a <div>, this may or may not be a problem (if might even be desirable but probably not desirable if the image uses a template variable in its src attribute).
Basically, you can do it but you shouldn't, you should put your templates in <script id="..." type="text/x-handlebars-template"> elements instead.

The part of the view after an `extend` statement is not rendered

I'm trying to use the extend keyword to add a comment-box (a view placed under default/comment_box.html) across several of my views, by:
...
<hr/>
{{extend "default/comment_box.html"}}
<span id="master">
...
But, when this executes, all the part of the view after the extend statement is not being rendered and all I'm getting is:
...
<hr/>
<!--Content from the Comment-Box-->
As you can see, the part after the extend statement, i.e. <span id="master"> has gone missing. The Web2Py examples seem to be doing it the same way. Am I missing something here? Why is it truncating abruptly after the extend statement?
I think you want:
{{include 'default/comment_box.html'}}
If you use {{extend 'default/comment_box.html'}}, the comment_box.html view must contain an {{include}} directive somewhere, in which case, the content of the extending view gets included in place of that {{include}} directive. On the other hand, if you simply want to include the contents of comment_box.html within your view, you need to use {{include 'default/comment_box.html'}}.
See here for more on extend and include.

Blogger template: Style blog post based on label

I'm trying to change the style of a blog post (for instance change the title color), based on the labels associated to the post.
I'm a bit new to the templating, so I though I would be going to add a class with the label in the title <h3> element, and then add my CSS rules.
So I found this which would generate a proper list of labels separated by a space:
<b:loop values='data:post.labels' var='label'><data:label.name/> </b:loop>
However, it seems the validator does not let me add this inside the class attribute as follow:
<h3 class='post-title entry-title <b:loop values="data:post.labels" var="label"><data:label.name/> </b:loop>'>
From there, I found half the solution. Apparently, I should use expr:class instead of class as follow:
<h3 expr:class='"post-title entry-title " + data:list_of_labels'>
So now:
- How can I build this variable data:list_of_labels? (basically how to set a variable)
- Is there a full description of the template syntax somewhere?
- Is there another way to go around this?
Thanks,
JB
This should do it. Using XML entities allows you bypass the XML validation and move the Blogger functions to where you need them. Longer explanation here: http://www.karlhorky.com/2012/06/add-blogger-labels-to-post-as-css.html
<div class="post<b:if cond="data:post.labels"><b:loop values="data:post.labels" var="label"> <data:label.name></data:label.name></b:loop></b:if>">
<data:post.body>
</div>
There is no way to set variables in the blogger data xml, however you can set variables using javascript.
There are many pages on the blogger data xml. Google is your friend. For example this one.
You are on the right track: do a loop, use javascript to check for the combinations you want, change the style properties or load a css file dynamically.

Resources