ZK: zul get value from input form-data - html

I need a help about ZK framework. This is my situation.
I have a html page:
<form id="frm1" action="http://localhost:8080/spuWebApp" METHOD="POST">
<input type="hidden" id="codigoUnicoCliente" name="codigoUnicoCliente" value="00000050055255">
<input type="button" onclick="myFunction()" value="Invar Spu POST URL">
</form>
Then, after submitting the form, my zk project recieves the data in bridge.zul.
<?init class="com.ibm.ibk.spu.view.BridgeChecker"?>
This class contains the following
public class BridgeChecker extends BaseWindow implements Initiator{
#Override
public void doInit(Page arg0, Map<String, Object> arg1) throws Exception {
Bridge bridge = new Bridge();
logger.debug("ANTIGUA MANERA");
logger.debug(Executions.getCurrent().getParameterMap());
logger.debug(Executions.getCurrent().getArg());
logger.debug(Executions.getCurrent().getAttributes());
bridge.setClienteCodigoUnicoFromURL(Executions.getCurrent().getParameter("codigoUnicoCliente"));
But I cant read the value.
I am racking my brain a lot. But I couldnt succeed in find out how to read the values. Someone who can help me to read the form-data. I'd appreciate it a lot.
Thanks in advanced.

it work with Executions.getCurrent().getParameter("codigoUnicoCliente") but I do not know what myFunction() do, so I replace it with this code:
<form id="frm1" action="test.zul" METHOD="POST">
<input type="hidden" id="codigoUnicoCliente" name="codigoUnicoCliente" value="00000050055255">
<input type="submit" value="Invar Spu POST URL">
</form>
Then, I use following in test.zul
<window apply="org.zkoss.bind.BindComposer" viewModel="#id('vm') #init('test.vm.TestViewModel')">
and then in TestViewModel
#Init
public void init(#ContextParam(ContextType.SESSION) Session session) {
System.out.println(Executions.getCurrent().getParameter("codigoUnicoCliente"));
}
and work like charm :)

Related

How to initialize an external reference in Thymeleaf?

If I had a Java class called for instance Buffet and one of its fields was something like:
#ManyToOne
private Chef chef
and I had to create a new Buffet object in an html form using Thymeleaf, how would I be able to refer to this chef field? At the moment my html looks like this:
<form th:action="#{/newBuffet}" method="POST" th:object="${buffet}">
<div>
<div>
<span><input type="text" th:field="*{name}" placeholder="name"/></span>
</div>
<div>
<span><input type="text" th:field="*{chef}" placeholder="chef"/></span>
</div>
<div>
<span><button type="submit">Invio<i class="material-icons">done</i></button></span>
</div>
</div>
</form>
and my controller like this:
#RequestMapping(value = "/newBuffet", method = RequestMethod.GET)
public String formBuffet (Model model) {
model.addAttribute("buffet", new Buffet());
return "newBuffet.html";
}
#RequestMapping(value = "/newBuffet", method = RequestMethod.POST)
public String addBuffet (#ModelAttribute("buffet") Buffet b, Model model) {
this.buffetService.save(b);
model.addAttribute("buffets", this.buffetService.listBuffets());
return "buffets.html";
}
the error it gives is, of course, because of the way Thymeleaf's input takes only strings whilst my input is an instance of my class Chef.

Passing an array of ints from my HTML to Controller with Thymeleaf and SpringBoot

I am trying to pass an array of ints from my HTML back to my controller.
My flow is as follows:
I am retrieving data from an API and converting it to an Entity. All works fine.
However, I pass this to my HTML (Thymeleaf) and display some of the values to the User.
They then select one of the options and this is passed back to my Controller.
It is at this stage I lose the data I need.
In my Entity, I get the following data which I pass to the View (Example Below):
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "MOVIE_ID")
private long movieId;
#JsonProperty("title")
#Column(name = "TITLE")
private String title;
#JsonProperty("overview")
#Column(name = "OVERVIEW", length = 2000)
private String overview;
#JsonProperty("popularity")
#Column(name = "POPULARITY")
private float popularity;
#JsonProperty("release_date")
#Column(name = "RELEASE_DATE")
private String releaseDate;
#JsonProperty("genre_ids")
private int[] genreIds;
Then in my view, I display some values and hide the ids I dont need to display so that I can pass them back to my controller:
<form action = "#" th:action="#{/saveMovie}" method="post" th:object="${movie}">
<tr>
<td th:text="${movie.title}"></td>
<td th:text="${movie.releaseDate}"></td>
<td th:text="${movie.overview}"></td>
<input type="hidden" id="title" name="title" th:value="*{title}"/>
<input type="hidden" id="overview" name="overview" th:value="*{overview}"/>
<input type="hidden" id="popularity" name="popularity" th:value="*{popularity}"/>
<input type="hidden" id="releaseDate" name="releaseDate" th:value="*{releaseDate}"/>
<input type="hidden" id="genreIds" name="genreIds" th:value="*{genreIds}"/>
<td>
<div class="col-auto">
<button class="btn btn-primary" type="submit">Add</button>
</div>
</td>
</tr>
</form>
Controller to handle the call:
#PostMapping("/saveMovie") public String saveMovie(#ModelAttribute(value = "movie") Movie movie)
UPDATE***
Adding the GET/POST controllers that currently interact with this page:
#GetMapping("/searchMovie")
public String searchMovie(final Model model){
List<Movie> returnedMovies = new ArrayList<>();
model.addAttribute("movies", returnedMovies);
return "Search";
}
#PostMapping("/searchMovie")
public String searchMovieInTMDB(#RequestParam(value = "movieName", required = true) String movieName,
Model model){
List<Movie> returnedMovies = service.searchMovies(movieName);
model.addAttribute("movies", returnedMovies);
return "Search";
}
#PostMapping("/saveMovie")
public String saveMovie(#ModelAttribute(value = "movie") Movie movie){
service.storeMovie(movie);
return "WORK_IN_PROGRESS";
}
However, when I pass the values back to the controller I get the conversion error:
[Failed to convert property value of type 'java.lang.String' to required type 'int[]' for property 'genreIds']
I have changed it to String[] to test this works and error goes away but then I am presented with another problem in that it is converted to :
String Value Image
The only way I have found to pass the object back is by using the input tag and hiding them.
It converts the float fine, but can't handle the array of ints.
Is there a better way to pass objects back and forth between the controller using Thymeleaf or is there another attribute I can use to pass the array back and forth?
Thanks in advance
Conor
<form action="#" th:action="#{/saveMovie}" method="post"
th:object="${movie}">
<tr>
<td th:text="${movie.title}"></td>
<td th:text="${movie.releaseDate}"></td>
<td th:text="${movie.overview}"></td>
<input type="hidden" id="title" name="title" th:value="*{title}" />
<input type="hidden" id="overview" name="overview"
th:value="*{overview}" />
<input type="hidden" id="popularity" name="popularity"
th:value="*{popularity}" />
<input type="hidden" id="releaseDate" name="releaseDate"
th:value="*{releaseDate}" />
<input type="hidden" name="genreIds" th:field="*{genreIds}" />
<td>
<div class="col-auto">
<button class="btn btn-primary" type="submit">Add</button>
</div>
</td>
</tr>
</form>
#PostMapping("/saveMovie")
public String saveMovie(#ModelAttribute Movie movie) {
System.err.println(movie);
return "redirect:/movies";
}
#GetMapping("/movies")
public String getBooks(Model model) {
Movie movie = new Movie();
movie.setGenreIds(new int[] {4,5,6,7,8});
model.addAttribute("movie", movie);
return "movie";
}
Maybe You should send numbers as List to the controller.
#PostMapping("/saveMovie")
public String saveMovie(#RequestBody List<Movie> movies){
movieService.function_name(movies);
return "movies";
}
Another way to do this is using AJAX call to the controller. Just need to collect numbers as list in javascript and through ajax you should send array as json to controller. In controller you will parse them

Can I make HTTP POST request from Thymeleaf table in Spring Boot application

I have a Thymeleaf template in a simple Spring Boot application. The template contains a list in a table as follows:
<p>There are <span th:text="${#lists.size(persons)}"></span> people:</p>
<table th:if="${not #lists.isEmpty(persons)}" border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Telephone</th>
<th>Email</th>
<th>Actions</th>
</tr>
<tr th:each="person : ${persons}">
<td th:text="${person.personId}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.address}"></td>
<td th:text="${person.telephone}"></td>
<td th:text="${person.email}"></td>
<td>
Edit |
Delete
</td>
</tr>
</table>
I want to enable edit and delete functionality as per the last cell in the table. But at the moment both requests are for HTTP GET. That is fine for edit where a person's details are fetched from the server for editing, but delete should trigger a POST request because of the data changes on the server.
Does anyone know if Thymeleaf allow a POST request per row of a table? Or do I have to write a simple HTML form per row?
The GET form is currently:
<td>
Edit
<!--a href="#" data-th-href="#{/delete(personId=${person.personId})}">Delete</a></td-->
<form method="get" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value">Edit</button>
</form>
</td>
Where I have a link and a form for testing.
The controller method to be called is:
// Gets a Person.
#RequestMapping(value="/edit", method=RequestMethod.GET)
public String getEditPerson(#RequestParam("personId") String personId, Model model) {
logger.info(PersonController.class.getName() + ".getEditPerson() method called.");
Person person = personDAO.get(Integer.parseInt(personId));
model.addAttribute("person", person);
// Set view.
return "/edit";
}
The error when the button version of GET is called is:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Jul 24 00:26:16 BST 2016
There was an unexpected error (type=Bad Request, status=400).
Required String parameter 'personId' is not present`
I am using GET to trigger editing because no data is sent to the server here other than the personId. No database action is taken so it should be a GET.
you are using Links and I don't think that is possible, you would need to use a form where you can specify the method POST to be used.
In the example below im using a <button> instead of a <a> element, but it will work, the only thing you need to do is to style your button with CSS to look like your links
<form method="POST" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">This is a link that sends a POST request</button>
</form>
now in your code should look like this
<tr th:each="person : ${persons}">
<td th:text="${person.personId}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.address}"></td>
<td th:text="${person.telephone}"></td>
<td th:text="${person.email}"></td>
<td>
<form method="POST" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">EDIT</button>
</form> |
<form method="POST" th:action="#{/delete(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">DELETE</button>
</form>
</td>
</tr>
EDIT
As you just shared you Java code, in the controller you are expecting the personId not as a PathVariable, but as a RequestParam,
in that case your form should have that value...
edit your form and add the person id as follows.
<form method="POST" th:action="#{/edit}">
<input type="hidden" name="personid" id="personId" th:value="${person.personId}" />
<button type="submit" name="submit" value="value" class="link-button">This is a link that sends a POST request</button>
</form>
Notice also I changed the action of the form to be just /edit, as its what your controller looks like
Does anyone know if Thymeleaf allow a POST request per row of a table? Or do I have to write a simple HTML form per row?
HTML doesn't support POST request with links and you have to use forms (as Rayweb_on explained). But Thymeleaf allows you to define custom tags which helps a lot :
<a th:href="#{/edit(personId=${person.personId})}" custom:linkMethod="post">Edit</a>
... which would generate following HTML (assuming jQuery is available) :
Edit
Custom tag definition (without error checking to keep it simple) :
/**
* Custom attribute processor that allows to specify which method (get or post) is used on a standard link.
*/
public class LinkMethodAttrProcessor extends AbstractAttributeTagProcessor {
private static final String ATTR_NAME = "linkMethod";
private static final int PRECEDENCE = 10000;
public LinkMethodAttrProcessor(final String dialectPrefix) {
super(
TemplateMode.HTML, // This processor will apply only to HTML mode
dialectPrefix, // Prefix to be applied to name for matching
null, // No tag name: match any tag name
false, // No prefix to be applied to tag name
ATTR_NAME, // Name of the attribute that will be matched
true, // Apply dialect prefix to attribute name
PRECEDENCE, // Precedence (inside dialect's own precedence)
true); // Remove the matched attribute afterwards
}
#Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag,
final AttributeName attributeName, final String attributeValue,
final IElementTagStructureHandler structureHandler) {
// get the method name (tag parameter)
final IEngineConfiguration configuration = context.getConfiguration();
final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = parser.parseExpression(context, attributeValue);
final String method = (String) expression.execute(context);
// add custom javascript to change link method
final String link = tag.getAttribute("href").getValue();
final String action = "$('<form action="" + link + "" method="" + method + ""></form>').appendTo('body').submit(); return false;";
structureHandler.setAttribute("onclick", action);
structureHandler.setAttribute("href", "#");
}
}
See the Thymelead documentation for example of how this custom attribute needs to be registered.

How to display the values from one partial view control(Search) to a web grid partial view control?

In my view i have two partial views (Search,webgrid). When i click the update button in the search , the values filtered are not binding in the webgrid ? How can i do this?
You could try something like this. Hope I understood your question correctly.
search partial:
...
#using(Ajax.BeginForm("Search", new AjaxOptions(){UpdateTargetId = "SearchResults",
HttpMethod = "post" InsertionMode=InsertionMode.Replace})){
<input id="searchString" type="text" value="Search for this ..." />
<input type="submit" value="Search" />
}
...
controller:
[HttpPost]
public PartialViewResult Search(string searchString){
IList<Results> results = _service.Search(searchString);
return new PartialView("Webgrid", results)
}
webgrid partial:
#Model IList<Result>
<div id="SearchResults">
// Display Results
</div>
Didn't compile the code. Hope it is almost compileable.

HTML button calling an MVC Controller and Action method

I know this isn't right, but for the sake of illustration I'd like to do something like this:
<%= Html.Button("Action", "Controller") %>
My goal is to make an HTML button that will call my MVC controller's action method.
No need to use a form at all unless you want to post to the action. An input button (not submit) will do the trick.
<input type="button"
value="Go Somewhere Else"
onclick="location.href='<%: Url.Action("Action", "Controller") %>'" />
Razor syntax is here:
<input type="button" value="Create" onclick="location.href='#Url.Action("Create", "User")'" />
<button type="button" onclick="location.href='#Url.Action("MyAction", "MyController")'" />
type="button" prevents page from submitting, instead it performs your action.
Try this:
#Html.ActionLink("DisplayText", "Action", "Controller", route, attribute)
This should work for you.
You can use Url.Action to specify generate the url to a controller action, so you could use either of the following:
<form method="post" action="<%: Url.Action("About", "Home") %>">
<input type="submit" value="Click me to go to /Home/About" />
</form>
or:
<form action="#">
<input type="submit" onclick="parent.location='<%: Url.Action("About", "Home") %>';return false;" value="Click me to go to /Home/About" />
<input type="submit" onclick="parent.location='<%: Url.Action("Register", "Account") %>';return false;" value="Click me to go to /Account/Register" />
</form>
This is how you can submit your form to a specific controller and action method in Razor.
<input type="submit" value="Upload" onclick="location.href='#Url.Action("ActionName", "ControllerName")'" />
Building on couple of the above answers, you could do this:
<button onclick="location.href='#Url.Action("ActionName", "ControllerName")'" />
Of all the suggestions, nobdy used the razor syntax (this is with bootstrap styles as well). This will make a button that redirects to the Login view in the Account controller:
<form>
<button class="btn btn-primary" asp-action="Login" asp-
controller="Account">#Localizer["Login"]</button>
</form>
it's better use this example
<a href="#Url.Action("Register","Account", new {id=Item.id })"
class="btn btn-primary btn-lg">Register</a>
The HTML <button> element can only postback to the form containing it.
Therefore, you need to make a form that POSTs to the action, then put a <button> or <input type="submit" /> in the form.
So, I'm using Razor but this will work using either. I'm basically wrapping a button in a link.
<a href="Controller/ActionMethod">
<input type="button" value="Click Me" />
</a>
Despite onclick Method you can also use formaction as follows:
<button type="submit" id="button1" name="button1" formaction='#Url.Action("Action", "Controller")'>Save</button>
Use this example :
<button name="nameButton" id="idButton" title="your title" class="btn btn-secondary" onclick="location.href='#Url.Action( "Index","Controller" new { id = Item.id })';return false;">valueButton</button>
In case if you are getting an error as "unterminated string constant", use the following razor syntax :
<input type="button" onclick="#("location.href='"+ Url.Action("Index","Test")+ "'")" />
When you implement the action in the controller, use
return View("Index");
or
return RedirectToAction("Index");
where Index.cshtml (or the page that generates the action) page is already defined. Otherwise you are likely encountering "the view or its master was not found..." error.
Source: https://blogs.msdn.microsoft.com/aspnetue/2010/09/17/best-practices-for-asp-net-mvc/
If you are in home page ("/Home/Index") and you would like to call Index action of Admin controller, following would work for you.
<li>Admin</li>
it's better use this example.
Call action and controller using a ActionLink:
#Html.ActionLink("Submit", "Action", "Controller", route, new { #class = "btn btn-block"})
OK, you basically need to pass the action to the button and call it when click happens, it doesn't need to be inside a from, you can use HTML onclick on button to trigger it when the button get clicked...
<button id="my-button" onclick="location.href='#Url.Action("YourActionName", "YourControllerName")'">Submit</button>
You can always play around with htmlHelpers and build some stuff
public static IHtmlContent BtnWithAction(this IHtmlHelper htmlHelper, string id, string text, string css="", string action="", string controller="")
{
try
{
string str = $"<button id=\"{id}\" class=\"{css}\" type=\"button\" ###>{text}</button>";
if (!string.IsNullOrEmpty(action) && !string.IsNullOrEmpty(controller))
{
string url = ((TagBuilder)htmlHelper.ActionLink("dummy", action, controller)).Attributes["href"];
var click = !string.IsNullOrEmpty(url) ? $"onclick=\"location.href='{url}'\"" : string.Empty;
return new HtmlString(str.Replace("###", click));
}
return new HtmlString(str.Replace("###", string.Empty));
}
catch (Exception ex)
{
Log.Error(ex, ex.Message);
var fkup = "<script>alert(\"assumption is the mother of all failures\")</script>";
return new HtmlString(fkup);
}
}
And then on the view call it like this
#Html.BtnWithAction("btnCaretakerBack", "Back", "btn btn-primary float-right", "Index", "Caretakers")