Issue
I am writing an extension for a web application. Its API has an interface IFormExtension
which needs to be implemented and provides access to the database and has a String render()
method, which is called to get the html which will be placed within the existing html of the web application.
I know there are multiple topics on the different aspects mentioned in my question, but until now I am failing to combine the different solutions of each of the "trivial" subtopics to one working solution for my "complex" scenario:
The idea of the extension is to load and display various objects from the database in a list or table, each entry accompanied by a button which causes that additional html (unique to the item it belongs to) gets loaded dynamically from a servlet to be displayed within the existing html - without triggering a reload of the page.
This is my current approach:
// all html I want to pass must be present in the returned String
// of this method due to the API of the web application and will
// be placed within a div in the existing html
public String render(..){
// getting items from database
String html = "..."; // here the html (see below) is build with values from the items where necessary
return html;
}
here the architecture of html that render() will return:
<div>
<table>
<tbody>
<tr>
<!-- the curly braces expressions are a placeholder for values which will be inserted by the java code above -->
<td>
<form onSubmit="return loadFromServlet({itemId});">
<input id="property_{itemid}" type="hidden" value="{itemid.myProperty}">
<input type="image" src="{path_to_image}">
</form>
</td>
</tr>
<!-- more tr's with different itemId's... -->
</tbody>
</table>
</div>
<!-- html from Servlet should show up in this div: -->
<div id="dynamicallyLoadedHtmlHere"/>
<!-- the javascript shows up in the terminal script tag:-->
<script>
// see the javascript below
</script>
here the javascript:
"use strict";
function loadFromServlet(itemId){
var xhr = new XMLHttpRequest();
//xhr.addEventListener("load", showDynamicHtml); // I intuitivly wanted to do something like this, but i can't pass a parameter to showDynamicHtml (or at least I don't know how); therefore:
xhr.open("POST","my/servlet/uri",true);
var params = "ItemId=" + itemId;
params += "&MyProperty=" + document.getElementById("property_"+itemId);
xhr.onload = function (evnt) {
document.getElementById("dynamicallyLoadedHtmlHere").innerHtml = xhr.responseText;
evnt.preventDefault();
}
xhr.send(params);
return false;
}
The image in the form is supposed to work as a submit button, which worked in a previous approach, when the form still had the action="my/servlet/uri" method="POST" target="someIFrameId"
attributes before I found the onSubmit
approach. I moved away from the first approach because the target should be a div and not an iframe. But now the function loadFromServlet doesnt seem to be executed (when I add console.log("debug")
s nothing shows up in console and the whole webpage refreshes - i.e. not the intended or expected behaviour. I'm having doubts, if the script is even in the scope of the form(s)?
Summary:
- The html and the script which gets returned from the render() method show up in the target web page just fine.
- The javascript code somehow doesn't get executed when clicking the img button though - therefore the servlet isn't called.
I hope I have elaborated sufficiently on my problem.
Solution
Try adjusting your onSubmit handler as per below.
I modified the your form to correctly call loadFromServlet
and I moved the itemId
out of the function parameters and into a data attribute on the form, this way we can use the event
object that loadFromServlet
will have access to.
We want access to the event object so we can call event.preventDefault()
which will stop the page from refreshing.
Then the JS code get the itemId by accessing the data attribute on the form.
Additionally, if you cant get XHR to work for your request, try fetch
or even a third-party library like axios.
html
<div>
<table>
<tbody>
<tr>
<!-- the curly braces expressions are a placeholder for values which will be inserted by the java code above -->
<td>
<form onsubmit="loadFromServlet()" data-itemid="{itemId}" data.itemproperty="{itemId.myProperty}">
<input type="image" src="{path_to_image}">
</form>
</td>
</tr>
<!-- more tr's with different itemId's... -->
</tbody>
</table>
</div>
<!-- html from Servlet should show up in this div: -->
<div id="dynamicallyLoadedHtmlHere"/>
js
"use strict";
function loadFromServlet (){
// Stop the form from submitting (and reloading the page)
event.preventDefault(); //event is accessible even though it doesn't show up as function parameter
// Get the parameters
// dataset contains every parameter of a tag prefixed with 'data-'
const itemId = event.currentTarget.dataset.itemid;
const itemProperty = event.currentTarget.dataset.itemproperty;
const URI = 'my/servlet/uri';
// calling encodeURIComponent() on parameter values to escape potential illegal uri characters
const params = '?ItemId=' + encodeURIComponent(itemId);
params += '&myProperty=' + encodeURIComponent(itemProperty);
fetch(URI + params)
.then(response => response.text())
.then(data => {
document.getElementById("dynamicallyLoadedHtmlHere").innerHTML = data;
});
}
Edit:
I fixed some errors in the above code I found while debugging the approach suggested by this answer and added some comments for clarity.
Answered By - camaulay