wallwalker
wallwalker

Reputation: 621

Thymeleaf renders to one page errors on another

I can return a list of cars to localhost:8080/list but not in localhost:8080/car. My goal is to render the list just below the Car Form in car.html.

I have tried two scenarios when rendering a list using Thymeleaf : With controller method getAllCars() mapped to /list I'm able to render the list on list.html however with the same method mapped to /car I get en error when trying to render to car.html.

I'm sure there is something small that I'm missing here. Perhaps its my use of controller methods when trying to render the list on car.html. The html I successfully used on list.html is the same I use when I add it to car.html with the Car Form. I simply comment/uncomment the necessary code to attempt each scenario.

Working Scenario : Using getAllCars() method in CarController mapped to list.html

@Controller
public class CarController {

    @Autowired
    private CarService carService;

    //PRESENT VIEW car.html
    @GetMapping("/car")
    public String carForm(Model model) {
        model.addAttribute("car", new Car());
        return "car";
    }

    //GET list of cars. render to /list
    @RequestMapping("/list")
    public String getAllCars(Model model) {
        model.addAttribute("cars", carService.getAllCars());
        return "list";
    }

    //GET list of cars. Render to /car
//    @RequestMapping("/car")
//    public String getAllCars(Model model) {
//        model.addAttribute("cars", carService.getAllCars());
//        return "car";
//    }

    //POST TO DATABASE
    @PostMapping("/car")
    public void carSubmit(@ModelAttribute Car car) {
        carService.addCar(car);
    }

}

list.html --> this works fine

This is the html code

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Car List</h1>

<table>
    <thead>
        <tr>
            <th>Id</th>
            <th>Make</th>
            <th>Model</th>
            <th>Year</th>
        </tr>
    </thead>
    <tbody>
        <!-- if true, display this       -->
        <tr th:if="${!cars}">
            <td colspan="2"> No Cars Available</td>
        </tr>
        <!--  otherwise, iterate over list and display info      -->
        <tr th:each="car : ${cars}">
            <td><span th:text="${car.id}">Id</span></td>
            <td><span th:text="${car.make}">Make</span></td>
            <td><span th:text="${car.model}">Model</span></td>
            <td><span th:text="${car.year}">Year</span></td>

    </tbody>
</table>
</body>
</html>

Non-Working Scenario : Using getAllCars() method in CarController mapped to car.html

For brevity, see commented getAllCars() method in above CarController car.html --> this does not work

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Car Form</h1>
<form action="#" th:action="@{/car}" th:object="${car}" method="post">
    <p>Id: <input type="text" th:field="*{id}" /></p>
    <p>Make: <input type="text" th:field="*{make}" /></p>
    <p>Model: <input type="text" th:field="*{model}" /></p>
    <p>Year: <input type="text" th:field="*{year}" /></p>
    <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>

<h1>Car List</h1>

<table>
    <thead>
    <tr>
        <th>Id</th>
        <th>Make</th>
        <th>Model</th>
        <th>Year</th>
    </tr>
    </thead>
    <tbody>
    <!-- if true, display this       -->
    <tr th:if="${!cars}">
        <td colspan="2"> No Cars Available</td>
    </tr>
    <!--  otherwise, iterate over list and display info      -->
    <tr th:each="car : ${cars}">
        <td><span th:text="${car.id}">Id</span></td>
        <td><span th:text="${car.make}">Make</span></td>
        <td><span th:text="${car.model}">Model</span></td>
        <td><span th:text="${car.year}">Year</span></td>

    </tbody>
</table>
</body>
</html>

And this is the error I am facing

2019-08-27 12:30:32.519 ERROR 22384 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "car": Exception evaluating SpringEL expression: "!cars" (template: "car" - line 33, col 9)

org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "!cars" (template: "car" - line 33, col 9)

Upvotes: 0

Views: 175

Answers (3)

Avijit Barua
Avijit Barua

Reputation: 3086

I think I got your problem. You are redirecting to car.html page with controller

 @GetMapping("/car")
    public String carForm(Model model) {
        model.addAttribute("car", new Car());
        return "car";
    }

In the same page you are both showing your car list and saving with form. But you hadn't put cars with a model in this controller. That's why you are getting a template error. To resolve this problem you need to put cars in the previous controller. So modify your controller

 @GetMapping("/car")
    public String carForm(Model model) {
        model.addAttribute("car", new Car());
        return "car";
    }

to

@GetMapping("/car")
public String carForm(Model model) {
    model.addAttribute("car", new Car());
    model.addAttribute("cars", carService.getAllCars());
    return "car";
}

Now after posting car you have to redirects to a page. But you didn't do that. So modify your controller

 @PostMapping("/car")
    public void carSubmit(@ModelAttribute Car car) {
        carService.addCar(car);
    }

to

 @PostMapping("/car")
    public String carSubmit(@ModelAttribute Car car) {
        carService.addCar(car);
        return "redirect:/car"
    }

Hope it will work. Give a shout!

Upvotes: 1

ANSALKHAN K A
ANSALKHAN K A

Reputation: 1

I think the issue is that, you are redirecting to car.html with 2 different methods. So only the first one, ie

@GetMapping("/car")
public String carForm(Model model) {
   model.addAttribute("car", new Car());
   return "car";
}

is working and not,

@RequestMapping("/car")
    public String getAllCars(Model model) {
    model.addAttribute("cars", carService.getAllCars());
    return "car";
}

so either you can do like,

@GetMapping("/car")
public String carForm(Model model) {
   model.addAttribute("car", new Car());
   return getAllCars(model);
}

or use any one method exactly, or even give different url mappings for both

Also please let me know why exactly you have commented out the getallcars method? Are you getting any ambiguous mapping error while uncommenting the method.

Upvotes: 0

Mark
Mark

Reputation: 5239

It's saying there's an issue with the expresion !cars which can be found in your car template:

    <tr th:if="${!cars}">
        <td colspan="2"> No Cars Available</td>
    </tr>

However the attribute passed to the car template in carForm is car and not cars.

Upvotes: 0

Related Questions