Thymeleaf recursion not working - html

I'm trying to create a recursive list using Thymeleaf. I'm using a simple Java object to model a node which has has two fields, a description and then an array list of child nodes. I'm using the following HTML/Thymeleaf to process the structure but it isn't recursively iterating through to the next level down.
My Java code looks as follows:
public class Node {
public String description;
public ArrayList<Node> children;
}
My Thymeleaf/HTML code is as follows:
<html>
...
<body>
<div th:fragment="fragment_node" th:remove="tag">
<ul th:if="${not #lists.isEmpty(node.children)}" >
<li th:each="child : ${node.children}"
th:text="${child.description}"
th:with="node = ${child}"
th:include="this::fragment_node">List Item</li>
</ul>
</div>
</body>
</html>
If my data structure looks as follows:
Main node 1
Child node 1
Child node 2
Main node 2
Child node 3
Child node 4
I'd expect to get:
<ul>
<li>Main Node 1</li>
<li>
<ul>
<li>Child node 1</li>
<li>Child node 2</li>
</ul>
</li>
<li>Main Node 2</li>
<li>
<ul>
<li>Child node 3</li>
<li>Child node 4</li>
</ul>
</li>
</ul>
However, I only get:
<ul>
<li>Main Node 1</li>
<li>Main Node 2</li>
</ul>
Can anyone spot why this may not be working?

The cause of the problem is
You are trying to th:text and trying to add the description to a <li> as well as you are trying to th:include the fragment inside the same tag <li>.
Your th:include is replaced by the th:text as th:text is processed with priority by default.
Direct solution to your source code
.....
<li th:each="child : ${node.children}" th:inline="text" th:with="node = ${child}">
[[${child.description}]]
<ul th:replace="this::fragment_node">List Item</ul>
</li>
.....
Even thought the above will work as you want, personally I find some design issues in your thymeleaf page.
Better solution using fragment parameters
...
<ul th:fragment="fragment_node(node)" th:unless="${#lists.isEmpty(node.children)}" >
<li th:each="child : ${node.children}" th:inline="text">
[[${child.description}]]
<ul th:replace="this::fragment_node(${child})"></ul>
</li>
</ul>
...

Related

Regex open Li tag inside ul tag

Hi I am try to amke regexp which extract only li tags in ul tags (no ol)
Text:
<ul><li>some text</li></ul>
<ol><li>some text</li></lo>
Extracted
<ul>**<li>**some text</li></ul>
<ol><li>some text</li></lo>
Could you help me ?
Solution 1
Regex solution
/(?<=<ul>\s*(?:<li>.*?<\/li>\s*)*)<li>.*?<\/li>/gi
Demo
If you work in a team and someone else may read your code I advise you to use Solution 2. It's more simple and easy to understand by code reading.
Solution 2
Do it in 2 steps:
Delete all <ol>...</ol> nodes;
Take all <li>...</li> nodes.
*I assume your html is valid and you have no <li> outside <ul> or <ol>.
Code example in JavaScript:
let html = `
<ul>
<li>take this node 1</li>
<li>take this node 2</li>
</ul>
<ol>
<li>exclude this node</li>
<li>exclude this node</li>
</ol>
<ul>
<li>take this node 3</li>
<li>take this node 4</li>
</ul>
<ol>
<li>exclude this node</li>
<li>exclude this node</li>
</ol>
`;
let htmlWithoutOl = html.replace(/<ol>.*?<\/ol>/gis, '');
let matches = htmlWithoutOl.matchAll(/<li>.*?<\/li>/gis);
for (const match of matches) {
console.log(match[0]);
}

Build HTML popup with packages [duplicate]

This question already has answers here:
Property does not exist on type 'DetailedHTMLProps, HTMLDivElement>' with React 16
(4 answers)
Closed 3 years ago.
I have to build an html popup inside a react component but I get errors
from this code
<div>
<button class="toggle">Button</button>
<div id="link-box">
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
</div>
error:
Type '{ children: string; class: string; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
Property 'class' does not exist on type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
I'd like to accomplish this without a react npm package for dropdown menus.
If I have to do some really rudimentary html with later css styling that okay. But I need some insight into what are the issues I'm facing how to best proceed.
More of File code:
export class Header extends React.Component<IHeaderProps, IHeaderState> {
public handleChange() {
console.log('handling');
}
public render() {
return (
<div>
<button class="toggle">Button</button>
<div id="link-box">
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
</div>
);
}
}
About the error you are facing, if you could provide the typescript code of the component then we could look for a solution.
By the way since you are using React you could set a Modal to popup when certain buttons are clicked.
These are some Modal examples .
And this is a Modal tutorial that doesn't require to install any npm package, which may be what you are looking for.

Why is my attribute selector working when it doesn't have any whitespace in it?

MDN states the following about the [attr~=value] attribute selector:
Represents elements with an attribute name of attr whose value is a
whitespace-separated list of words, one of which is exactly value.
If liquid is not separated by whitespace, then why is it working?
[data-vegetable~="liquid"] {
color: red;
}
Ingredients for my recipe: <i lang="fr-FR">Poulet basquaise</i>
<ul>
<li data-quantity="1kg" data-vegetable>Tomatoes</li>
<li data-quantity="3" data-vegetable>Onions</li>
<li data-quantity="3" data-vegetable>Garlic</li>
<li data-quantity="700g" data-vegetable="not spicy like chili">Red pepper</li>
<li data-quantity="2kg" data-meat>Chicken</li>
<li data-quantity="optional 150g" data-meat>Bacon bits</li>
<li data-quantity="optional 10ml" data-vegetable="liquid">Olive oil</li>
<li data-quantity="25cl" data-vegetable="liquid">White wine</li>
</ul>
It's not separated by whitespace but:
a whitespace-separated list of words
Which mean a list of words where you have whitespace between and if alone no need whitespace because there is nothing to separate.
[data-vegetable~="liquid"] {
color: red;
}
<ul>
<li data-vegetable="liquid other and other">this one</li>
<li data-vegetable="liquid">and this one</li>
<li data-vegetable="liquid ">also this one</li>
<li data-vegetable="another liquid ">also this one</li>
<li data-vegetable="liquid-one">NOT this one !!</li>
<li data-vegetable="another-liquid">NOT this one !!</li>
<li data-vegetable="aliquid">NOT this one !!</li>
</ul>
For the last ones you will need *
[data-vegetable*="liquid"] {
color: red;
}
<ul>
<li data-vegetable="liquid other and other">this one</li>
<li data-vegetable="liquid">and this one</li>
<li data-vegetable="liquid ">also this one</li>
<li data-vegetable="another liquid ">also this one</li>
<li data-vegetable="liquid-one">this one too!!</li>
<li data-vegetable="another-liquid">this one too!!</li>
<li data-vegetable="aliquid">this one too!!</li>
</ul>
A list of words has separators between the words.
If the list contains only one word, there are no separators
What that means is, the attribute (data-vegetable in this case) can have multiple values, assigned to it in one string using whitespace to delimit the values, like data-vegetable="liquid foo bar", which gives data-vegetable three values 'liquid', 'foo' and 'bar'.
The selector can be used to match any of these values, so you will get this element when matching either [data-vegetable~="liquid"], [data-vegetable~="foo"] or [data-vegetable~="bar"].
It said: "whitespace-separated list of words"
That means that it is a list, separated by whitespace. But a list can have only one item. So in that case, no spaces are needed.

How to add class to kramdown-generated table of content?

I would like to add few Bootstrap classes to <ul id="markdown-toc">. How can I do it?
Input:
* ToC
{:toc}
Output:
<ul id="markdown-toc">
<li>Welcome</li>
<li>Header 1</li>
</ul>
Add the class name you want to apply as an IAL:
* TOC
{:toc}
{: .this-is-my-class}
Then it will generate:
<ul class="this-is-my-class" id="markdown-toc">
<li>..</li>
</ul>

Mootools - getFirst().get('text') not a function?

the HTML:
<ul id="nav">
<li id="listItem">a list item</li>
<li id="link01">list item with ID</li>
<li id="link02">another link with ID</li>
<li class="lastItem">Contact</li>
<li class="lastItem">the Very Last List Item</li>
</ul>
the JavaScript:
alert($$('.lastItem').getFirst('li').get('text'));
console returns this error:
TypeError: $$(...).getFirst(...).get is not a function
um...whut? what did i miss? if i take out the getFirst(), it works, but returns, of course, both <li> text contents... which i don't want. just want the first...
halp.
WR!
You trying to call getFirst on Elements array($$ return elements array!) the getFirst() method is only on a dom mootools element and it will return his first child
what you are looking for is this:
alert($$('.lastItem')[0].get('text'));