How to submit another get attribute and keep previous one? - java

I'm building my first web app in Java. I came across this problem. When I have a get attribute like ?page=2 correctly submitted it goes missing after calling another get request. How can I keep the first one and append another one? Here are pics that help clear out my question
Before
After
Desired
Here are code snippets of my forms in .jsp page. This is used to sort the table with passing a column name:
<form action="GetUsersServlet" method="get">name
<input type="hidden" name="column" value="name">
<button class="sort" type="submit"></button>
</form>
How can I append the value to existing ?page=x attribute?

Use URLSearchParams method set on event click and set window.location.search to parsed params.
document.querySelector("button").onclick = () => {
const urlParams = new URLSearchParams(window.location.search);
urlParams.set("page", 2)
window.location.search = urlParams.toString()
}

Related

Java servlet request working correctly only for first of multiple auto generated html elements

unfortunately this is a project for school and most of the variables are in my native language, i'll translate any if needed, but leave the code as is, just in case that's somehow the problem.
I'm making a web app for a Catering Service, using Java servlets for my backend and JSP for my front end.
The session stores an Order object which has a HashMap<Product, Quantity>.
On my Cart jsp foreach Product in the hashmap there's a row in the css grid displayed on the screen.
<!-- Cart jsp snippet-->
<!--article Order.getHashMap().keySet()-->
<c:forEach var="stavka" items="${Narudzbina.getStavkeNarudzbine().keySet()}">
<div class='korpa-stavka'>
<!-- article.getName() -->
<h5>${stavka.getNazivProizvoda()}</h5>
<input class="btn btn-light poeni-korpa" type="number" min="1" id="${stavka.getProizvodID()}" onchange="updateUrl(this)" value="${Narudzbina.getStavkeNarudzbine().get(stavka)}">
<div class="stavka-buttons">
<!-- Link is filled with a js script -->
Izmeni
<!-- Link is static except for the ID, but no JS -->
IzbriĆĄi
</div>
</div>
<p class='stavka-total'>Cena: ${stavka.getCenaPoPorciji() * Narudzbina.getStavkeNarudzbine().get(stavka)} RSD</p>
</c:forEach>
This works as intended.
One of the a tags href value is filled with an onchange call from the number input before it.
// Js for updating href of that a tag
function updateUrl(element){
var link = document.getElementById("a" + element.id);
link.setAttribute("href", "Korpa?Zahtev=Izmeni&Proizvod="+ element.id +"&Kolicina=" + element.value);
}
That also works well, for every auto generated row from the hashtable. Clicking on the a button on any of them, as far as i can see, correctly calls the "Korpa" Controller, with good parameters, different, and correct ArticleID, different and correct Quantity for each of them.
Korpa servlet then packs the session Order object in a temporary Order, calls changeQuantity(article, newQuantity) on it, when that's done packs the changed Order in session and reloads the cart page..
// Order order = session order
Narudzbina narudzbina = (Narudzbina)session.getAttribute("Narudzbina");
//order.change quantity
narudzbina.izmeniKolicinu(Integer.valueOf(request.getParameter("Proizvod")), Integer.valueOf(request.getParameter("Kolicina")));
session.setAttribute("Narudzbina",narudzbina);
//refreshes the Cart jsp
response.sendRedirect("Profil?User=" + session.getAttribute("User").toString() + "&View=Korpa");
return;
The Order Model just changes the value in the hash map
//changeQuantity article ID newQuantity
public void izmeniKolicinu(int proizvodID, int novaKolicina) {
//Order ord : hashMap.keySet()
for (Proizvod prod : stavkeNarudzbine.keySet()) {
//if ord.getArticleID == articleID
if (prod.getProizvodID() == proizvodID) {
stavkeNarudzbine.put(prod, novaKolicina);
}
break;
}
}
Now all of this works perfectly well for both changing quantity and deleting the article ( deleting is almost identical and there's a switch statement in the Controller to check what to run, i ommited that since this is already a long post, and it's very likely irrelevant )
But only for the first article drawn on the cart jsp screen.
The other articles properly update their respective href's, and all properly call the servlet, the page refreshes, there's no exceptions thrown, and the status of the request is 302 for both the 1st one ( that works ) and the rest. But the values do not update.
Clicking on any but the first generated link doesn't update values
Also if i click on Remove on the first one that actually works, it gets removed, and the new first drawn one works now.
Sorry for the rambling question, I'm just a student, really lost on this one, not really quite sure what the problem could be so I gave all the info i thought would be in any way helpful...
P.S There's no communication with the database anywhere in this process.
EDIT: Clarified problem
To have a proper answer here (the OP found it through the comments): the break needs to be within the if-condition
if (prod.getProizvodID() == proizvodID) {
stavkeNarudzbine.put(prod, novaKolicina);
break; // HERE
}
// NOT HERE: break;

Load two return function with one click JSP and javascript

There is a jsp file calling 2 different js files. I had a button(assume ButtonA) in jsp which when clicked it load a function(Function1) which fill jsp form with values. There is another button in page (ButtonB) which when clicked it load another function where this function(Function2) calculate a figure based on result that Function1 populated in form. So the action was user click ButtonA first, field values loaded, then click ButtonB to get calculated figure. Now I dont want two button clicks here. I tried to put two functions in one button as example below
<td colspan=3><center><INPUT TYPE="Button" VALUE="Query Package Info" TARGET="bottom" onClick="generateReport('MK07FormPackageInfo'); computeMarkFormat(document.MK07Form.markSurf.value);"></td>
but it only correctly run first one but the second one with gives empty values.
Please help.
Why dont you have the Javascript Function1 just call Function2.
If Function 1 and 2 are used by other JSP's:
Function 1 could be overloaded or modified to take in a parameter that says call function2 or not. Other JSP's can still keep calling Function1 as is. This particular button can call Function1 with parameter to trigger
Function 2 call.
function1 (callFunction2) {
function1();
function2();
}
function1 (){
}
function2 () {
}
Is there another reason you need this to be two seperate calls?
Thanks,
Paul
I tried to execute your scenario, it is working actually.
Here is my code
<script language="javascript">
function loadValues(){
document.getElementById('a').value = '2';
document.getElementById('b').value = '2';
}
function calc(){
document.getElementById('c').value = document.getElementById('a').value + document.getElementById('b').value;
}
</script>
HTML
<input type="text" id="a"/>
<input type="text" id="b"/>
<input type="text" id="c"/>
<input type="button" onClick="loadValues(); calc();" />
Only place where it fails is, if your first method executed successfully then only the second function will be executed. If you have any exception or problem in first function, the second one will not work, you may try to give 'b1' instead of 'b' After then nothing will be executed. Correct me if something wrong. Thanks..
Why don't you have a close tag for <center> ?
You may need to debug or add console.log to debug your second function if the result is not what you expected(Since you said it returned empty val, which means it actually got called, right?). Also, try to open console on browser's developer tool and see if any Exception/Error.
Btw, just like other guys says:
onClick="generateReport('MK07FormPackageInfo'); computeMarkFormat(document.MK07Form.markSurf.value);"
Isn't really pretty and is not a recommend way to do this...
You may want to add multiple event Listener to your using jQuery:
<script src="//code.jquery.com/jquery-1.11.2.min.js" />
<!-- watever here -->
<INPUT id="queryPackageInfoBtn" TYPE="Button" VALUE="Query Package Info" TARGET="bottom" />
<!-- watever here -->
<!--
Binding the even
-->
<script>
jQuery('#queryPackageInfoBtn').click(function(){generateReport('MK07FormPackageInfo'); });
jQuery('#queryPackageInfoBtn').click(function(){computeMarkFormat(document.MK07Form.markSurf.value);});
</script>
<!--
actually you can just do:
jQuery('#queryPackageInfoBtn').click(function(){
generateReport('MK07FormPackageInfo');
computeMarkFormat(document.MK07Form.markSurf.value);
});
but I want to make it obvious how you can add multiple event handler to the buttons without using inline onClick which will be messy.
-->

Angularjs UI Bootstrap Popover Prevents input submit

I have used Angularjs with ui.bootstrap popover feature in following manner,
<form name="frm1" role="form" ng-submit='myFunc()' novalidate="novalidate">
.... other inputs go here...
<input type="number" ng-pattern="/^[0-9]+$/" name="testNo" ng-model='testNo' required popover="Locate number here" popover-trigger="focus">
<input type="submit" ng-model='funcBtn' value="Submit" ng-click="submitted = true" ng-disabled="value.length=0">
</form>
The issue is because of popover="Locate number here" popover-trigger="focus" code when I check after submitting the form the value for the input testNo is not passed to controller.
The Controller is as follows,
app.controller('myCtrl', ['$scope','$location','$log', function($scope,$location,$log)
{
$log.log('testNo', $scope.testNo);
}]);
And If I remove the popover code from this input it works fine. I like to know whether there's a specific way in using popover into inputs.
Used resource ui.bootstrap example, input trigger: http://angular-ui.github.io/bootstrap/
The problem is that the current version of AngularJS can only have one scope for a given DOM element, and the popover creates a child scope that then gets inherited by the other directives. Fortunately, the solution is simple. Just refer to $parent.my_var in the directive, in your case ng-model="$parent.$model".
Here is the popover FAQ on this problem.
I ran into this problem in the bowels of my own custom directive, but fortunately the solution is simple there as well: rather than refer to $scope.var, refer to $scope.parent.var. Simple solution, but hours of debugging!

Trying to use a #RequestParam field in Spring form [duplicate]

Consider this form:
<form action="http://www.blabla.com?a=1&b=2" method="GET">
<input type="hidden" name="c" value="3" />
</form>
When submitting this GET form, the parameters a and b are disappearing.
Is there a reason for that?
Is there a way of avoiding this behaviour?
Isn't that what hidden parameters are for to start with...?
<form action="http://www.example.com" method="GET">
<input type="hidden" name="a" value="1" />
<input type="hidden" name="b" value="2" />
<input type="hidden" name="c" value="3" />
<input type="submit" />
</form>
I wouldn't count on any browser retaining any existing query string in the action URL.
As the specifications (RFC1866, page 46; HTML 4.x section 17.13.3) state:
If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type.
Maybe one could percent-encode the action-URL to embed the question mark and the parameters, and then cross one's fingers to hope all browsers would leave that URL as it (and validate that the server understands it too). But I'd never rely on that.
By the way: it's not different for non-hidden form fields. For POST the action URL could hold a query string though.
In HTML5, this is per-spec behaviour.
See Association of controls and forms - Form submission algorithm.
Look at "4.10.22.3 Form submission algorithm", step 17. In the case of a GET form to an http/s URI with a query string:
Let destination be a new URL that is equal to the action except that
its <query> component is replaced by query (adding a U+003F QUESTION
MARK character (?) if appropriate).
So, your browser will trash the existing "?..." part of your URI and replace it with a new one based on your form.
In HTML 4.01, the spec produces invalid URIs - most browsers didn't actually do this though...
See Forms - Processing form data, step four - the URI will have a ? appended, even if it already contains one.
What you can do is using a simple foreach on the table containing the GET information. For example in PHP :
foreach ($_GET as $key => $value) {
$key = htmlspecialchars($key);
$value = htmlspecialchars($value);
echo "<input type='hidden' name='$key' value='$value'/>";
}
As the GET values are coming from the user, we should escape them before printing on screen.
You should include the two items (a and b) as hidden input elements as well as C.
I had a very similar problem where for the form action, I had something like:
<form action="http://www.example.com/?q=content/something" method="GET">
<input type="submit" value="Go away..." />
</form>
The button would get the user to the site, but the query info disappeared so the user landed on the home page rather than the desired content page. The solution in my case was to find out how to code the URL without the query that would get the user to the desired page. In this case my target was a Drupal site, so as it turned out /content/something also worked. I also could have used a node number (i.e. /node/123).
If you need workaround, as this form can be placed in 3rd party systems, you can use Apache mod_rewrite like this:
RewriteRule ^dummy.link$ index.php?a=1&b=2 [QSA,L]
then your new form will look like this:
<form ... action="http:/www.blabla.com/dummy.link" method="GET">
<input type="hidden" name="c" value="3" />
</form>
and Apache will append 3rd parameter to query
When the original query has array, for php:
foreach (explode("\n", http_build_query($query, '', "\n")) as $keyValue) {
[$key, $value] = explode('=', $keyValue, 2);
$key = htmlspecialchars(urldecode($key), ENT_COMPAT | ENT_HTML5);
$value = htmlspecialchars(urldecode($value), ENT_COMPAT | ENT_HTML5);
echo '<input type="hidden" name="' . $key . '" value="' . $value . '"' . "/>\n";
}
To answer your first question yes the browser does that and the reason is
that the browser does not care about existing parameters in the action URL
so it removes them completely
and to prevent this from happening use this JavaScript function that I wrote
using jQuery in:
function addQueryStringAsHidden(form){
if (form.attr("action") === undefined){
throw "form does not have action attribute"
}
let url = form.attr("action");
if (url.includes("?") === false) return false;
let index = url.indexOf("?");
let action = url.slice(0, index)
let params = url.slice(index);
url = new URLSearchParams(params);
for (param of url.keys()){
let paramValue = url.get(param);
let attrObject = {"type":"hidden", "name":param, "value":paramValue};
let hidden = $("<input>").attr(attrObject);
form.append(hidden);
}
form.attr("action", action)
}
My observation
when method is GET and form is submitted, hidden input element was sent as query parmater. Old params in action url were wiped out. So basically in this case, form data is replacing query string in action url
When method is POST, and form is submitted, Query parameters in action url were intact (req.query) and input element data was sent as form data (req.body)
So short story long, if you want to pass query params as well as form data, use method attribute as "POST"
This is in response to the above post by Efx:
If the URL already contains the var you want to change, then it is added yet again as a hidden field.
Here is a modification of that code as to prevent duplicating vars in the URL:
foreach ($_GET as $key => $value) {
if ($key != "my_key") {
echo("<input type='hidden' name='$key' value='$value'/>");
}
}
Your construction is illegal. You cannot include parameters in the action value of a form. What happens if you try this is going to depend on quirks of the browser. I wouldn't be surprised if it worked with one browser and not another. Even if it appeared to work, I would not rely on it, because the next version of the browser might change the behavior.
"But lets say I have parameters in query string and in hidden inputs, what can I do?" What you can do is fix the error. Not to be snide, but this is a little like asking, "But lets say my URL uses percent signs instead of slashes, what can I do?" The only possible answer is, you can fix the URL.
I usually write something like this:
foreach($_GET as $key=>$content){
echo "<input type='hidden' name='$key' value='$content'/>";
}
This is working, but don't forget to sanitize your inputs against XSS attacks!
<form ... action="http:/www.blabla.com?a=1&b=2" method ="POST">
<input type="hidden" name="c" value="3" />
</form>
change the request method to' POST' instead of 'GET'.

Spring + JQuery dynamic binding

I am new to Spring and still learning. I want to make some more advanced form handling.
Currently my problem is dynamic list binding.
I want to have one text box, one list and add button. What is scenario?
User populates text box(with autocomplete) and cliks add button. After initiation add action, list gets populated without issuing request to server.
User adds few more items to list, and then submits form to server.
What is problem?
I dont know how to bind list or pass dynamic data to server.
Currently I have managed to get JSON response from Controller with list for autocomplete.
Is Spring forms suitable for this task? What is the right way to implement this?
Here's a stab at what I think you're trying to achieve. First: I'm assuming the issue isn't autocomplete/add to list, but rather what to do with the list in the MVC side. Let's say your command object has a property "employee names," defined as
List<String> getNames(){..}
void setNames(List<String>){..}
On the JSP side, you define the form list items like so:
<form:form>
<c:forEach items="${command.names}" var="name" varStatus="status">
<form:input path="names[${status.index}]" />
</c:forEach>
</form:form>
The real trick to making it "dynamic" with jQuery is to add to the form with the next increasing index. So somewhere you have:
<script type="text/javascript">
var count = ${fn:length(command.names)};
function addToList()
{
// add to form with name to "names[count]"
count++;
}
</script>
Putting it all together, you set the list in the controller formBackingObject to an AutoPopulatingList
That should be enough to get you started.

Categories