Drag 'n Drop Destroys ID Numbering Scheme? - php

I have a web app which include a questionnaire editor. There can be many questions; each can have many answers; and each question has two sets of radio buttons for setting various question options.
I'm using the following style of IDs:
id="Q-$questionNumber"
id="Q-$questionNumber-A-$answerNumber"
...where '$questionNumber' and '$answerNumber' are replaced with the appropriate numbers.
The ID numbering scheme has two functions:
When an element is clicked, my javascript can examine the ID number to find out which question/answer it belongs to.
Input elements have names which follow this same numbering scheme. When the form is submitted, my PHP code can determine which question number/answer number the submitted value is associated with, by examining the name.
Naturally, when I drag and drop a question, all these IDs and names need to be renumbered. I've written javascript/jQuery that successfully renumbers everything and works correctly. But it feels kludgy.
It seems like I could remove the numbering scheme from all the IDs and just figure out what question number/answer number everything is by examining its placement in the DOM using jQuery. But it seems I would still need to use the numbering scheme on input element names so that my PHP code on the server could tell what question number/answer number the various submitted form elements belong to.
Is there a better way?
UPDATE per request from Bankzilla. Here is some sample HTML. This is one question. Each document can have many questions, each of which can have many answers.
<div id="Q-1" class="QuestionGroup ui-draggable">
<br>
<h2 id="QuestionText-Q-1">
Question #1
<input type="text" name="questionText-Q-1" value="" id="questionText-Q-1" class="questionText" maxlength="256" size="70">
</h2>
<div class="containerForAnswers">
<p class="answerPar">
<span class="answerLabel answerLabelinEditView">#1:</span>
<input type="text" name="Q-1-A-1" value="" id="Q-1-A-1" class="answer answer-Q-1" maxlength="256" size="70">
</p>
<p class="answerPar">
<span class="answerLabel answerLabelinEditView">#2:</span>
<input type="text" name="Q-1-A-2" value="" id="Q-1-A-2" class="answer answer-Q-1" maxlength="256" size="70">
</p>
<p class="answerPar">
<span class="answerLabel answerLabelinEditView">#3:</span>
<input type="text" name="Q-1-A-3" value="" id="Q-1-A-3" class="answer answer-Q-1" maxlength="256" size="70">
</p>
</div>
</div>

Not sure if this will help but you can actually use arrays in inputs. Makes structuring questions/ answers in your case much easier and you don't have to worry about numbering.
<input name="Q[1][text]"/>
<input name="Q[1][answers][]" value="number 1"/>
<input name="Q[1][answers][]" value="number 2"/>
When you have multiple Q[1][answers][] it will stack them like an array index, 0,1,2,3,4.
If you were to dump the above out it would look like
var_dump($_POST);
array(
'Q' => array(
1 => (
'text' => '',
answers => array(
0 => 'number 1'
1 => 'number 2'
)
)
)
)
Now when you drag an drop you only need to find what the question id is, instead of the order of answers.

After studying this some more, I think I might try something like this next time: leave question number/answer number identifiers completely out of all form element names and IDs. When the form is submitted, question number/answer number identifiers would be added via jQuery to all form elements. This way I wouldn't have to deal with renumbering any question number/answer number identifiers during drag and drop, insert, cut/paste, etc.

Related

POST-ing HTMLFormElements as Array Keep DOM Order Accross Browser

I am POST-ing three HTML input elements that has the PHP Array naming convention i.e. name="name[]" (the 3 inputs have different names "A[]", "B[]" and "C[]"). The input elements are children of <td> elements of which there are anything from 7 to 1001 <td>'s, meaning for each <td> there is 3 times the input elements i.e. 21 to 3003. The layout is similar to that of a Spreadsheet e.g.
<table>
<--! ... -->
<tbody>
<tr>
<td>
<input type="text" name="A[]" placeholder="A1">
<input type="hidden" name="B[]" value="A1">
<input type="hidden" name="C[]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[]" placeholder="B1">
<input type="hidden" name="B[]" value="B1">
<input type="hidden" name="C[]" value="2021-10-04">
</td>
<--! ... -->
</tr>
<--! ... -->
</tbody>
<--! ... -->
When I POST them I noticed that each input' Array keys on the server side conforms to the order the input element appears within the HTMLFormElement.
What I want to know is the order of array keys true accross browser? I could not find anything in the HTML Spec, but the PHP manual gives the following note when denoting an input name as name[] :
Specifying array keys is optional in HTML. If you do not specify the keys, the array gets filled in the order the elements appear in the form. Our first example will contain keys 0, 1, 2 and 3.
Thanks for your question, quite interesting, however I have problems to answer it specifically. That is because this depends on implementation and it can (or as we can see at least could) be different across browsers.
For the PHP part, this is encoded in PHPs source code and therefore defined, but that is only one side and my educated guess (have not looked into the sources) is that it depends on the input order.
This is how I understand it: Given the browsers build the form data set from successful controls and then encode it. For the PHP array keys (of which order you're interested in) with the HTML form (excerpt) example:
<form method="post">
...
<td>
<input type="text" name="A[]" placeholder="A1">
<input type="hidden" name="B[]" value="A1">
<input type="hidden" name="C[]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[]" placeholder="B1">
<input type="hidden" name="B[]" value="B1">
<input type="hidden" name="C[]" value="2021-10-04">
</td>
...
</form>
I would assume document order of the input elements to build the form data-set from. Problem with that is - IIRC - that in HTML there is no specification of document order. Within the DOM there is but from what I know a browser must not have a DOM. It's perhaps stupid to not have a DOM browser internally (or some structure with similar semantics) but there is no requirement in the HTML specification to have one: From what I know DOM is Javascript specific and a browser must not support any client side scripting.
NOTE: The HTML living standard supports this interpretation (as of today 2021-10-03). It does not relate to the DOM in form data encoding, instead it has tree order which has similar semantics to DOM document order. And it is the tree from which the list of input elements is obtained from that is used to identify the successful controls for building and encoding the forms' data. All lists have ordered sequence (first to last, add appends), are initialized empty and are traversed from start to end. So it is that this sequence is retained including in the encoding serializers' encoding which becomes the input parsed by the PHP SAPI.
This confirms the observation that the input order is always the same. If not (the part you're curious about), you could treat it as a flaw. Your standard form input validation should handle that case thought anyway, as any form data in the request could be composed elsewhere (e.g. different form, there is no same-origin policy for form submits) and therefore needs validation.
Considering there is DOM support and also used internally when creating the forms data-set and considering that the successful inputs are processed in document order when building the data-set, the following data-set in this top-down order (one control-name/current-value pair per line) is created:
A[]: A1
B[]: A1
C[]: 2021-10-03
A[]: B1
B[]: B1
C[]: 2021-10-04
If then the result of the encoding (not further specified for the order in the HTML 4.01 specs) of this data-set. Again it would be kind of counter-intuitive to implement it different to the processing order, but if in processing order this then defines the input-order as the PHP SAPI receives this data (HTTP request body) and forms the $_POST array out of it.
What then follows is the following (at least how I explain it to myself, not verified in the sources):
The $_POST array is initialized empty.
The first control-name is A[].
PHP "realizes" the array access brackets [] and that no index or key is given within those brackets.
Therefore the array is populated similar like in PHP code: $_POST['A'][] = 'A1'; (compare: array_push()).
These steps 2. - 4. are done for each name/value pair.
Now this does not specifically answer your question. However if you're asking because you'd like to set the indexes in stone (apart from any order), it should be possible to provide those within the HTML form control-names and it perhaps is what you're looking for:
<form method="post">
...
<td>
<input type="text" name="A[0]" placeholder="A1">
<input type="hidden" name="B[0]" value="A1">
<input type="hidden" name="C[0]" value="2021-10-03">
</td>
<td>
<input type="text" name="A[1]" placeholder="B1">
<input type="hidden" name="B[1]" value="B1">
<input type="hidden" name="C[1]" value="2021-10-04">
</td>
...
</form>
Then at least on the level of accessing via $_POST the keys are defined as the control-names need to be preserved by the HTML standard. And they have the names you expect, as you can re-create the order via the numerical index.
If you're concerned about rows, all you would need to do is to transpose those "named" parts (as PHP is handling the [...] array part) to their indexes:
// required input
$input = $_POST;
// define structure of result data
$fields = ['A' => null, 'B' => null, 'C' => null];
$count = 2;
// initialize the result
$result = array_fill(0, $count, $fields);
// map $input to $result
foreach (array_keys($result) as $index) {
foreach ($fields as $name => $default) {
$result[$index][$name] = $_POST[$name][$index] ?? $result[$index][$name];
}
}
Such a part is also a good place to verify the input is complete. The resulting $result (pick the name that fits best in your case) are also better to map onto database fields (e.g. use A, B, C, ... within the form when you generate the inputs from a structure and then map them back with the same structure onto database (or your applications internal entity/property names).
This is especially the case if you realized that the order was suddenly brittle - you can make the form creation/submission/data-handling a more distinct transaction even HTTP is stateless. At least more distinct on the data level.
Which brings me to another improvement/variant when writing the HTML of the form to have the data in the processing order already within $_POST. It won't spare the needed validation steps, however this can be done within PHP:
<td>
<input type="text" name="set[0][D]" placeholder="A1">
<input type="hidden" name="set[0][E]" value="A1">
<input type="hidden" name="set[0][F]" value="2021-10-05">
</td>
<td>
<input type="text" name="set[1][D]" placeholder="B1">
<input type="hidden" name="set[1][E]" value="B1">
<input type="hidden" name="set[1][F]" value="2021-10-06">
</td>
Then $_POST['set'] already contains the form-data in an ordered array and the transposition is not necessary and to map the order, ksort may suffice already:
ksort($_POST['set']);
So this can help with the immediate processing for the form data (the numeric indexes can be left out as well if the input elements are in the correct order, no ksort() necessary then, PHP will take care of that).
It would be even possible to leave the first name out but it might not be useful because of other form fields not relating to the set:
<td>
<input type="text" name="0[G]" placeholder="A1">
<input type="hidden" name="0[H]" value="A1">
<input type="hidden" name="0[I]" value="2021-10-07">
</td>
<td>
<input type="text" name="1[G]" placeholder="B1">
<input type="hidden" name="1[H]" value="B1">
<input type="hidden" name="1[I]" value="2021-10-08">
</td>
Makes $_POST a numerically indexed (in undefined order) array of arrays.

Using XPath in PHP to get cells from specific table [duplicate]

There is an HTML file (whose contents I do not control) that has several input elements all with the same fixed id attribute of "search_query". The contents of the file can change, but I know that I always want to get the second input element with the id attribute "search_query".
I need an XPath expression to do this. I tried //input[#id="search_query"][2] but that does not work. Here is an example XML string where this query failed:
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
Keep in mind that that the above is merely an example and the other HTML code can be quite different and the input elements can appear anywhere with no consistent document structure (except that I am guaranteed there will always be at least two input elements with an id attribute of "search_query").
What is the correct XPath expression?
This is a FAQ:
//somexpression[$N]
means "Find every node selected by //somexpression that is the $Nth child of its parent".
What you want is:
(//input[#id="search_query"])[2]
Remember: The [] operator has higher precedence (priority) than the // abbreviation.
This seems to work:
/descendant::input[#id="search_query"][2]
I go this from "XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition" by Michael Kay.
There is also a note in the "Abbreviated Syntax" section of the XML Path Language specification http://www.w3.org/TR/xpath/#path-abbrev that provided a clue.

How to combine two input with same name?

I'm trying to combine two input with same name. One part will be disable but user can see the random value and other part will be given by user.
[<div class="form-group col-md-6">
<label for="ProductCode">Product Code</label>
<input name="prid" type="text\[\]" class="form-control" id="prid" placeholder="Product Code" value="value">
</div>][1]
https://i.imgur.com/CqBHqBk.png
Not sure I understand your question correctly, but it seems to be simple. You can combine two input with same name using "class" html element.

HTTP ordering variables in form

given a form like the following
<form action="/page" method="POST>
<input type="hidden" name="input" value="12" />
<input type="hidden" name="input" value="24" />
</form>
Using Google Chrome 31.x and PHP 5.5, /page now has a $_POST variable for input of 24
This happens because when the $_POST array is created, The value is over written in the array. And the latter value is the value which is preserved.
Most browsers Ive tested this is the case, But Is there any HTTP spec / browser spec which says that form inputs should be sent in the order they are defined ? Or could an update in the future (or an old browser) send these updates in the reverse order for example ? or a random order ?
Edit:
to give more context, It will not be used like the above in all cases. only in a certain case.
The first form element is a SELECT box, But depending on the options chosen, Javascript will be able to change the value, Without changing the Select box value
Regardless of the order in which HTTP sends your two values, PHP can only have one value for $_POST['input'].
To solve this, use array notation:
<form action="/page" method="POST>
<input type="hidden" name="input[]" value="12" />
<input type="hidden" name="input[]" value="24" />
</form>
Now you'll have an array $_POST['input'] with both values.
To answer your question about the spec, see this page:
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
See the bullets for the application/x-www-form-urlencoded default content type.
The control names/values are listed in the order they appear in the document. The name is separated from the value by '=' and name/value pairs are separated from each other by '&'.
To my knoweledge there is no specification as to the order in which a browser should parse the from before submitting.
But I would say that you can pretty much assume that the form fields will be parsed from top to bottom, because the whole dom is parsed like this.
Here is a little bit additional information as to how a form submit is processed/handled.
http://www.w3.org/TR/html401/interact/forms.html#successful-controls
Steve

PHP - HTML - Get multiple checkbox value without making it become array

I have read through many questions and do my searches for hours, but i still cannot find the solution to what i exactly want.
<form method="POST">
<input type="checkbox" name="fruit" value="0" />No Preference
<input type="checkbox" name="fruit" value="1" />Apple
<input type="checkbox" name="fruit" value="2" />Orange
<input type="checkbox" name="fruit" value="3" />Banana
</form>
print_r($_POST);
I already did validation to checkbox value 0 to 1,2,3 so they will inverse and i did it using looping javascript search for the element name. The problem is, i have to use the element name without changing it become array name. (e.g Fruit => Fruit[] ). So i need to use this element name to retrieve all checked information inputted by the customer. I've seen this can be done in ASP, but i could not figure how they do as it's long time ago already.
My question is, could any one figure how to do this without changing the element name into array format (e.g Fruit => Fruit[] ) ? T.T
Any help will be appreciated. Thank you..
As you already figured, when you submit the same name multiple times, the latest one will overwrite former ones. A solution is to set up a hidden field
<input type="hidden" value="" name="foobar_as_array">
and use jQuery or plain JS to concat your values into that field on submit
<form ... onSubmit=$('#foobar_as_array').value(...concatenate them...);">
I changed the validation using this line :
var GenBox = eval("document.forms['SubmitSearchAll']['" + oCheckBox+"[]']");
and it helps me alot. Now it is solved.
Thanks everyone for contributing.

Categories