How to get form data in Java Spark using Thymeleaf template engine? - thymeleaf

I've built a simple application and now I'm trying to host attach it to a web server. I'm attempting to have a HTML form (using Thymeleaf) that the user enters their location in as text, and then my server will take and produce a result using that string. So to get started, I'm attempting to make a simple spark application that makes a home page with a "enter your location" form, that then gets the users input and does something with it. I can get the "entryMessage" displayed, as tutorials show, but how to get user data is proving difficult.
However, there is very little documentation on how this can be done with these two framworks. My attempt at what the code should look like is as follows. Note the middle post is just me trying to find ways to get the form data - none proved succesful
ThymeleafTemplateEngine engine = new ThymeleafTemplateEngine();
HashMap<String, String> userLocationMap = new HashMap<>();
get("/home", (request, response) -> {
userLocationMap.put("entryMessage", "Please enter your location");
return new ModelAndView(userLocationMap, "home");
}, engine);
post("/home", (request, response) -> {
System.out.println(request.toString());
//System.out.println(request.body());
//System.out.println(userResponse.location);
//response.redirect("/locationAccepted");
return userLocationMap.get("userLocation");
});
get("/locationAccepted", (request, response) -> {
String location = request.queryParams("userLocation");
return new ModelAndView(userLocationMap, "locationAccepted");
}, engine);
with the following thymeleaf templates
home.html
<!DOCTYPE html SYSTEM "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>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> <span th:text="${entryMessage}"> default message </span> </p>
<form action="/locationAccepted" method="post">
<input type="text" th:field="userLocation"/>
<div class="button">
<button type="submit">Send your message</button>
</div>
</form>
</body>
</html>
and locationAccepted.html
<!DOCTYPE html SYSTEM "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>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> <span th:text="${userLocation}"> default message </span> </p>
</form>
</body>
</html>

You have two bugs in your code, both in the HTML form:
In your Java code you're defining the route "/locationAccepted" as GET, but your form method attribute is POST => Change your form to GET.
If you want to get the form's input data it should have a name with value userLocation. th:field isn't translated to name (it's translated to field attribute which I'm not sure what it means).
So your form (after Thymeleaf) should look like this:
<form action="/locationAccepted" method="GET">
<input type="text" name="userLocation"/>
<div class="button">
<button type="submit">Send your message</button>
</div>
</form>
And then request.queryParams("userLocation") will work like you wanted.

Related

How to load a specific html file in the BrowserWindow

I am creating an app in Electron. I am still new to the framework however I
did some reading around how to communicate between the main and renderer
processes using ipcMain and ipcRenderer. I have a simple html page with a
login form that gets load when the app is ready and in the renderer process
I listen
to the click event of the submit button on the form(For testing purposes I
have hard coded the username and password) and I run a simple check to see
if the password and username matches the one I have hard coded. The aim is
to then load a specific html file in the browser window based on the result
of the check. My render.js looks like this:
const ipc = require('electron').ipcRenderer;
document.querySelector('#btn').addEventListener('click', function (event){
event.preventDefault();
const username = 'Belinda';
const password = 'admin';
const inputUsername = document.querySelector('#username').value;
const inputPassword = document.querySelector('#password').value;
if(inputUsername != username || inputPassword != password){
ipc.send('errortest', function (){
alert('Error')
});
}else{
ipc.send('successtest', function (){
alert('Success')
});
};
});
In main.js I listen to the events like this:
ipc.on('successtest', function (){
mainWindow.loadFile('admin.html');
});
ipc.on('errortest', function(){
console.log('error');
mainWindow.loadFile('error.html');
});
My index.html page looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet"
href="assets/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/fonts/#fortawesome/fontawesome-
free/css/all.css">
<link rel="stylesheet" href="assets/stylesheets/main.css">
<!-- <link rel="import" href="./admin.html"> -->
<link rel="import" href="./admin.html">
<link rel="import" href="./error.html">
</head>
<body id="body">
<form class="form-signin" method="POST">
<div class="text-center mb-4">
<img class="mb-4" src="./assets/icons/logo4.jpg" alt="" width="80"
height="40">
</div>
<div class="form-group">
<input type="text" value="" autofocus class="form-control form-
control-sm" id="username" placeholder="Username">
</div>
<div class="form-group">
<input type="password" autofocus value="" class="form-control form-
control-sm success" id="password" placeholder="Password">
</div>
<button class="btn btn-lg btn-success btn-block btn-sm" id="btn"
type="submit">Log in</button>
<p class="mt-5 mb-3 text-muted text-center">© Save Money
Solutions 2018-19</p>
</form>
<script>
require('./renderer');
</script>
</body>
</html>
Running the app works only for the 'errortest' event. Any advice on how I
get around this. Or any Ideas on how to do basic login and redirect paths
in electron. I did try some research but I haven't come across anything
useful. Thank you
I believe your problem is how you're getting the value of the username and password inputs.
Since both of your inputs has ids I think you should be getting their value like this:
const inputUsername = document.getElementById('username').value;
const inputPassword = document.getElementById('password').value;
Using the getElementById function.

Thymeleaf 3 #request object is null in inline Javascript

I have below code in a web page in Spring Boot 2 web app:
<div data-th-fragment="head-section">
<div> blah </div>
<script data-th-inline="javascript">
var url = [[${#request.requestURL} ]];
var country = [[${#locale.country}]]
</script>
</div>
Thymeleaf throws error that says cannot get requestURL on null while it correctly gets the locale. Thymeleaf 3 official documentation says #request and #locale are valid objects in web context.
How to fix this issue?
Just Metroids mention and Refer to Spring boot getting started Securing a Web Application User #httpServletRequest is not null. is an instance of HttpServletRequestWrapper
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="#{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>

Why Does IsPostBack Require runat="server" on the Form?

I must not understand something fundamental about the aspx page processing cycle. Please take a look at this simple example below.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<div>
<form method="post">
<textarea name="someContent" cols="35" rows="15"></textarea>
<input type="submit"/>
</form>
</div>
</body>
</html>
<script runat="server">
public void Page_Load() {
// The httpMethod is always set correctly to "GET" or "POST"
String httpMethod = HttpContext.Current.Request.HttpMethod;
if(IsPostBack)
DoSomething();
else
DoSomethingElse();
}
</script>
Note the <form> element does not have a runat='server' attribute.
When the page is loaded for the first time, the Page_Load() fires and the httpMethod variable is set to "GET" and the IsPostback property returns false, all as expected.
When the user clicks the "submit" button, the Page_Load() fires again and the httpMethod variable is set to "POST", so the ASP.NET plumbing obviously knows this is a POST verb; however, the IsPostBack property still returns false. This seems odd to me. I would think that if the httpMethod was set to "POST", the IsPostBack would return true.
If I change the <form> element to contain a runat='server' attribute things change a bit. Now when the user presses the "submit" button the httpMethod variable is set to "POST", just as before, but now IsPostBack returns true.
Since I have no need to access the <form> element on the server, I saw no need to use a runat='server' attribute on it. But for some reason, the runat='server' must be present on the <form> in order for the IsPostBack to return a correct value, even though the HttpContext.Current.Request.HttpMethod property returns the correct value regardless of the runat='server' attribute.
Can anyone explain WHY the runat='server' is necessary on the <form> to make IsPostBack work correctly?
NOTE: Please note that I am not asking how to "do this" or "do that". My goal is to understand "The Why".
Thanks
Page checks few special fields (viewstate and postback event) to determine if request is postback or not.
http://referencesource.microsoft.com/System.Web/R/ae07c23d0aba6bb9.html
Both forms here cause IsPostBack to be true:
<%# Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<p><%= IsPostBack? "POSTBACK" : "NO POSTBACK" %></p>
<form id="form1" runat="server">
<input type="submit" />
</form>
<form id="form2" method="get">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="submit" />
</form>
</body>
</html>
Server-controlled form just adds and populates these fields automatically.

.Net MVC Razor submit form post action

I have an html form like:
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<form name="mercForm" action="http://someurl.com/" method="post">
<input type="hidden" name="some_input" value="206">
<input type="submit" value="sub" />
</form>
</body>
</html>
When I post this form by clicking submit button, the new window opens with the posted values. But, I want to implement the same form into a MVC Razor page. I habe tried some code but I failed. New window does not open.
#using (Html.BeginForm("http://some url.com/","SomeController", FormMethod.Post, null))
{
<input type="hidden" name="some_input" value="206">
<input type="submit" value="sub" />
}
How can I make it work?
As I know Html.BeginForm does not take 1st argument as some url, it should be some Action name.
If you want to post your form data to some third party web site then just collect the data inside an action directly and process the form post using HttpWebRequest.

jQuery Mobile : page not loading completely on initial visit

I looked through all the similar questions that showed up before typing this, but I can't find an answer for my issue.
I'm using jQuery Mobile (1.1) and jQuery (1.7.1) to develop a small portal. As such, I have it all on one page, and use data-role="page" to handle the process transitions.
The flow is currently like this:
User visits main URL
User clicks on an action ("do this" or "do that")
When a user clicks on the action (both are just tags with a href to another file with data-role="button"), it takes them to that page just fine.
However, when first visiting the page (either by manually typing in the URL or clicking on the action button/link), the form is empty and clicking the submit button does nothing. After refreshing the page though everything works as it should.
So, say for example someone clicks on action link #1 ("make a payment"):
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.js"></script>
<title>Credit Card Payments</title>
<style>
.ui-dialog .ui-header a[data-icon=delete] { display: none; }
</style>
<script>
$(document).bind("mobileinit", function(){
});
</script>
</head>
<body>
<div data-role="dialog" id="popup">
<div data-role="header" data-theme="b" data-content-theme="b">
<h1>Destination</h1>
</div>
<div data-role="content" data-theme="b" data-content-theme="b">
Please choose what you would like to do:
Make A Payment
Add Credit Card To Account
</div>
</div>
</body>
</html>
It takes them to "payment.php" and displays page id "step1", which is a simple log in form:
<div data-role="page" id="step1">
<div data-role="header">
<h2>Log In</h2>
</div>
<form id="step1frm">
<div data-role="fieldcontain">
<label for="mail">Blesta e-mail: </label>
<input type="text" name="mail" id="mail" />
</div>
<div data-role="fieldcontain">
<label for="pw">Blesta password: </label>
<input type="password" name="pw" id="pw" />
</div>
<input type="button" id="step1frmsub" value="Log In" />
</form>
</div>
The log in form page also has a lot of jQM stuff but after I commented all the code out it didn't change anything so that isn't the cause. I also verified the HTML via W3.org and it came back valid.
A better representation of what's going on can be found in the screen shots I took of Chrome's Inspector:
First Visit - after clicking "make a payment"
After Refreshing Page - after refreshing the login for "make a payment"
Edit - As a small follow up, I noticed "data-external-page="true"" is being set on the div page on load, and then on refresh it's not there anymore. From my understanding of what I've read this is done because it's coming from a dialog basically, but I'm not sure if there's a way to disable that from being set.
Answer - Well, the solution to this, after initially thinking it wasn't what I was looking for, was actually to add this to my links:
rel="external"
So that they look like this:
Make A Payment
Well, the solution to this, after initially thinking it wasn't what I was looking for, was actually to add this to my links:
rel="external"
So that they look like this:
Make A Payment

Resources