DavidMontani
DavidMontani

Reputation: 15

Passing List from Thymeleaf to Spring Controller

I'm trying to pass a List which is already provided in my Thymeleaf HTML back to the controller after changing the option. I've tried it with a hidden input, but unfortunately, it's not working yet.

My form looks like this (a List "movies" is already provided by the controller)

<form action="/movies" method="POST">
    <input type="hidden" th:field="*{movies}" name="movies"/>
    <select name="myselect" id="myselect" onchange="this.form.submit()">
        <option value="1">Sort by Name (A-Z)</option>
        <option value="2">Sort by Name (Z-A)</option>
        <option value="3">Newest First</option>
        <option value="4">Oldest First</option>
    </select>
</form>

And my Controller looks like this:

package at.spengergasse.omdbspring.controller;

import at.spengergasse.omdbspring.domain.Movie;
import at.spengergasse.omdbspring.service.MovieService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@RequiredArgsConstructor

@Controller
public class MoviesController {
    private final MovieService movieService;

    @GetMapping("/")
    public String greeting(Model model) {
        model.addAttribute("movies", movieService.findAll());
        return "movies";
    }

    @PostMapping("/movies")
    public String getMoviesOrdered(@RequestAttribute List<Movie> movies, @RequestParam String myselect, Model model){
        model.addAttribute(movieService.findCustomListSorted(movies,myselect));
        return "movies";
    }
}

Looking forward to someone you is able to help me!

Upvotes: 0

Views: 7294

Answers (4)

Szakalakamaka
Szakalakamaka

Reputation: 21

@RequestBody List<Movie> movies

worked for me only when I added

consumes="application/json; charset=utf-8"

which is not always what you want to do. Also the accepted answer with the wrapper object works, but it would be simpler just to declare global variable for all controller methods:

@RequiredArgsConstructor
@Controller
public class MoviesController {
    private final MovieService movieService;
    private final Set<Movie> movieSet = new HashSet<>();

    @GetMapping("/")
    public String greeting(Model model) {
        movieSet.addAll("movies", movieService.findAll());
        model.addAttribute("movies", movieSet);
        return "movies";
    }

    @PostMapping("/movies")
    public String getMoviesOrdered(@RequestParam String myselect, Model model){
        model.addAttribute(movieService.findCustomListSorted(movieSet, myselect));
        return "movies";
    }
}

and populate or read the list in each method.

Upvotes: 0

Sumit
Sumit

Reputation: 957

I've got the same issue in my Project Where the Hidden List value is already provided by Controller and then the same value needs to be passed further to controller. I've got it resolved using @ModelAttribute annotation (I'm pasting same code of mine as per your Requirements) :---

1.) Create an object of the form (which needs to send further to controller after form submit) on the controller where you're sending the movies :-

    model.addAttribute("some_value", new YourDesiredJavaClass());

2.) Create Thymeleaf object on the form by the same name - "some_value" in this case :--

<form action="/movies" th:object="${some_value}" method="POST">
    <input th:field="${movies}" type="hidden" ></input>
</form>

3.) get the List from Thymleaf To controller . :--

 @PostMapping("movies")
         public String getMovies(@ModelAttribute("some_value") YourDesiredJavaClass requestClass, Model model) {

// further code ..

}


4.) Create the Request class with setter & getter methods . :---

  public class YourDesiredJavaClass{

       private List<String> movies;

      //setter & getter methods

    }

Upvotes: 1

victor gallet
victor gallet

Reputation: 1898

As your list of movies is sent by your form, it will be available in HTTP POST body. So you have to use @RequestBody instead of @RequestAttribute.

@PostMapping("/movies")
public String getMoviesOrdered(@RequestBody List<Movie> movies, @RequestParam String myselect, Model model){
    model.addAttribute(movieService.findCustomListSorted(movies,myselect));
    return "movies";
}

Upvotes: 1

Conor Thompson
Conor Thompson

Reputation: 308

If I understand your question correctly, you want to call on a list of movies when you click a select field, and add the movies to some div? This can be done by an AJAX call to the controller, so that upon completion it will then populate the div with the content, if that makes sense:

    function getMoviesOrdered(myselect){
    var prep = {};
    prep['movies'] = myselect;

    var data = JSON.stringify(prep);
    $.ajax({
  url:"/movies",
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  error:function(){},
  complete:function(data){
  document.getElementById("#someDivId").innerHTML = data;
  }
    });
}

Upvotes: 0

Related Questions