I'm trying to request two numbers (first and second) as input via a form using Thymeleaf, and have the numbers added and the answer returned. The code is run from:
http://localhost:8080/add
I've based the program on this link:
https://spring.io/guides/gs/validating-form-input/
I'm also using the latest version of Springboot, currently 1.5.8.
I'm finding this simple task becoming somewhat convoluted (compared to say python), with continual errors that aren't making any sense. My current problem is I'm getting the following error, which even after checking similar posts online, I can't resolve...
Error:
"Exception processing template "add": Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'"
Based on these posts I've change "long" to "Long" in my NumberForm, and moved my NumberForm.java under "sec.calculator", but no joy...
Any help would be appreciated !
Here's my code:
1) src/main/java
CalculatorController.java:
package sec.calculator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class CalculatorController {
#GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("add", new NumberForm());
return "add";
}
#PostMapping("/add")
public String addSubmit(#ModelAttribute NumberForm add) {
return "result";
}
}
------------------------------------
CalculatorApplication.java
package sec.calculator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CalculatorApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(CalculatorApplication.class, args);
}
}
------------------------------------
NumberForm.java
package sec.calculator;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
/**import javax.validation.constraints.Size;
*/
public class NumberForm {
#NotNull
#Min(0)
private Long first;
private Long second;
public Long add_out;
public Long add_output() {
return add_out ;
}
public void Setfirst(Long first) {
this.first = first;
}
public void Setsecond(Long second) {
this.second = second;
}
}
-----------------------------------
2) src/main/resources/templates
add.html
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project
Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Form</h1>
<form action="#" th:action="#{/add}" th:object="${NumberForm}" method="post">
<p>First: <input type="text" th:field="*{First}" /></p>
<p>Second: <input type="text" th:field="*{Second}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
------------------------------------------
Welcome to SO.
There are several issues here. In particular, Java is very much case-sensitive.
Follow the convention for setters so that Thymeleaf can
understand it:
public void setFirst(Long first) {
this.first = first;
}
public void setSecond(Long second) {
this.second = second;
}
I am assuming you left out the analogous getter methods.
Even better, see Project Lombok - stop the madness entirely and use
#Setter and #Getter or #Data.
In your form, lower-case your field names:
<p>First: <input type="text" th:field="*{first}" /></p>
<p>Second: <input type="text" th:field="*{second}" /></p>
I'd also stay away from variable names like these since they can become very confusing.
Also in your form, you are using th:object="${NumberForm}" but
you named your variable add. Thymeleaf knows nothing about this variable named NumberForm. Your variable is named add of a type NumberForm, but Thymeleaf will need the name of the variable here.
So you can do: model.addAttribute("numberForm", new
NumberForm());
and th:object="${numberForm}"
Using lower-case for your th:object (modelAttribute) is by
convention.
You'll actually need to include some code to sum the values. I'll
leave that part for you.
Related
In my below given code i cant get java arraylist value inside javascript. I am new to java and play framework kindly guide me.
/* This is controller code */
package controllers;
import play.*;
import play.mvc.*;
import views.html.*;
import play.data.*;
import java.util.List;
import java.util.ArrayList;
public class Application extends Controller {
public static Result playGraph() {
List<String> dashboardList = new ArrayList<String>();
dashboardList.add("{First Value}");
dashboardList.add("{Second Value}");
return ok(playGraph.render(dashboardList));
}
}
/****** The above controller code is working fine the problem is only in template******
/******Template page playGraph.scala.html ************/
#(dashboardList:List[String])
#main("All Graph") {
Size:#dashboardList.size()
<br>
1st Value: #dashboardList.get(0); <!--This line prints First Value-->
<br>
2nd Value: #dashboardList.get(1);<!--This line prints Second Value-->
<script>
alert(#dashboardList.size());//Alert shows 2
alert(#dashboardList.get(0)); // ==> Not working
</script>
}
In this above code i cannot get #dashboardList.get(0) value in javascript but #dashboardList.size() is working.
I am understanding how to handle JS events like onfocus and onblur in apache wicket. I have a simple form in which there is a textfield. "onfocus" event on this I am trying to set the textfield to a value. I have observed on running the code that onfocus is called again and again (recursively it seems). I fail to understand why and what I have done wrong.
Below is the code :
HTML:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
<head>
<title>Wicket Examples - component reference</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<form wicket:id="form">
<INPUT wicket:id="input" type="text" name="input" style="WIDTH: 800px" />
</form>
Java:
package com.poc.pages;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;
public class IndexPage extends WebPage
{
/**
* Constructor
*/
public IndexPage()
{
Form form = new Form("form");
TextField<String> TextInput = new TextField<String>("input",Model.of(""));
TextInput.add(new AjaxFormComponentUpdatingBehavior("onfocus"){
#Override
protected void onUpdate(AjaxRequestTarget target) {
String thisValue =
this.getComponent().getDefaultModelObjectAsString();
thisValue = "ChangedNormally";
this.getComponent().setDefaultModelObject("ChangedViaDefaultSetModel");
target.add(this.getComponent());
System.out.println("onfocus"+thisValue);
}
});
form.add(TextInput);
add(form);
}
}
When I focus on textfield here, ChangedViaDefaultSetModel is set and on console onfocusChangedNormally gets print continuously. I fail to undertsand few things :
Why does onfocus gets called again and again printing onfocusChangedNormally evertytime on console?
How can I get the value of actual model and not default model.
WHy does the normal value doesnot get reflected in model whereas on doing setDefaultModel() it works?
Thanks For Help
1) This behavior, you implmented, is a little tricky. When you focus your TextField and add this component to the target, then AjaxRequest is updating it. When update is over, component must return its state, thats why focus gained and your behavior method onUpdate is called again.
To resolve this problem you must use some kind of blocking. The easiest way is to use boolean field and check if focus was already gained to prevent another update. (see the code below).
2) Second and third question is about models, and this is very large subject to discuss. You can learn more by reading this and this articles, or "Wicket in Action" and "Wicket cookbook" books.
In my solution I used PropertyModel, that reflects the value of the field you set as a model of the Component. This code:new PropertyModel<String>(this, "modelValue") means that Wicket must search field with name "modelValue" in this (IndexPage) object and set as the model of TextField. That's why now you can only change this object field to set another value to TextField (don't forget to update component after that).
Comments for code:
I have used AjaxEventBehavior but it's ok to use AjaxFormComponentUpdatingBehavior.
I have added onblur behavior to return old value of the TextField just to show possibilities of this solution.
I have changed TextInput to textInput because code conventions said so.
package com.poc.pages;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.PropertyModel;
public class IndexPage extends WebPage {
private String modelValue = "ChangedNormally";
private boolean focusGained = false;
public IndexPage() {
Form form = new Form("form");
TextField<String> textInput = new TextField<String>("input", new PropertyModel<String>(this, "modelValue"));
textInput.add(new AjaxEventBehavior( "onfocus" ) {
#Override
protected void onEvent(AjaxRequestTarget target) {
if (!focusGained) {
modelValue = "ChangedViaDefaultSetModel";
target.add(this.getComponent());
focusGained = true;
System.out.println( "focus gained " + getComponent().getDefaultModelObject() );
}
}
});
textInput.add(new AjaxEventBehavior( "onblur" ) {
#Override
protected void onEvent(AjaxRequestTarget target) {
modelValue = "ChangedNormally";
target.add(this.getComponent());
focusGained = false;
System.out.println( "focus lost " + getComponent().getDefaultModelObject() );
}
});
form.add(textInput);
add(form);
}
}
Hope this helps.
I'm coding a program in java that take a few information from a graph (X axis and Y axis), and then I need to take this information and pass to a JSP page.
this is the java
package view;
public class Axis{
double[] axisX;
double[] axisY;
int test;
public Axis(){
}
public void setAxisX(double[] axisX){
this.axisX = axisX;
}
public void setAxisY(double[] axisY){
this.axisY = axisY;
}
public double[] getAxisX(){
return axisX;
}
public double[] getAxisY(){
return axisY;
}
}
Then in the JSP is this what I have to do?
<jsp:useBean id="view" class="view.Axis" scope="session"/>
Test: <%= view.getAxisX() %>
What you are basically trying to do is use Standard Actions :
<jsp:useBean id="view" class="view.Axis" scope="session"/>
<br> X :<jsp:getProperty name="view" property="axisX" />
<br> Y :<jsp:getProperty name="view" property="axisY" />
You can use EL/JSTL for this instead of Standard Actions.
Also read ,
How to avoid Java Code in JSP-Files?
I'm learning the development flow of Play Framework following this tutorial http://www.playframework.com/documentation/2.1.1/JavaTodoList.
However I'm getting this compilation error at index.scala.html view:
"value description is not a member of Product"
It's my Product's model:
package app.models;
import java.util.*;
import javax.validation.*;
import play.data.validation.Constraints.*;
/**
* Product.
*/
public class Product
{
public int id;
public String name;
public String description;
public String dimensions;
public double price;
public static List<Product> all()
{
return new ArrayList<Product>();
}
public static void create(Product product)
{
return;
}
public static void delete(Long id)
{
return;
}
}
And here is the view's code:
#(products: List[Product], productForm: Form[Product])
#import helper._
#main("ezbuy") {
<h1>#products.size() product(s)</h1>
<ul>
#for(product <- products) {
<li>
#product.description
#form(routes.Application.deleteProduct(product.id)) {
<input type="submit" value="Delete">
}
</li>
}
</ul>
<h2>Add a new product</h2>
#form(routes.Application.newProduct()) {
#inputText(productForm("label"))
<input type="submit" value="Create">
}
}
I'm just not finding where is the problem, since I've declared the Product's list at the top of the view and it's looping using the #for statement.
Thanks in advance.
There is a Scala class scala.Product (http://www.scala-lang.org/api/current/index.html#scala.Product). Scala automatically imports all from the scala package. I think you got that class and not app.models.Product.
Use the fully qualified class name:
#(products: List[app.models.Product], productForm: Form[app.models.Product])
That error does not occur if you put Product directly into the models package, since models.* are imported by default in Scala templates of Play. So there would be no need to use the fully qualified class name.
I am a newbie to play and have started to develop an application to fetch the data from database.
I have the following code in my application:
public static Result list() {
List products = Productslist.getListOfProducts();
return ok(index.render(products));
}
and this gives me the following error:
Actual List cannot be converted to String on method invocation conversion
You can also view my index.scala.html
#{extends 'main.html' /}
#{set title:'Cars in the car lot' /}
<h1>Products in Lot</h1>
<table border=1>
<tr>
<td>productname</td>
<td>Quantity</td>
<td>Price</td>
</tr>
#{list items:products, as:'product'}
<tr>
<td>${product.getProductname()}</td>
<td>${product.getQuantity()}</td>
<td>${product.getPrice()}</td>
</tr>
#{/list}
</table>
The complete code for Application.java is:
package controllers;
import play.*;
import play.mvc.*;
import models.Productslist;
import views.html.*;
import views.*;
import java.util.*;
public class Application extends Controller
{
public static Result list()
{
List products = Productslist.getListOfProducts();
return ok(index.render(products));
}
}
Can anyone help me find the source of the error?
Look like you used the wrong code for the view. Try this instead
#(products: List[Productslist])
#import helper._
#main("Product list") {
<h1>#product.size() product(s)</h1>
<ul>
#for(product <- products) {
<li>
#product.name
</li>
}
</ul>
}
Use play clean-all before running your server
Looks like error is happening on index.render(products) ; where method render is expecting a string but we are passing list. Can you put in the code of method render()