The checked attribute of the checkbox is not set in th:each.

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

The checked attribute of the checkbox is not set in th:each.

smallfish
Hi,
Here are codes:
<ul>
        <li th:each="role : ${resource.roles}"><input type="checkbox"
                th:field="*{roles}" th:value="${role.id}" th:checked="${true}" /> <label
                th:text="${role.name}">ROLE_USER</label></li>
</ul>

Why the checked attribute of the checkbox is not set?There are not any checked attributes in rendered page.
But the follwing code works well.It's not in th:each.
    <input type="checkbox"
                 th:checked="${true}" />
And I notice that comments in Thymeleaf-Spring tutorial:"Also note that if our features property contained some selected values in our form-backing bean, th:field would have taken care of that and would have added a checked="checked" attribute to the corresponding input tags."
Could you provide any examples?
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

danielfernandez
Administrator
Hi,

In the following fragment of your code:

smallfish wrote
<ul>
        <li th:each="role : ${resource.roles}"><input type="checkbox"
                th:field="*{roles}" th:value="${role.id}" th:checked="${true}" /> <label
                th:text="${role.name}">ROLE_USER</label></li>
</ul>
...you do not need that "th:checked" attribute at all. The th:field="*{roles}" attribute should take care of checking each of the values in the "roles" property of your form-backing bean so that, when one of the elements equals ${role.id} (the value set in the "th:value" attribute), thymeleaf will automatically write a checked="checked" attribute into your checkbox tag.

Trying to exemplify, let's say:

   1. Your form-backing bean (th:object) is called "form"...
   2. ...and form.getRoles() returns an array of Integers [23, 43, 76] (the roles currently selected)...
   3. ...and role.getId() returns an Integer...
   4. ...and resource.roles contains roles with ids [10, 20, 23, 43, 46, 76]

Thymeleaf will do the following:

  1. Iterate for 10. 10 is not contained in form.getRoles() --> No checked attribute.
  2. Iterate for 20. 20 is not contained in form.getRoles() --> No checked attribute.
  3. Iterate for 23. 23 IS contained in form.getRoles() --> checked="checked" attribute.
  4. Iterate for 45. 45 IS contained in form.getRoles() --> checked="checked" attribute.
  5. Iterate for 46. 46 is not contained in form.getRoles() --> No checked attribute.
  6. Iterate for 76. 76 IS contained in form.getRoles() --> checked="checked" attribute.

If this does not work for you, verify that:

  1. The type of the array/list/set returned by form.getRoles() corresponds to the type returned by role.getId() (e.g. Integer, String, etc). This is, if form.getRoles() returns an array of Role objects (instead of Integers), then your th:value attribute should have "${role}" as value instead of "${role.id}".

  2. The type returned by these methods correctly implements "equals()". Integer of course implements it, but if form.getRoles() returns Role[] and you rewrite th:value as "${role}", you should make sure the Role class implements "equals" so that Thymeleaf can know when a value is really contained in the roles array.


If after this explanation this still does not work for you, please give me more details about the type returned by form.getRoles() and role.getId() so that I can track any possible issues.


Regards,
Daniel.

Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

smallfish
There is a fragment of the controller codes.
smallfish wrote
        @RequestMapping(value = "{id}/edit", method = RequestMethod.GET)
        public String getEditForm(@PathVariable long id, Model model) {

                ResourceInfo resourceInfo = resourceService.load(id);
                Resource resource = new Resource();
                BeanUtils.copyProperties(resourceInfo, resource);
               
                resource.setRoles(new HashSet<Role>());
                Iterator iter = resourceInfo.getRoles().iterator();
                while (iter.hasNext()) {
                        RoleInfo roleInfo = (RoleInfo) iter.next();
                        Role role = new Role();
                        BeanUtils.copyProperties(roleInfo, role);
                        resource.getRoles().add(role);

                }

                HashSet<Long> allRoles = new HashSet<Long>();
                List<RoleInfo> roles = roleService.getAllRoles();
                iter = roles.iterator();
                while (iter.hasNext()) {
                        RoleInfo roleInfo = (RoleInfo) iter.next();

                        allRoles.add(roleInfo .getId());

                }
                model.addAttribute("roles", allRoles);

                model.addAttribute(resource);

                return "resource/editForm";
        }
The roles attribute has been put into the model.I have not yet seen any checked marks.
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

danielfernandez
Administrator

Ok.

From your initial fragment of code I had understood that you were using a form-backing bean with a "getRoles()" method (which is the correct use for the th:field="*{roles}" attribute in your checkboxes), but now I see you are not using a form-backing bean at all.

With your controller setup, using th:field makes no sense at all, because you have no object modelling your form data. Instead, you should use only the "name", "th:value" and "th:checked" attributes.

The "name" attribute will set the name of your request parameter. The "th:value" is probably OK with "role.id" value, and the "th:checked" attribute will probably need the use of a #sets.contains() function (have a look at appendix in the "Using Thymeleaf" tutorial for this.

Regards,
Daniel.
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

smallfish
Is like this setting?
<ul>
        <li th:each="role : ${resource.roles}"><input type="checkbox"
                th:field="*{roles}" th:value="${role.id}" th:checked="${#sets.contains(roles,role.id)}" /> <label
                th:text="${role.name}">ROLE_USER</label></li>
</ul>

But I haven't seen any ticks.
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

smallfish

<input type="checkbox"
                 th:checked="${true}" />

<input type="checkbox" th:field="*{roles}"
                 th:checked="${true}" />

The first checkbox is checked and the second checkbox is not checked.Why?
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

danielfernandez
Administrator
Hi,

As I said in a previous message, having no form-backing bean, yo do not need that th:field at all.

The code you need would be something like:

<ul>
  <li th:each="role : ${resource.roles}"><input type="checkbox"
      name="roles" th:value="${role.id}" th:checked="${#sets.contains(roles,role.id)}" /> <label
      th:text="${role.name}">ROLE_USER</label></li>
</ul>

Your code:
smallfish wrote
<ul>
        <li th:each="role : ${resource.roles}"><input type="checkbox"
                th:field="*{roles}" th:value="${role.id}" th:checked="${#sets.contains(roles,role.id)}" /> <label
                th:text="${role.name}">ROLE_USER</label></li>
</ul>
...does not work mainly because you should not specify th:field AND th:checked at the same time in that scenario (th:field will try to override what you set in th:checked). But you should not specify th:field either because of not using a form-backing bean, so th:checked is enough.

Regards,
Daniel.
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

smallfish
But the following codes will cause an exception.
        <input type="checkbox" th:checked="${true}" th:value="${1}"/>
Here  is the exception.
smallfish wrote
java.lang.RuntimeException: 没有说明名称空间前缀“th”。
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.getNamespaceURI(SerializerBase.java:895)
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.addAttribute(SerializerBase.java:422)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:197)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:226)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:226)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:226)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:226)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:132)
        at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:94)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:661)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:707)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313)
        at org.thymeleaf.OutputHandler.output(OutputHandler.java:113)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:671)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:570)
        at org.thymeleaf.spring3.view.ThymeleafView.render(ThymeleafView.java:201)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:113)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:368)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.crusoe.myauth.filter.MySecurityInterceptor.invoke(MySecurityInterceptor.java:56)
        at org.crusoe.myauth.filter.MySecurityInterceptor.doFilter(MySecurityInterceptor.java:47)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:119)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
        at java.lang.Thread.run(Thread.java:619)

This code works well.
<input type="checkbox"
                 th:checked="${true}" />
Reply | Threaded
Open this post in threaded view
|

Re: The checked attribute of the checkbox is not set in th:each.

danielfernandez
Administrator
Hello,

This is a bug, you are right. It's just been fixed in a snapshot version (1.0.0-beta3-20110620.224148-3)

https://sourceforge.net/tracker/?func=detail&aid=3323477&group_id=509826&atid=2072659

For using a snapshot version, you should configure Sonatype OSS snapshot repositories (https://oss.sonatype.org/content/repositories/snapshots/)

Regards,
Daniel.