Thymeleaf: How to use fragment parameter in expressions - spring

Is there a way to use a fragment parameter in an expression?
I'd like to create a fragment to show fields with their corresponding binding errors e.g. like:
<div th:fragment="alert (field, fieldLabel)">
<label><span th:text="${fieldLabel}">Label:</span><input type="text" th:errorclass="field_error" th:field="*{field}"/></label>
<div th:if="${#fields.hasErrors(field)}"><span th:errors="*{field}">Some error</span></div>
</div>
Getting the fragment with:
<div th:replace=":: alert (field='firstName', fieldLabel='Firstname')">Field</div>
How do I use the field parameter in the expressions for the th:field and th:errors attributes? *{field} does at least not work.

With Thymeleaf 2.1 I've been using the following:
Declare field:
<input type="password" th:field="*{password}" />
Show possible errors related to password:
<div th:replace="util/form :: field-errors('password')"></div>
And this prints all the errors related to given field:
<div class="error-container help-block"
th:fragment="field-errors(field)"
th:if="${#fields.hasErrors('__${field}__')}">
<ul>
<li th:each="error : ${#fields.errors('__${field}__')}"
th:text="${error}" />
</ul>
</div>

It seems that it is not possible at least
using th:field and th:errors, it keeps trying to look for a bean instead
of the parameter of the fragment.
Try setting a local variable for the DOM object
th:with="variableName=${field}"
An then try to use that variable in the expressions.

Related

Thymeleaf setting object attribute based on click

What I am trying to do set object user variable attribute based on click.
`
<form class="container" th:action="#{/processSignup}" method="post"
th:object="${user}">
<div class="switch">
<div class="MenteeSignUp" onclick="tab1();" th:onclick="*{}" >Mentee</div>
<div class="MentorSignUp" onclick="tab2();" th:value="MENTOR" th:field="*{userRole}">Mentor</div>
</div>
`
Trying to add different role-based what user click which either mentor or mentee which you can see from the screenshot.
I am kind of new to thyme leaf, so I tried to have th:onClick and then tried to assign it but it didn't work
form
The code you have there doesn't really make sense. <div />s do not have a value attribute, and the expression in a th:onclick must be valid javascript (instead you have a blank selection variable expressions: th:onclick="*{}"). Maybe you're looking for something like this?
<form class="container" th:action="#{/processSignup}" method="post" th:object="${user}">
<input type="hidden" th:field="*{userRole}" id="userRole" />
<div class="switch">
<div class="MenteeSignUp" onclick="document.getElementById('userRole').value = 'MENTEE';">Mentee</div>
<div class="MentorSignUp" onclick="document.getElementById('userRole').value = 'MENTOR';">Mentor</div>
</div>

executing a template returns an unexpected <define> error

In this code, I am trying to set the navbar and I am defining nav in each file because for some files, the navbar will log in or signup but for some files, it will be log out or about. No file is giving me errors except this login.html and the error is
Error
panic: template: login.html:7: unexpected <define> in command
code
{{template "base" .}}
{{define "title"}} Log In {{end}}
{{define "body"}}
{{if .Loggedin}}
{{define "nav"}} // this is line 7 which is showing error.
<div>
About
Logout
</div>
{{end}}
{{else}}
<h1> Log In</h1>
<p>Login to access your account.</p>
<hr>
<form action="/loggedin" method="POST" name="login" id="login">
<div>
<label for="email">Email</label>
<input type="email" name="email", placeholder="Enter your email address" required>
</div>
<div>
<label for="password">Password</label>
<input type="password" name="password", placeholder="Enter the password" required>
</div>
<div>
<input type="submit" value="Login">
</div>
</form>
{{end}}
{{end}}
Quoting from package doc of text/template, Nested template definitions:
Template definitions must appear at the top level of the template, much like global variables in a Go program.
You can't define a template inside another template definition (and that's what you're doing).
Also note that {{define}} just defines a template, it does not include / execute it.
To define and execute a template in place, use {{block}}.
In your case move the template definition to the top level, and execute it where it's needed using the {{template}} action.
If you need different template definitions based on certain conditions, that's not possible.
What's possible is define different templates (with different names), and include the one you need based on the conditions.
Another option is to pass some data (the conditions) to the template, and make it render different things based on the template parameters (the conditions) with e.g. using the {{if}} action.
See related for even more options: How to use a field of struct or variable value as template name?

Thymeleaf + Spring. Using an object method instead another block in the form

I have a typical updateUser form built with Thymeleaf + Spring. I can list the user roles but I am trying to put these into a selectbox component. I am struggling with this line th:selected="${user.hasRole(role.role)}". Now, I know this component works and that is only a matter of access a boolean function to enable it. I am trying to reference a function of the form object using the select th:object. My syntax doesn't work. I have also try to access that function just like previous input tags would (only using the name without the object itself .ie username or in this case hasRole(). That doesn't work either.
<form th:object="${user}"
th:action="#{'/admin/usermanagement/adduser'} " method="post">
<div class="row">
<div class="col-md-3 form-group">
<label>Username:</label> <input type="text" class="form-control"
th:field="*{username}" />
</div>
</div>
<div class="col-md-3">
<h5>Roles :</h5>
</div>
<select class="js-example-basic-multiple" style="width: 75%"
name="froles" id="froles" multiple="multiple">
<option th:each="role : ${roles}" th:value="${role.role}"
th:selected="${user.hasRole(role.role)}"
th:text="${role.role}"></option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
In fact, my problem is types. th:selected="${user.hasRole(role.role)}" is a string and should be th:selected="${user.hasRole(role)}". I have both method in the domain object so that is fine.
th:value="${role.role}" is wrong for persistence. I want to return role but I get the following error message when I use role.role
codes [user.roles,roles]; arguments []; default message [roles]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property
and Java null exception when I use "${role}"

xPath how to access input text file with generic name

Is there any option to access input in code like this:
(...)
<div class="dialogProp">
<div class="gwt-Label">Name</div>
<div class="floatLeft">
<div>
<input type="text" class="textBox">
</div>
<div class="notVisible"></div>
</div>
<div class="dialogProp">
<div class="gwt-Label">Surname</div>
<div class="floatLeft">
<div>
<input type="text" class="textBox">
</div>
<div class="notVisible"></div>
</div>
(...)
As you can see I got two inputs and only difference between them is label inside of div with different text inside. This kind of pattern can be found all around of website and I cannot change this. I can not add id's as well.
Do you know if there is possibility to add to the xPath this different text inside of div's?
Let's say I would like to access first input.
Of course I could use some ass long xPath, but I would like to reuse this with text inside of gwt-Label as variable.
Use below to locate input by label text:
//div[#class="gwt-Label" and .="Name"]/following-sibling::div//input
In Python you can pass label from variable:
label = "Name"
xpath = '//div[#class="gwt-Label" and .="%s"]/following-sibling::div//input' % label
To access the input with respect to the label text you can use the following solution:
labelText = "Name"
#or labelText = "Surname"
xpath = "//div[#class='gwt-Label' and contains(.,'" +labelText+ "')]//following::div[1]//input"

CSS selector path for text box that comes immediately after h3 with text "Company Name"

Below is my html
<div class="right" data-bindattr-13="13">
<h3>Company Name</h3>
<div class="input-row">
<input id="ember4258" class="ember-view ember-text-field" type="text"/>
</div>
<h3>Full Company Legal Name</h3>
<div class="input-row">
<input id="ember4259" class="ember-view ember-text-field" type="text"/>
</div>
<h3>Company Phone</h3>
<div class="input-row">
<input id="ember4260" class="ember-view ember-text-field" type="text"/>
</div>
<h3>Federal Tax / Employer ID (EIN)</h3>
<div class="input-row">
<input id="ember4261" class="ember-view ember-text-field" type="text"/>
</div>
</div>
Since class value off all the text fields and respective parent div class attributes are same I need to fill these text fields without using nth-of-type.
I have done work around to create a CSS selector that should point the text box that is immediately after <h3>Full Company Legal Name</h3> .
h3:contains(^Company Name$)+div>input
But my Capybara script is not recognizing the above way and throwing the below error.
annotateInvalidSelectorError_': The given selector h3:contains(^Company Name$)+div>input is either invalid or does not result in a WebElement. The following error occurred: (Selenium::WebDriver::Error::InvalidSelectorError)
InvalidSelectorError: An invalid or illegal selector was specified
Can any one provide a CSS that matches my requirement?
Regards,
Avinash Duggirala
The contains pseudo class was deprecated, which is why the InvalidSelectorError occurs. There is currently no way to check text nodes using CSS-selectors.
Instead, you can use XPath to traverse the DOM to sibling elements.
text_field = page.find(:xpath, '//h3[text() = "Company Name"]/following-sibling::div[1]/input')
text_field.set('some value')

Resources