I'm using bean validation(JSR303) to validate two fields, those fields are validate with an annotation and a validator, the annotation targeted the type that means the annotation is a class level constraint of my bean.
The question is how do I express the error on my view?
(I'm using groovy)
SignupForm :
package core.model
import core.validation.PasswordConfirmation
import core.validation.UniqueEmail
import core.validation.UniqueUsername
import groovy.util.logging.Slf4j
import org.hibernate.validator.constraints.Email
import org.hibernate.validator.constraints.NotBlank
import static core.model.AuthoritiesEnum.ROLE_USER
#Slf4j
#PasswordConfirmation
class SignupForm {
static final String NOT_BLANK_MESSAGE = "{notBlank.message}"
static final String UNIQUE_USERNAME_MESSAGE = "{uniqueUsername.message}"
static final String EMAIL_MESSAGE = "{username.message}"
static final String UNIQUE_EMAIL_MESSAGE = "{uniqueEmail.message}"
#UniqueUsername
#NotBlank(message = SignupForm.NOT_BLANK_MESSAGE)
String username
#UniqueEmail
#NotBlank(message = SignupForm.NOT_BLANK_MESSAGE)
#Email(message = SignupForm.EMAIL_MESSAGE)
String email
#NotBlank(message = SignupForm.NOT_BLANK_MESSAGE)
String password
#NotBlank(message = SignupForm.NOT_BLANK_MESSAGE)
String confirmPassword
User createAccount() {
new User(username: email, email: email, password: password, role: ROLE_USER)
}
}
PasswordConfirmation validation annotation :
package core.validation
import javax.validation.Constraint
import javax.validation.Payload
import java.lang.annotation.Retention
import java.lang.annotation.Target
import static java.lang.annotation.ElementType.TYPE
import static java.lang.annotation.RetentionPolicy.RUNTIME
#Target(TYPE)
#Retention(RUNTIME)
#Constraint(validatedBy = PasswordConfirmationValidator)
#interface PasswordConfirmation {
String message() default "{core.signup.validation.passwordConfirmation.message}"
Class<?>[] groups() default []
Class<? extends Payload>[] payload() default []
}
Password confirmation validator :
package core.validation
import core.model.SignupForm
import groovy.util.logging.Slf4j
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
#Slf4j
class PasswordConfirmationValidator implements ConstraintValidator<PasswordConfirmation, SignupForm> {
#Override
void initialize(PasswordConfirmation constraintAnnotation) {
}
#Override
boolean isValid(SignupForm form, ConstraintValidatorContext context) {
log.info "password : ${form.password}"
log.info "confirmPassword : ${form.confirmPassword}"
println "password : ${form.password}"
println "confirmPassword : ${form.confirmPassword}"
println "defaultConstraintMessageTemplate : ${context.defaultConstraintMessageTemplate}"
form.password.equals form.confirmPassword
}
}
the thymeleaf view signup.html :
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{view.signup.title}">Inscription</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="../../../resources/css/bootstrap.min.css" rel="stylesheet" media="screen"
th:href="#{/resources/css/bootstrap.min.css}"/>
<link href="../../../resources/css/core.css" rel="stylesheet" media="screen" th:href="#{/resources/css/core.css}"/>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="../../../resources/js/bootstrap.min.js" th:src="#{/resources/js/bootstrap.min.js}"></script>
</head>
<body>
<div th:replace="fragments/header_signup :: header">Header</div>
<form class="form-narrow form-horizontal" method="post"
th:action="#{/signup}" th:object="${signupForm}">
<!-- /* Show general error message when form contains errors */ -->
<th:block th:if="${#fields.hasErrors('${signupForm.*}')}">
<div th:replace="fragments/alert :: alert (type='danger', message='Form contains errors. Please try again.')">
Alert
</div>
</th:block>
<fieldset>
<div class="form-group" th:classappend="${#fields.hasErrors('username')}? 'has-error'">
<label for="username" class="col-lg-2 control-label">Username</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="username" placeholder="Username" th:field="*{username}"/>
<span class="help-block" th:if="${#fields.hasErrors('username')}"
th:errors="*{username}">Incorrect username</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('email')}? 'has-error'">
<label for="email" class="col-lg-2 control-label">Email</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="email" placeholder="Email address" th:field="*{email}"/>
<span class="help-block" th:if="${#fields.hasErrors('email')}"
th:errors="*{email}">Incorrect email</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('password')}? 'has-error'">
<label for="password" class="col-lg-2 control-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="password" placeholder="Password"
th:field="*{password}"/>
<span class="help-block" th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Incorrect password</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('confirmPassword')}? 'has-error'">
<label for="confirmPassword" class="col-lg-2 control-label">Password confirmation</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="confirmPassword" placeholder="Password confirmation"
th:field="*{confirmPassword}"/>
<!--how to show classe level constraint validation-->
<span class="help-block" th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}">Incorrect password confirmation</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit" class="btn btn-default" th:text="#{view.signup.label}">Sign up</button>
</div>
</div>
</fieldset>
</form>
</body>
</html>
In order to show a class level constraint message I succeeded by using the global constant, like in the updated html code as shown in the documentation
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{view.signup.title}">Inscription</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="../../../resources/css/bootstrap.min.css" rel="stylesheet" media="screen"
th:href="#{/resources/css/bootstrap.min.css}"/>
<link href="../../../resources/css/core.css" rel="stylesheet" media="screen" th:href="#{/resources/css/core.css}"/>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="../../../resources/js/bootstrap.min.js" th:src="#{/resources/js/bootstrap.min.js}"></script>
</head>
<body>
<div th:replace="fragments/header_signup :: header">Header</div>
<form class="form-narrow form-horizontal" method="post"
th:action="#{/signup}" th:object="${signupForm}">
<!-- /* Show general error message when form contains errors */ -->
<th:block th:if="${#fields.hasErrors('${signupForm.*}')}">
<div th:replace="fragments/alert :: alert (type='danger', message='Form contains errors. Please try again.')">
Alert
</div>
</th:block>
<fieldset>
<div class="form-group" th:classappend="${#fields.hasErrors('username')}? 'has-error'">
<label for="username" class="col-lg-2 control-label">Username</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="username" placeholder="Username" th:field="*{username}"/>
<span class="help-block" th:if="${#fields.hasErrors('username')}"
th:errors="*{username}">Incorrect username</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('email')}? 'has-error'">
<label for="email" class="col-lg-2 control-label">Email</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="email" placeholder="Email address" th:field="*{email}"/>
<span class="help-block" th:if="${#fields.hasErrors('email')}"
th:errors="*{email}">Incorrect email</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('password')}? 'has-error'">
<label for="password" class="col-lg-2 control-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="password" placeholder="Password"
th:field="*{password}"/>
<span class="help-block" th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Incorrect password</span>
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('confirmPassword')}? 'has-error'">
<label for="confirmPassword" class="col-lg-2 control-label">Password confirmation</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="confirmPassword" placeholder="Password confirmation"
th:field="*{confirmPassword}"/>
<span class="help-block" th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}">Incorrect password confirmation</span>
<span class="help-block" th:if="${#fields.hasErrors('global')}" th:errors="*{global}">Incorrect password confirmation</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit" class="btn btn-default" th:text="#{view.signup.label}">Sign up</button>
</div>
</div>
</fieldset>
</form>
</body>
</html>
Related
so.. I have a registration page and there are a lot of validations in there but my binding result is always false. After a few tries I found the problem but I don't know the solution. When I pass a parameter in the /processRegistrationForm method it doesn't work but when I delete the #RequestParam it works. Why the passed parameter is influencing the binding result and how can I resolve this?
registration-form.html
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Register New User Form</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Reference Bootstrap files -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
.error {color:red}
</style>
</head>
<body>
<div>
<div id="loginbox" style="margin-top: 50px;"
class="mainbox col-md-3 col-md-offset-2 col-sm-6 col-sm-offset-2">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="panel-title">Register New User</div>
</div>
<div style="padding-top: 30px" class="panel-body">
<!-- Registration Form -->
<form th:action="#{/processRegistrationForm(flag=${flag})}"
th:object="${crmUser}" method="POST"
class="form-horizontal">
<!-- Place for messages: error, alert etc ... -->
<div class="form-group">
<div class="col-xs-15">
<div>
<!-- Check for registration error -->
<div th:if="${registrationError}" class="alert alert-danger col-xs-offset-1 col-xs-10">
<span th:text="${registrationError}"></span>
</div>
</div>
</div>
</div>
<!-- User name -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" th:field="*{userName}" placeholder="username (*)" class="form-control" />
</div>
<div th:if="${#fields.hasErrors('userName')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('userName')}" th:text="'User name ' + ${err}" />
</ul>
</div>
<!-- Password -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input type="password" th:field="*{password}" placeholder="password (*)" class="form-control" th:errorclass="fieldError" />
</div>
<div th:if="${#fields.hasErrors('password')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('password')}" th:text="'Password ' + ${err}" />
</ul>
</div>
<!-- Confirm Password -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input type="password" th:field="*{matchingPassword}" placeholder="confirm password (*)" class="form-control" th:errorclass="fieldError" />
</div>
<div th:if="${#fields.hasErrors('matchingPassword')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('matchingPassword')}" th:text="'Password ' + ${err}" />
</ul>
</div>
<!-- First name -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" th:field="*{firstName}" placeholder="first name (*)" class="form-control" th:errorclass="fieldError" />
</div>
<div th:if="${#fields.hasErrors('firstName')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('firstName')}" th:text="'First name ' + ${err}" />
</ul>
</div>
<!-- Last name -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" th:field="*{lastName}" placeholder="last name (*)" class="form-control" th:errorclass="fieldError" />
</div>
<div th:if="${#fields.hasErrors('lastName')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('lastName')}" th:text="'Last name ' + ${err}" />
</ul>
</div>
<!-- Email -->
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" th:field="*{email}" placeholder="email (*)" class="form-control" th:errorclass="fieldError" />
</div>
<div th:if="${#fields.hasErrors('email')}"
style="margin-bottom: 25px" class="text-danger">
<ul>
<li th:each="err : ${#fields.errors('email')}" th:text="'Email ' + ${err}" />
</ul>
</div>
<!-- Register Button -->
<div style="margin-top: 10px" class="form-group">
<div class="col-sm-6 controls">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
controller:
#PostMapping("/processRegistrationForm")
public String processRegistrationForm(
#Valid #ModelAttribute("crmUser") CrmUser theCrmUser,#RequestParam(name="flag") Integer flag,
Model theModel,BindingResult theBindingResult) {
String userName = theCrmUser.getUserName();
// form validation
if (theBindingResult.hasErrors()){
return "registration-form";
}
// check the database if user already exists
User existing = userService.findByUserName(userName);
if (existing != null){
theModel.addAttribute("crmUser", new CrmUser());
theModel.addAttribute("registrationError", "User name already exists.");
return "registration-form";
}
// create user account
userService.save(theCrmUser);
if(flag==0)
return "redirect:/user";
else return "redirect:/list";
}
The problems are here:
/register-form:
<!-- Registration Form -->
<form th:action="#{/processRegistrationForm(flag=${flag})}"
th:object="${crmUser}" method="POST"
class="form-horizontal">
/processRegisterForm:
PostMapping("/processRegistrationForm")
public String processRegistrationForm(
#Valid #ModelAttribute("crmUser") CrmUser theCrmUser,#RequestParam(value = "flag",required = false) Integer flag,
BindingResult theBindingResult,
Model theModel) {...
How to edit a database entry in a modal window? I am doing the following but getting an error. Please help me to edit in modal window.
Controller
#Controller
#RequestMapping("/classifier")
public class ClassifierController {
private final LuServices luServices;
private final ModelMapper modelMapper;
#Autowired
public ClassifierController(LuServices luServices, ModelMapper modelMapper) {
this.luServices = luServices;
this.modelMapper = modelMapper;
}
#GetMapping()
public String showClassifierPage(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
PersonDetails personDetails = (PersonDetails) authentication.getPrincipal();
model.addAttribute("personDetails", personDetails);
model.addAttribute("luDTO", luServices.findByTagWith0());
model.addAttribute("newLuDTO", new LuDTO());
return "lu/index";
}
#PostMapping()
public String createLuWith0(#ModelAttribute("newLuDTO") #Valid LuDTO luDTO, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
StringBuilder errorMessage = new StringBuilder();
List<FieldError> errors = bindingResult.getFieldErrors();
for (FieldError error : errors) {
errorMessage.append(error.getField()).append(error.getDefaultMessage()).append(";");
}
return "lu/index";
} else {
luServices.addNewLu(convertToLu(luDTO));
return "redirect:/classifier";
}
}
#GetMapping("/chageLuWith0")
public String test(#RequestParam("id") int id, Model model) {
model.addAttribute("editedLuDTO", luServices.findById(id));
return "lu/index";
}
#PostMapping("/chageLuWith0")
public String changeLuWith0(#RequestParam("id") int id, #ModelAttribute("editedLuDTO") #Valid LuDTO luDTO) {
luServices.update(id, convertToLu(luDTO));
return "redirect:/classifier";
}
private Lu convertToLu(LuDTO luDTO) {
return modelMapper.map(luDTO, Lu.class);
}
private LuDTO convertToLuDTO(Lu lu) {
return modelMapper.map(lu, LuDTO.class);
}
}
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:form="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width"/>
<link rel="stylesheet" th:href="#{/styles/css/style.css}"/>
<link rel="stylesheet" th:href="#{/styles/css/bootstrap.min.css}"/>
<link rel="stylesheet" th:href="#{/styles/css/awesome/all.css}"/>
<script th:src="#{/js/jquery.min.js}" type="text/javascript"></script>
<script th:src="#{/js/bootstrap.min.js}" type="text/javascript"></script>
<script th:src="#{/js/bootstrap.bundle.min.js}" type="text/javascript"></script>
<title>Main page</title>
</head>
<body>
<div class="page_wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-3">
<div class="row">
<div class="item_configure_menu">
<button type="button" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#addNewLuWith0">
<i class="fa-solid fa-file-medical"></i>
</button>
</div>
<div class="lu_block">
<table>
<tr th:each="luDTO : ${luDTO}">
<td>[[*{luDTO.text}]]
<button type="button" class="btn btn-outline-warning" data-bs-toggle="modal" th:attr="data-bs-target='#editNewLuWith0' + *{luDTO.id}">
<i class="fa-solid fa-pen"></i>
</button>
<div class="modal fade" th:id="*{'editNewLuWith0' + {luDTO.id}}" tabindex="-1" aria-labelledby="editNewLuWith0Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editNewLuWith0Label">Add item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" action="#{/chageLuWith0}" th:object="${editedLuDTO}">
<input type="text" th:field="*{tag}" id="tag" value="" placeholder="tag"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('tag')}"
th:errors="*{tag}">tag errors
</div>
<input type="text" th:field="*{shorttext}" id="shorttext" placeholder="shorttext"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('shorttext')}"
th:errors="*{shorttext}">shorttext errors
</div>
<input type="text" th:field="*{text}" id="text" placeholder="text"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('text')}"
th:errors="*{text}">text errors
</div>
<input type="text" th:field="*{lcode}" id="lcode" placeholder="lcode"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('lcode')}"
th:errors="*{lcode}">lcode errors
</div>
<input type="text" th:field="*{code}" id="code" value="" placeholder="code"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('code')}"
th:errors="*{code}">code errors
</div>
<input type="text" th:field="*{bgndat}" id="bgndat" placeholder="bgndat"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('bgndat')}"
th:errors="*{bgndat}">bgndat errors
</div>
<input type="text" th:field="*{enddate}" id="enddate" placeholder="enddate"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('enddate')}"
th:errors="*{enddate}">enddate errors
</div>
<input type="submit" value="Add"/>
</form>
</div>
</div>
</div>
</div>
</td>
<td>[[*{luDTO.getTag()}]]</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col-9">
test info
</div>
</div>
</div>
<div class="modal fade" id="addNewLuWith0" tabindex="-1" aria-labelledby="addNewLuWith0Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addNewLuWith0Label">Add item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form th:method="POST" th:action="#{/classifier}" th:object="${newLuDTO}">
<input type="text" th:field="*{tag}" id="tag" value="" placeholder="tag"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('tag')}"
th:errors="*{tag}">tag errors
</div>
<input type="text" th:field="*{shorttext}" id="shorttext" placeholder="shorttext"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('shorttext')}"
th:errors="*{shorttext}">shorttext errors
</div>
<input type="text" th:field="*{text}" id="text" placeholder="text"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('text')}"
th:errors="*{text}">text errors
</div>
<input type="text" th:field="*{lcode}" id="lcode" placeholder="lcode"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('lcode')}"
th:errors="*{lcode}">lcode errors
</div>
<input type="text" th:field="*{code}" id="code" value="" placeholder="code"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('code')}"
th:errors="*{code}">code errors
</div>
<input type="text" th:field="*{bgndat}" id="bgndat" placeholder="bgndat"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('bgndat')}"
th:errors="*{bgndat}">bgndat errors
</div>
<input type="text" th:field="*{enddate}" id="enddate" placeholder="enddate"/>
<div class="error_block" style="color: red" th:if="${#fields.hasErrors('enddate')}"
th:errors="*{enddate}">enddate errors
</div>
<input type="submit" value="Add"/>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
I get an error:
java.lang.IllegalStateException: Neither BindingResult nor plain
target object for bean name 'editedLuDTO' available as request
attribute
I properly define everything in my back end file. When I try to use
the back end variables in Thymeleaf by using selection variable
expression it is not working. It show errors in every field:
cannot resolve field name
register.html
<!doctype html "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<nav th:replace="/fragments/nav :: nav-front"></nav>
<div class="container-fluid mt-5">
<div class="row">
<div th:replace="/fragments/categories"></div>
<div class="col"></div>
<div class="col-6">
<h3 class="display-4">Register</h3>
<form method="post" th:object="${user}" th:action="#{/register}" >
<div th:if="${#fields.hasErrors('*')}" class="alert alert-danger">
There are errors
</div>
<div class="form-group">
<label for>Username:</label>
<input type="text" class="form-control" th:field="*{username}" placeholder="Username">
<span class="error" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></span>
</div>
<div class="form-group">
<label for>Password:</label>
<input type="password" class="form-control" th:field="*{password}">
<span class="error" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span>
</div>
<div class="form-group">
<label for>Confirm Password:</label>
<input type="password" class="form-control" th:field="*{confirmPassword}">
<span class="error" th:if="${passwordMatchProblem}">Passwords do not match</span>
</div>
<div class="form-group">
<label for>E-mail:</label>
<input type="email" class="form-control" th:field="*{email}" placeholder="E-mail" required>
<span class="error" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
</div>
<div class="form-group">
<label for>Phone number:</label>
<input type="text" class="form-control" th:field="*{phoneNumber}" placeholder="Phone number">
<span class="error" th:if="${#fields.hasErrors('phoneNumber')}" th:errors="*{phoneNumber}"></span>
</div>
<button class="btn btn-danger mb-5">Register</button>
</form>
</div>
<div class="col"></div>
</div>
</div>
<div th:replace="/fragments/footer"></div>
</body>
</html>
I get errors everywhere I use the selection expression field.
Are you adding "user" to your model in your controller?
You need to add it to your model so Thymeleaf can access it.
addAttribute method can be used like so: model.addAttribute("user", myUser);
I am learning Laravel 5.2 and vue.js,and not familiar with the grammars,the question is:
How to get all of the values of the form elements below and send them to controller with vue.js?
Including text,select,textarea,file input,radios,checkboxes.
PS:
There is a plugin in the html demo,it's function is compressing a selected image.
lrz.bundle.js,https://github.com/think2011/localResizeIMG
html demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossorigin="anonymous">
</head>
<body>
<div class="container">
<form>
<div class="form-group row">
<label for="formGroupExampleInput" class="col-sm-2 form-control-label">Text</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="formGroupExampleInput" placeholder="">
</div>
</div>
<div class="form-group row">
<label for="exampleSelect1" class="col-sm-2 form-control-label">Select</label>
<div class="col-sm-10">
<select class="form-control" id="exampleSelect1">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="exampleTextarea" class="col-sm-2 form-control-label">Textarea</label>
<div class="col-sm-10">
<textarea class="form-control" id="exampleTextarea" rows="3"></textarea>
</div>
</div>
<div class="form-group row">
<label for="exampleInputFile" class="col-sm-2 form-control-label">File input</label>
<div class="col-sm-10">
<input id="exampleInputFile" name="photo" type="file" class="form-control-file" value="Upload" accept="image/*">
preview:
<img id="preview"/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Radios</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
</label>
<label class="radio-inline">
<input type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2"> 2
</label>
<label class="radio-inline">
<input type="radio" name="inlineRadioOptions" id="inlineRadio3" value="option3"> 3
</label>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Checkboxes</label>
<div class="col-sm-10">
<div class="checkbox">
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> 1
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox2" value="option2"> 2
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 3
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-secondary">Submit</button>
</div>
</div>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js" integrity="sha384-vZ2WRJMwsjRMW/8U7i6PWi6AlO1L79snBrmgiDpgIWJ82z8eA5lenwvxbMV1PAh7" crossorigin="anonymous"></script>
<script src="js/dist/lrz.bundle.js"></script>
<script>
$(function () {
var $preview = $('#preview');
$('#exampleInputFile').on('change', function () {
lrz(this.files[0], {
width: 800
}).then(function (rst) {
$preview.attr('src', rst.base64);
rst.formData.append('fileLen', rst.fileLen);
});
});
});
</script>
</body>
</html>
I've a little bit of uncertainty as to whether or not it's actually a Laravel -> Vue setup you're looking for since you have absolutely no Laravel nor Vue code in your question which is extremely broad, but here's a basic template to get started. I use the following in pretty much every project.
Laravel
Create your route - routes/web.php:
Route::post('/myform', 'FormControntroller#submitForm');
Create your controller and method - app/http/controllers/FormController.php
class FormController extends App\Controllers\Controller {
public function submitForm()
{
var_dump(request->all());
}
}
Create your entry view - resources/views/app.blade.php
<html>
<head>
<title>Minimal Vue Example</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.1/vue.min.js"></script>
<script src="/js/main.js"></script
</body>
</html>
Vue
main.js
import Vue from 'vue'
import Resource from 'vue-resource'
import Router from 'vue-router'
import Root from './components/Root.vue'
Vue.use(Router)
Vue.use(Resource)
var router = new Router({
history: true,
});
router.map({
'/': {
component: Root
},
});
// Start up our app
router.start(Root, '#app');
Create your root component - resources/views/assets/js/components/Root.vue
<template>
<form v-on:submit.prevent="submitForm">
<input type="text" v-model="formData.username"/>
<input type="text" v-model="formData.password"/>
</form>
</template>
<script>
export default {
data: function() {
return {
formData: {
username: null,
password: null
}
}
},
methods: {
submitForm: function() {
this.$http.post('/myform', this.formData).then(function(response) {
alert('Yay, my form was posted!');
});
}
}
}
</script>
At this point you'll need to run webpack on your assets, see the Laravel Documentation on Elixir.
Again, you've asked a very broad question without providing much background, but this will get you going.
Notes: The above code is working code on Vue 1.X, version 2 is slightly different.
For further help on Vue and Laravel, see the Laravel Documentation.
We have to do validation on the page, in the case of empty fields to display a message.
It's my class, the method of the controller and settings of messages.
I can't to get on the page Freemarker display error messages.
public class CreateCourseDTO {
#NotEmpty
private String name;
#NotEmpty
private String category;
#NotEmpty
private String description;
#NotEmpty
private String links;
public CreateCourseDTO() {
}
NotEmpty.createCourseDTO.name = Name is required!
NotEmpty.createCourseDTO.category = Category is required!
NotEmpty.createCourseDTO.description = Description is required!
NotEmpty.createCourseDTO.links = Links is required!
<bean class="org.springframework.context.support.ResourceBundleMessageSource"
id="messageSource">
<property name="basename" value="messages" />
</bean>
#RequestMapping(value = "/create", method = RequestMethod.POST, params = {
"name", "category", "description", "links" })
public String createCoursePost(Model model, HttpSession session,
HttpServletRequest request, #Valid CreateCourseDTO createCourseDTO,
BindingResult result) {
model.addAttribute("eMail", session.getAttribute("eMail"));
String title = request.getParameter("name");
String description = request.getParameter("description");
String links = request.getParameter("links");
String category = request.getParameter("category");
if (result.hasErrors() ) {
How do I fix freemarker page?
<#import "/spring.ftl" as spring />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
<style>
.error {
color: #ff0000;
}
.errorblock {
color: #000;
background-color: #ffEEEE;
border: 3px solid #ff0000;
padding: 8px;
margin: 16px;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>
Create Course
<div class="logout">
<span id="currentUserLogin">
${eMail}
</span>
<a href="logout.html">
<i class="icon-off"></i>
</a>
</div>
</h1>
</header>
<form class="form-horizontal" commandName="createCourseDTO" method=POST>
<fieldset>
<div class="control-group">
<label class="control-label">Name</label>
<div class="controls">
<input id="name" name="name" class="span5" type="text"/>
<#spring.showErrors "<br>" />
</div>
</div>
<div class="control-group">
<label class="control-label">Category</label>
<div class="controls">
<select id="category" name="category" class="span5">
<option></option>
<#list listCategories as category>
<option>${category.category}</option>
</#list>
</select>
<#spring.showErrors "<br>" />
</div>
</div>
<div class="control-group">
<label class="control-label">Description</label>
<div class="controls">
<textarea id="description" name="description" class="span5" rows="3"></textarea>
<#spring.showErrors "<br>" />
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea id="links" name="links" class="span5" rows="3"></textarea>
<#spring.showErrors "<br>" />
</div>
</div>
<div class="form-actions">
<button id="createButton" name="createButton" class="btn btn-primary" type="submit">Create</button>
</div>
</fieldset>
</form>
<a class="btn" href="courses.html">Cancel</a>
</div>
Until that's happened.
<#import "/spring.ftl" as spring />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
</head>
<body>
<div class="container">
<header>
<h1>
Create Course
<div class="logout">
<span id="currentUserLogin">
${eMail}
</span>
<a href="logout.html">
<i class="icon-off"></i>
</a>
</div>
</h1>
</header>
<form action="create" method="POST"/>
<fieldset>
<#spring.bind "сreateCourseDTO" />
<#spring.showErrors '*', 'errors' />
<div class="control-group">
<label class="control-label">Name</label>
<div class="controls">
<#spring.formInput "createCourseDTO.name" ""/>
<#spring.showErrors '<br>',"error" />
</div>
</div>
<div class="control-group">
<label class="control-label">Category</label>
<div class="controls">
<#spring.formSingleSelect "createCourseDTO.category" categoryList "" />
<option></option>
<#list listCategories as category>
<option>${category.category}</option>
</#list>
</select>
<#spring.showErrors "createCourseDTO.category","error" />
</div>
</div>
<div class="control-group">
<label class="control-label">Description</label>
<div class="controls">
<#spring.formInput "createCourseDTO.description"/>
<#spring.showErrors "createCourseDTO.description","error" />
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<#spring.formInput "createCourseDTO.links"/>
<#spring.showErrors "createCourseDTO.links","error" />
</div>
</div>
<div class="form-actions">
<button id="createButton" name="createButton" class="btn btn-primary" type="submit">Create</button>
</div>
</fieldset>
</form>
<a class="btn" href="courses.html">Cancel</a>
</div>
</body>
</html>
Throws an error
==> assignment: status=springMacroRequestContext.getBindStatus(path) [on line 120, column 9 in spring.ftl]
in user-directive bind [on line 159, column 5 in spring.ftl]
in user-directive spring.formInput [on line 33, column 15 in pages/create.ftl]
on line <#spring.formInput "createCourseDTO.name" ""/>
and I have fixed bin
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
p:cache="true" p:prefix="/pages/" p:suffix=".ftl" p:exposeSpringMacroHelpers="true"/>