gene b.
gene b.

Reputation: 12026

Spring Thymeleaf - Call Service Method Boolean for Display of HTML Item

In my Header HTML I display a UL/LI Menu where the visiblity of one of the LI items depends on a Service method call.

I tried this:

HomeController

@Controller
public class HomeController {
    private static final Logger log = LogManager.getLogger(HomeController.class);

    @Autowired 
    private EtdService etdService;

    @GetMapping("/home")
    public String home(Model model) throws EtdException {

        model.addAttribute("tierTemplate", etdService.getTierTemplate());  
        // Also tried this explicitly
        model.addAttribute("etdService", etdService);
        return "home";
    }
}

Service Interface (EtdService)

public interface EtdService {
  boolean isChangeUserAllowed();
}

Service Implementation (EtdServiceImpl)

@Component
public class EtdServiceImpl implements EtdService {

    @Override
    public boolean isChangeUserAllowed() {
        System.out.println("Got here");
        return false;
    }

}

HTML:

<li th:if="${@etdService.isChangeUserAllowed()}" class="nav-item dropdown" id="changeUserPanel" role="presentation">
<!-- ... Definition of this LI -- note can't put a new DIV in a UL list ... -->
</li>

Error:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'etdService' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:772) ~[spring-beans-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221) ~[spring-beans-5.1.4.RELEASE.jar:5.1.4.RELEASE]

Upvotes: 3

Views: 1855

Answers (2)

gene b.
gene b.

Reputation: 12026

In addition to the answer by bphilipnyc (set the direct value into the model),

model.addAttribute("isChangeUserAllowed", etdService.isChangeUserAllowed());

If you need to globalize common Model Attributes without re-adding every time, a solution is a @ControllerAdvice class with a @ModelAttribute, e.g.

/**
 * This class is used to globalize common Model Attributes without re-adding every time
 * The approach is to mark it as @ControllerAdvice to make it apply to every Controller method, 
 * and implement a @ModelAttribute Model-Adder to append to the model on every Controller method.
 */

// Makes the methods of this class apply to all Controller Request methods
@ControllerAdvice
public class GlobalController {

    @Autowired
    MyService myService;

    @ModelAttribute   // A Model Attribute Adder method
    public void setGlobalModelAttributes(HttpServletRequest request, Model model) {

        model.addAttribute("isChangeUserAllowed", myService.isChangeUserAllowed());
        model.addAttribute("currentUserFullName", myService.getCurrentUserFullName());

    }       
}

Some more examples

https://stackoverflow.com/a/33879102/1005607

https://www.baeldung.com/spring-mvc-and-the-modelattribute-annotation

Upvotes: 3

riddle_me_this
riddle_me_this

Reputation: 9155

You are referencing an instance method in Thymeleaf. Here are two options:

1) Reference it by adding the value of the boolean to the model:

@GetMapping("/home")
public String home(Model model) throws EtdException {

   //...
   model.addAttribute("isChangeUserAllowed", etdService.isChangeUserAllowed());
   return "home";
}

And in your HTML: th:if="${isChangeUserAllowed}"

To avoid NPEs, you can alternatively use #bools.isTrue(isChangeUserAllowed) or the appropriate method in the bools utility.

This is the preferred way and the path that the Thymeleaf documentation takes. A clear benefit is that the front-end is now not tied to the service.

2) Reference it statically instead (not recommended):

Error trying call method from view Thymeleaf Spring


Aside: the recommended way is to use constructor injection instead of autowiring.

Upvotes: 2

Related Questions