Submitting hidden field data on Android/iOS browsers does not work - javascript

I am working on a site which connects to a MySQL database and lets you display/edit the data in it. The site uses JavaScript and PHP, with HTML and CSS parts (these are added using JS).
The site works, does everything I wanted it to do, but only from PC. When I try to use it from a smartphone, some of the hidden fields' value doesn't get submitted correctly to the PHP page responsible to working with them.
First, I have a few of this select box:
var maxLvl;
var select = document.createElement( 'select' );
var trooplist = [archerLvl, giantLvl, wizardLvl, balloonLvl, dragonLvl]; //this array contains numbers, which will be used to set the starting option in the select
select.id = "select" + k + " " + i; //k and i are both variables in their respective for loop: k goes from 0 to 2, in it there's another with i.
select.onblur = function() {
var selectid = this.id;
var last = selectid.slice(-1);
if(last==0){
document.getElementById("hiddenArcherid").value = this.value;
alert(document.getElementById("hiddenArcherid").name + " " + document.getElementById("hiddenArcherid").value);
}else if(last==1){
document.getElementById("hiddenGiant").value = this.value;
alert(document.getElementById("hiddenGiant").name + " " + document.getElementById("hiddenGiant").value);
}else if(last==2){
document.getElementById("hiddenWizard").value = this.value;
alert(document.getElementById("hiddenWizard").name + " " + document.getElementById("hiddenWizard").value);
}else if(last==3){
document.getElementById("hiddenBalloon").value = this.value;
alert(document.getElementById("hiddenBalloon").name + " " + document.getElementById("hiddenBalloon").value);
}else if(last==4){
document.getElementById("hiddenDragon").value = this.value;
alert(document.getElementById("hiddenDragon").name + " " + document.getElementById("hiddenDragon").value);
}
};
select.style.position = "absolute";
select.style.left = 250 + (i*(width + (width/10))) +"px";
select.style.top = 110 + height + (rowcounter * (height * 1.5)) + "px";
select.style.width = width;
if(i==0 || i==1 || i==2 || i==3)
maxLvl = 6;
else
maxLvl=4;
for(var l=0; l <= maxLvl; l++){
var option = document.createElement( 'option' );
option.setAttribute("value", l);
option.innerHTML = "Level " + l;
select.appendChild(option);
}
select.selectedIndex = trooplist[i];
IDarray.push(select.id);
document.body.appendChild(select);
This code runs in a for loop, and creates 5 select boxes using data passed by a function. Then, when the user selects a new option, the option's value is stored in a HTML hidden input field with. Like this one:
var hiddenArcher = document.createElement('input');
hiddenArcher.setAttribute("type","hidden");
hiddenArcher.name = "hiddenArcher";
hiddenArcher.id = "hiddenArcherid";
hiddenArcher.setAttribute("value", document.getElementById("select1 0").value);
formNew.appendChild(hiddenArcher);
These input fields have a basic value, which is the default of the select box - 0 if the user creates a new entry, or an already known value if the user wants to modify an already existing entry. All the input fields have the same structure, only the JS var, the name, the id and the default value changes.
The input fields are part of the formNew form, which has multiple submit buttons - pressing those buttons posts the fields' values to a PHP page, which executes the MySQL queries, depending on which button was pressed. For this, I use if/else if (isset). Then the PHP redirects (by using header("Location: http://my_sites_address"); exit();) to the main page - the one I where the select boxes are.
If I try it from Chrome, the site works - The right values get passed, the PHP executes the right queries correctly. I can add new entry, and both delete or modify existing ones. When I try it on Android (via emulator) or iOS (via my friend's phone), although I can select the values I want to change, and the alerts display the correct data, too, when I hit submit, nothing happens within the database, it seems like I did nothing. The browser gets redirected to the PHP, so I guess the submit does happen, but there will be no changes in the database. The PHP simply redirects to the main page, and that's all.
The only function can be used successfully on phone is deleting the entry, most likely because the hidden field responsible for storing the row's ID gets it's value the moment it's added to (a different) form, and the value never changes, only when the user switches to a different entry.
The hidden fields "physically" (based on their location in the file) are declared later than the select boxes.
Currently, the code acts this way on phone:
1) I start editing the entry. The select boxes show up.
2) I can select the desired value.
3) An alert pops up, confirming the value got passed to the hidden field.
4) I press the submit button, comes the PHP, then the redirects, and I am back where I started. There are no changes in the database.
I already tried to switch onchange to onblur at the select boxes; I made sure JS is enabled (which was totally unnecessary, because the images/texts displayed with JS). Right now I have no idea what's wrong.
Are any of you experienced something similar, or has any idea what should I do?

Some browsers fail to correctly and completely recognize the programmatic change of a hidden input's value immediately after it is changed. If you submit the form directly after changing the hidden input's value via javascript, the value sent for that input will be the pre-change value, rather than the value you set in javascript.
Unfortunately, I don't have a list of browsers that exhibit this behavior, nor do I know the exact mechanics behind it. What I do know is that I've run into the issue you're describing, and I have always been able to solve it by triggering a change event on the hidden input after changing its value via javascript.
For those using plain javascript with no external libraries, your code would look something like this (see here):
<input id="myHidden" name="myHidden" type="hidden" value="old value"/>
<script type="text/javascript">
var hiddenInput = document.getElementById('myHidden');
hiddenInput.value = 'new value';
console.log(hiddenInput.value); // = 'new value'
// Submit the form now, and myHidden='old value' will be sent to the server
// Set up and trigger the change event on our input:
var changeEvent = document.createEvent("UIEvents");
changeEvent.initUIEvent("change", true, true);
hiddenInput.dispatchEvent(changeEvent);
// Submit the form now, and myHidden='new value' will be sent to the server
</script>
For those using jQuery or a similar library, the code is a little more concise:
<input id="myHidden" name="myHidden" value="old value"/>
<script type="text/javascript">
var $hiddenInput = $('#myHidden');
$hiddenInput.val('new value');
console.log($hiddenInput.val()); // = 'new value'
// Submit the form now, and myHidden='old value' will be sent to the server
// Trigger the change event on our input:
$hiddenInput.change();
// Submit the form now, and myHidden='new value' will be sent to the server
</script>
Really concise example (one-liner) using jQuery:
<input id="myHidden" name="myHidden" value="old value"/>
<script type="text/javascript">
$('#myHidden').val('new value').change();
// Submit the form now, and myHidden='new value' will be sent to the server
</script>
Here's a working example using a slightly simplified version of the code supplied in the original question.

In our case, the issue was simply that we had this check in PHP:
if (isset($POST['myvalue']) && !empty($POST['myvalue'])) {
// save
}
However, in PHP 0 is considered empty in PHP and thats exactly what the passed value was!

Related

Not able to populate textarea value if it's updated?

On click of a button, I am showing a popup with one text area and a submit button.
I am able to enter a value in the textarea (e.g.: "hello1"), and when clicking on the submit button, I am checking the textarea's entered value, it gives me "hello1", and fades out the pop up. (as expected)
Issue: the second time, I click the same button again, I entered the value "hello2", and after submitting, it shows me the last entered value in an alert and fades out.
Below is my code:
function onCalChange(cal) {
// inputField = cal.inputField;
startDate = cal.date;
var calVal = this.id;
popup2(calVal);
}
function popup2(calVal) {
idValue = calVal.split("-");
$('.popup2').css('display','block');
//$('.popup2').addClass('pop_up_bckgd');
$(".popup2").append("<div class='pop_up_bckgd'></div>");
$(".popup2").append("<div class='pop_up_container'><form>\n\
\n\
\n\
<label style='margin-left:65px;margin-top:40px;'class = 'label-value' for = 'reason-for-change-" + idValue[2] + "'>Reason for change</label>\n\
<br>\n\
<textarea id='reasontxt" + idValue[2] + "'style = 'width: 74%;margin-left: 62px;height:100px' class = 'text-box' name = 'reason' required></textarea>\n\
<br>\n\
<div style = 'text-align:center'><input class = 'submit-value2' type = 'button' value = 'Submit' name = 'submit1' onclick= 'clicksubmit(idValue[2]);' '></div ></form>")
}
function clicksubmit(id) {
var idNum= parseInt(id);
if ($('#reasontxt' + idNum).val() == "") {
// alert("1");
$('#reasontxt' + idNum).next(".validation").remove();
$('#reasontxt' + idNum).after("<div class='validation' style='color:red;margin-top:5px'>Please enter Reason for change Field</div>");
} else {
alert('2');
alert($('#reasontxt' + idNum).val());
$('#reason' + (idNum)).val($('#reasontxt' + idNum).val());
// $('#reasontxt' + idNum).val() == ""
$('.popup2').fadeOut();
}
}
After making he change specified by erkaner on the comments, I was able to reproduce the issue by copying your code into this JSFiddle: http://jsfiddle.net/v2djohhw/ (I had to make another minor change to hardcode the value of calVal for testing).
From what I saw, the issue is:
Every time that you click on the button, a form with a textarea and a submit button are appended to the popup (using $(".popup2").append(...));
the id of the textarea depends on the id of the button that was clicked (calVal);
so if the same button is clicked several times [or the button is different but it has an id which third part (as you are splitting it and only using the third value idValue[2]) matches the one of a previously clicked button], you will be appending multiple textarea over time, all of them with the same id.
when you submit, and read the value of the textarea, as there are multiple with the same id, the browser will take the value of the first textarea with the specified id.
Because of that you get always the same value that is the one of the first textarea.
How to fix it? Avoid having multiple elements with the same id.
One possible solution: delete the content of the .popup2 box every time you are going to display it, that way you make sure that the id of the textbox is really unique and you don't face unexpected errors:
$(".popup2").html("");
You can see it working here: http://jsfiddle.net/v2djohhw/1/
If you don't want to (or you cannot) delete the content of the .popup2 box, and want to show all the previous textareas, another solution would be keeping track of the number of times the button was clicked and add that value into the id of the textarea. That way you'll make sure the textbox id will be really unique.
You can see it on this other fiddle: http://jsfiddle.net/v2djohhw/2/

Running javascript on page back

I have the following problem:
I've created a form with several input fields like these:
<td>Pizza Margherita</td>
<td><input type="number" id="countMargherita" class="formnumbers" name="PizzaMargherita" onChange="validateForm(this);changeTotalFromCount(this);" data-unitprice="7"/></td>
<td><span id="totalMargherita"></span></td>
11 to be exact.
the onChange="changeTotalFromCount(this)" looks as follows:
function changeTotalFromCount(input) {
var unitPrice = parseFloat(input.getAttribute("data-unitPrice"));
var count = input.value;
var price = unitPrice * count;
var formattedPrice = '\u20ac ' + price.toFixed(2);
var label = input.parentNode.nextElementSibling;
label.innerHTML = '';
label.appendChild(document.createTextNode(formattedPrice));
}
Now what this does is say the user wants 5 pizza margherita's he enters a 5 in the input field and then immdediately shows the cost which in this case is 7*5= 35. This works just fine, but when the user submits the form he gets taken to another .php file where he sees the confirmation with all the details. There is also a button that needs to take them back to the order page again. I did this first by just sending it straight to my orderform.php but as this doesn't save the customer his input i decided to use this instead:
<input type='button' value='Bestelling Wijzigen' onClick="history.go(-1);return false;" class='printbutton'>
I don't know if this is the right thing to do or not, but i saves the user's his information as he goes back. Except it doesn't show the prices next to the input anymore unless he/she changes the input again. And there lies my problem, i'd like it so that if the user goes back to change his order he can still see the costs of each product without changing it before he can see it again.
Im not really an expert in JS or PHP.
(if you miss any information please let me know!)
You can use the onload event to run code that initializes all totals. It's fired when you go to a page with the backbutton as well as when you visit it in any other way.
So, for example
function initTotals()
{
var inputs = document.getElementsByTagName('input');
for(var i=0; i < inputs.length; i++)
{
changeTotalFromCount(inputs[i]);
}
}
window.onload = initTotals;
http://jsfiddle.net/XK99Z/

How to find dropdown's selected option's index/value using javascript, before the selection change

I am not sure if the title of my question is meaningful enough, so here is my problem :
I have a dropdown dynamically generated from server side as below:
sb.append("<SELECT NAME='selectedQAStatuses' id='selectedReleaseQAStatuses' onchange='javascript:changeReleaseQAStatus(\""+releaseId+"\",\""+depEventSeq+"\",this);' >");
sb.append("<OPTION>Please select a QA status...</OPTION>");
for (String status : statusArray) {
if(status.equals(releaseStatus))
sb.append("<OPTION VALUE='"+status+"' selected>"+status+"</OPTION>");
else
sb.append("<OPTION VALUE='"+status+"'>"+status+"</OPTION>");
}
Now javascript : changeReleaseQAStatus() is getting called. In this javascript method I am calling a confirm() to see if user is sure or not. If user selects "OK" in the confirm popup then from the "IF" block i make a Ajax call etc., but if user selects "Cancel" in the confirm popup, then from the "ELSE" block I return from the JS method.
However, in "Cancel" scenario i see that although the user seems to have "Cancelled" his selection, still on the browser screen the dropdown seems to show the new option as "selected".
Therefore I think, in Javascript's "ELSE" block i should write something which should revert the selection to the original selection. How am I supposed to 'remember' what was the original value of the dropdown when the page had rendered on the browser, so that I can user this initial value in my 'ELSE' block to restore my dropdown.
My Javascript to handle 'OK' and 'CANCEL':
function changeReleaseQAStatus(releaseSeq, depEventSeq, element1){
var selectedIndex = element1.selectedIndex;
var selectedStatus = element1.options[selectedIndex].value;
if (confirm("Do you want to change Release QA status to \"" + selectedStatus + "\" ?")){
url = contextPath + "/changeQAStatusOfRelease.action?selectedStatus="+selectedStatus+"&releaseSeq="+releaseSeq+"&depEventSeq="+depEventSeq;
ajaxUpdate({url:url,
elementId:'compReleasesDtlsDiv',
});
}else{
/// No Code needed to execute here...
}
}
by using javascript you can use something like this
var arr = document.getElementsById('select_id');
alert(arr[0].options[arr[0].selectedIndex].value);

overriding data-confirm values

I want to change the value of data-confirm attribute on a button (submit) based on user's choices on a form. I put the following on the change function of a dropdown list:
...
if($("#"+select_name).val() == "abc")
{
$(".variable_button").attr("data-confirm","abc is good choice!");
} else
{
$(".variable_button").attr("data-confirm","abc would have been great but this is fine too...");
}
...
The problem I am facing is that apparently data-confirm cannot be changed once it is assigned a non-empty string. I have it set to "" in the server code. And, it changes to one of the two messages shown above when the user first makes a selection on the dropdownlist. But if the user changes the selection one more time, the data-confirm message does not change. Is this per design or am I missing something?
Don't use .attr(), use .data():
var newData = ($("#"+select_name).val() == "abc")
? "abc is good choice!"
: "abc would have been great but this is fine too...";
$(".variable_button").data("confirm", newData);
jQuery does allow you to update a data- attribute with the .attr() method, so something else is breaking.
Here's a working example (JSFiddle):
var counter = 1;
$('#click').click(function() {
button = $('#click');
console.log(button.attr('data-confirm'));
button.attr('data-confirm', 'this is test ' + counter);
console.log(button.attr('data-confirm'));
counter++;
});
Can you try to repo the issue in a JSFiddle?
On rereading your question, it sounds like an event handler isn't firing the second time the user changes the selection. See if you can set a breakpoint in your event handler to see if it even gets hit.

Javascript won't update DOM on what appears to be recent Items

I'm using 100% pure javascript, tried Jquery but it didn't help. Code not working in FF/Chrome/Safari.
I have built Edit-In-Place functionality where when the user clicks "Edit" (calling external function with onclick - passing in item_id) -- a string of text is hidden to reveal an input with the same string of text in it. (by changing classes) "Edit" is also replaced by "Save". When done editing the string - the user clicks save, and everything reverts back to normal.
AJAX is processing all the updates - but commenting out the AJAX block does not fix it.
I am loading a stream of these objects. The javascript works for all of them - but only updates the DOM, visually anyway for what appears is items before the last 24 hours. The blocks themselves are identical. That is - items that have been added within the last 18-26 hours when I click "Edit", do nothing. BUT if I alert out the class of the element I want to edit it says "editing" (as opposed to "saved") like it is working. (see below) Although this change is never reflected in inspect element.
Code on Page
<input type="text" class="input_field" id="input_254" value="Foo" onkeydown="javascript: if (event.keyCode == 13) { update(254); }" style="display: none; ">
<span class="user_links" id="display_269" style="display:none;">Foo</span> //hidden span that holds the value and acts at the check
<span id="edit_state_269" class="saved" style="display: none;">Foo</span>
<span onclick="update(269)" id="edit_269">Edit</span>
External Javascript
function update(item_id) {
var links_span = document.getElementById('display_' + item_id);
var input_span = document.getElementById('input_' + item_id);
var string_old = document.getElementById('edit_state_' + item_id).innerHTML;
var state_check = document.getElementById('edit_state_' + item_id);
var edit_button = document.getElementById('edit_' + item_id);
if (state_check.getAttribute('class') == 'saved') {
// Hide the links display list and show the input field
links_span.style.display = 'none';
input_span.style.display = 'inline';
// Change the Edit button text and state_check
edit_button.innerHTML = 'Save';
state_check.setAttribute('class','editing');
//alert(state_check.getAttribute('class')); // this alerts "editing" although in DOM it is still "saved" on the blocks that are the problem
If any more details would be helpful - I will provide them.
It is a devil of a problem - with no obvious solution. Would really appreciate any direction you can give!
Solved. As usual it's the little things. The first few blocks were being loaded on page load - and then hidden as the user navigated resulting in duplicate IDs. Javascript naturally selected the one higher on the page - the one that was hidden.

Categories

Resources