I have a form with a hidden field:
<input type="hidden" name="newdesc[]" id="newdesc" />
I have an autolookup and a plus button so the plus button adds the field value of the autolookup to an array:
newdesc_a.push(document.getElementById('autocomplete1').value);
var x=document.getElementById("businesslist");
x.innerHTML=newdesc_a;
document.getElementById('newdesc').value = newdesc_a;
(newdesc_a is previously declared as an array)
It updates the div OK (businesslist) but does not assign the value to the newdesc.
I am sure it is simple but it is driving me mad!
Given the name="newdesc[]" attribute, I assume PHP on the server side. When you submit a key two or more times, only the last value is available in the script via $_REQUEST. In the case of a key ending with [] , instead, PHP builds an array and make it available to your script via $_REQUEST['key']. Note that this behavior is application-specific, there's nothing like an array at the HTTP level.
Now, you want to pass an array from the client side (Javascript) to the backend (PHP). You have two options:
Use a proprietary format, eg separate values by commas or colons, and split the string on the server side (or you can use an existing format like JSON, XML, ...)
Take advantage of the PHP syntax for passing arrays
It seems you want to adopt the 2nd way, so you will want to submit a form like the following
<input name="email[]" value="joel#example.com" />
<input name="email[]" value="mark#people.com" />
<input name="email[]" value="bill#hello.com" />
PHP will be able to access a plain array in $_REQUEST if you build your form like this. Now, you have the problem of building the form programmatically on demand. This is the best I can think of (jQuery):
var email = $("#autocomplete").value;
// if you really need to keep emails in an array, just
// emails.push(email);
$('<input type="hidden">').attr({
name: 'email[]',
value: email
}).appendTo('#myForm');
You want to assign a particular value of array to that element?
You can use like this.
document.getElementById('newdesc').value = newdesc_a.index;
where 'index' is the index of array. replace it.
Related
I've have a CF page who's inventory search form, frm_inv post's back to itself. frm_inv's main table of records, tbl_inv, uses a tablesorter. A hidden input (sort_list) is used in conjunction with a cfparam to keep track of tbl_inv's sortList:
main.cfm
<cfparam name="form.sort_list" type="string" default="1,0">
<form id="frm_inv" action="main.cfm" method="post">
<input name="sort_list" type="hidden" value="#form.sort_list#"/>
<table id="tbl_inv" class="tablesorter">
...
</table>
</form>
When frm_inv is submitted, CF uses sort_list in $(document).ready() to restore tbl_inv's sort order:
$(document).ready(function(){
var sort_list_str = <cfoutput>"#form.sort_list#"</cfoutput>;
var sort_list = sort_list_str.split(",");
$("#tbl_inv").tablesorter({
textExtraction: ['complex'],
sortList:[[sort_list[0],sort_list[1]]]
}).bind("sortEnd", function(sorter) {
var sl = sorter.target.config.sortList;
$("input[name='sort_list']").val(sl.toString());
});
});
I would rather use arrays than convert a comma separated string into an array like I'm currently doing
<cfparam name="form.sort_list" type="string" default="1,0">
to
<cfparam name="form.sort_list" type="array" default="ArrayNew(2)">
however I need to know the proper javascript and coldfusion syntax in order pose everything that's relevant in arrays exclusively.
Copying a ColdFusion ... array into a JavaScript array
Why? For the most part, HTTP only transmits strings, so there is no translation between client and server complex types. Unless you are doing something more than just passing the sort value back and forth, converting between client and server side arrays is just an unnecessary complication. It is simpler to leave the value as a string and do any splitting or parsing on the client side.
You did not really explain what problem you are trying to solve, but .. there is nothing inherently wrong with the current approach. However, it could be simplified a bit. There is no need to cfoutput the variable again here:
(A) var sort_list_str = <cfoutput>"#form.sort_list#"</cfoutput>;
Since you already stored the current form.sort_list value in a hidden form field, the above is redundant. Instead, just read the field's value with javascript ie
(B) var sort_list_str = $("input[name='sort_list']").val();
Having said that, if you really prefer to work with arrays, you could store a JSON string representation of the arrays instead. Then use parse() and stringify() to convert the arrays back and forth. Same net effect as your current method, but a bit simpler in terms of code.
Form:
<cfparam name="form.sort_list" default="[[1,0]]">
...
<input id="sort_list" name="sort_list"
type="hidden" value="#encodeForHTML(form.sort_list)#" />
...
JQuery:
$(document).ready(function(){
$("#tbl_inv").tablesorter({
textExtraction: ['complex'],
sortList: JSON.parse($("#sort_list").val())
}).bind("sortEnd", function(sorter) {
var sort_arr = sorter.target.config.sortList;
$("#sort_list").val(JSON.stringify(sort_arr));
});
});
For creating a JavaScript variable from a ColdFusion variable, you can use toScript() function.
var #toScript(ListToArray(form.sort_list), "sort_list")#;
This can be used for wide range of variable types such as strings, arrays, structures etc.
Needs specific syntax to use an array in cfparam: ColdFusion CFParam Can Use Struct And Array Notation
<cfparam name="form.sort_list" type="array" default="#ArrayNew( 2 )#">
This has driven me "doo-lally" this afternoon!
A vendor (Zaxaa) uses a multi-dimentional form thus:
<form method="post" name="zaxaa" action="xxxx">
<input type="text" name="products[0][prod_name]" value="ABC">
<input type="text" name="products[0][prod_type]" id="pt" value="FRONTEND">
</form>
** This is my understanfing of how a multdimentional array is set up, and it seems to pass the variables to the server OK.
However, dependant on what other inputs are set to on the test form, the [prod_type] (and others) may need to change to "OTO" This is obviously going to be a javascript function, (but not the variant that starts with "$" on code lines ... whatever that type is!)
I have tried
document.zaxaa.products[0].prod_type.value
document.getElementById('products[0][prod_type]').value
document.getElementsByName('products[0][prod_type]').value
but in everycase, I get "products is not defined". (I have simplified the form as there are ten product[0] fields)
I've solved it... mainly a glaring error on my part. The getElementById worked fine ... except in my test script I'd used getElementById[xxx] and not getElementById(xxx)!! ie "[" rather than "(" Does help if you get the syntax right!
But I will take notice of those other methods, such as enclosing both array arguments in ["xxx"].
getElementById didn't work because the only one of those elements that has an id is the second input, with id="pt".
On any modern browser, you can use querySelector to get a list of the inputs using a CSS selector:
var nameInput = document.querySelector('input[name="products[0][prod_name]"]');
var typeInput = document.querySelector('input[name="products[0][prod_type]"]');
Then use their value property. So for instance, to set the name to "OTO":
document.querySelector('input[name="products[0][prod_name]"]').value = "OTO";
Use querySelectorAll if you need a list of relevant inputs, e.g.:
var nameInputs = document.querySelectorAll('input[name="products[0][prod_name]"]');
Then loop through them as needed (the list as a length, and you access elements via [n] where n is 0 to length - 1).
Re
* This is my understanfing of how a multdimentional array is set up...
All that HTML does is define input elements with a name property. That name property is sent to the server as-is, repeated as necessary if you have more than one field with that name. Anything turning them into an array for you is server-side, unrelated to JavaScript on the client. (The [0] is unusual, I'm used to seeing simply [], e.g name="products[][prod_name]".)
You can access it in this syntax:
document.zaxaa['products[0][prod_name]'].value
document.zaxaa.products[0].prod_type.value
The name is a single string, not making a nested structure to access the input. It would need to be
document.zaxaa["products[0][prod_type]"].value
// or better:
document.forms.zaxaa.elements["products[0][prod_type]"].value
The complicated name does only serve to parse the data into a (multidimensional) array on the server side, but all data will be sent "flattened".
document.getElementById('products[0][prod_type]').value
The id of your input is pt, so this should work as well:
document.getElementById("pt").value
document.getElementsByName('products[0][prod_type]').value
getElementsByName does return a collection of multiple elements - which does not have a .value property itself. Instead, access the first element in the collection (or iterate it completely):
document.getElementsByName('products[0][prod_type]')[0].value
I have an decent sized HTML form, on top of this is Javascript which can create many more 'records' to certain parts of the form. In total we could be talking 50+ INPUT elements.
I'm wondering of the best way to process all of this data by PHP:
Pass it as a normal INPUT elements via POST and let the PHP decode it all.
Or lose the names of the form input elements so they are not presented in the POST and then use Javascript on the submit event to encode all the required input elements into an object and then encode that object into JSON and pass via a single hidden input element.
I'm thinking the later would allow me to write clearer code on the PHP side, and it would basically be passed as an object once run through json_decode(), and would be more abstract from html changes. Whilst the former requires no javascript, but would need to be kept in sync with the html.
Or another method I've not thought of.
Which do you think would be the best way?
You don't even need JS to write "clearer code". You can pass arrays of data to PHP from forms in this manner. This is even clear enough. Taken from my other answer, you can do this (the previous question was about checkboxes, but should work with any input type):
<input type="checkbox" name="answers[set1][]" value="apple" /> //imagine checked
<input type="checkbox" name="answers[set1][]" value="orange" /> //imagine checked
<input type="checkbox" name="answers[set1][]" value="grape" />
<input type="checkbox" name="answers[set2][]" value="airplane" /> //imagine checked
<input type="checkbox" name="answers[set2][]" value="train" /> //imagine checked
<input type="checkbox" name="answers[set2][]" value="boat" />
<input type="checkbox" name="answers[solo]" value="boar" /> //single type value. note that there is no [] in the end
end up like this in the request array (like say POST):
$_POST[] = array(
'answers' => array(
'set1' => array('apple','orange'), //unchecked items won't be included
'set2' => array('airplane','train'), //unchecked items won't be included
'solo' => 'boar'
)
);
You do not need an abstraction layer between html and php. Nobody does.
Use normal html behavior and retrieve if from php the normal way.
If for some reason you really need an object instead the normal $_POST array, call
$POSTobject = json_decode(json_encode($_POST), FALSE);
In my experience I found that for large to very large forms the easiest was to keep the input fields in their own form, with tags, but rather to give the input fields a pattern name, like somefunctionalname_01, somefunctionalname_02, etc, and have the server-side processor to look for this class of variables.
Your business code can then sort the parameters according to the category they belong to, and you can use them at leisure in a structured way later.
e.g.
$MyBroadCategories = array('somefunctionalname', 'someotherfunctionalname');
foreach($MyBroadCategories as $Cat) {
foreach($_POST as $key => $val) {
if (preg_match('/^' . $Cat . '_(\d+)$/', $key, $bits)) {
// Please business code here with this particular class of variables
// Or add them to an specific array of candidates for later use.
}
}
}
}
}
Attention, in all cases, if you exceed the maximum number of parameters handled by your server (defaults to 1000), think of adjusting the max_input_vars parameter of your PHP configuration.
I'm developing a portlet for WebSphere Portal 6.1, with JSP/JSTL, pure javascript, no AJAX frameworks, with a JSP that shows a send feedback form and, when submitted, redirects to another JSP to show the user the success of the operation.
I use javascript to get the values of the form fields by using document.getElementById() function. For example:
var valorAsunto = document.getElementById("asunto").value;
where "asunto" is the ID of a text field in my form. Also my form has the following structure:
<form name="formularioCorreo" id="formularioCorreo" method="post" action="<portlet:renderURL><portlet:param name="nextTask" value="sendFeedback"/></portlet:renderURL>">
That works OK, but I'm having trouble when trying to build the <portlet:renderURL> tag from that javascript values: when I try to concatenate a string for the renderURL and then reassign to form action like this:
var valorAction = '<portlet:renderURL><portlet:param name="nextTask" value="sendFeedback"/><portlet:param name="asunto" value="'+valorAsunto+'"/></portlet:renderURL>';
document.formularioCorreo.action = valorAction;
document.formularioCorreo.submit();
The resulting string, when application is deployed, has the structure:
/wps/myportal/<portletpath>/!ut/p/c5/<a very long random sequence of
numbers and letters>/
So one can't figure out where the parameter values are, but if I print the assigned values it shows something like:
asunto: '+valorAsunto+'
instead of
asunto: this is a sample subject
I've been trying to use some other ways to concatenate the string; for instance with a StringBuffer, as shown on http://www.java2s.com/Tutorial/JavaScript/0120__String/StringBufferbasedonarray.htm
and also javascript functions like encodeURI()/decodeURI(), replace(), etc. but I just can't get either the URL with the right parameter values or the URL encoded in the structure shown above (the one with the long sequence of chars).
Sometimes I manage to get the right parameter values, by manually replacing in the valorAction assignation all the "<" for "<" and all the ">" for ">" before the concatenation, and then doing the following:
var valorAction = valorAction.replace(/</g,"<").replace(/>/g,">");
Then I get the following string:
<portlet:renderURL><portlet:param name="nextTask" value="sendFeedback"/><portlet:param name="asunto" value="this is a sample subject"/></portlet:renderURL>
which is OK, but when it has to redirect to the results page it shows an error like this
Error 404: EJPEI0088E: The resource <portlet:renderURL><portlet:param
name="nextTask" value="sendFeedback"/><portlet:param name="asunto"
value="this is a sample subject"/></portlet:renderURL> could not be
found.
Does someone know how to transform that string to the right format to be rendered?
Does someone know any other way to "inject" that parameter values to the renderURL?
I'd like to know also if it is possible to pass that parameter values from javascript to JSP so I could put that values in a HashMap of parameters to use with the PortletURLHelper.generateSinglePortletRenderURL() method, in case the former is not possible.
Thank you.
Update 1:
In my doView() I use the following, in order to make the redirection:
String targetJsp = "/_Feedback/jsp/html/FeedbackPortletView.jsp";
String nextTask = request.getParameter("nextTask");
//(... I have omitted code to conditionally select targetJsp value, according to nextTask value ...)
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(targetJsp);
rd.include(request, response);
This is just a new JSP inside my portlet, not a different portal page. I do use request.getParameter() to get the values for my form fields from my doview():
String subjectFeedback = request.getParameter("asunto");
String bodyFeedback = request.getParameter("mensaje");
String emailFeedback = request.getParameter("emailFeedback");
I don't see the need to include hidden fields if my form has the fields named above. In fact, what I'm trying to do is to pass the values the user entered in these fields as request parameters, but the values I get by this means are the following:
subjectFeedback: "'+valorAsunto+'"
bodyFeedback: "'+valorMensaje+'"
emailFeedback: "'+valorEmailFeedback+'"
I get the above values when using concatenation by "+"; when I use StringBuffer I get the following values:
subjectFeedback: "'); buffer.append(valorAsunto); buffer.append('"
bodyFeedback: "'); buffer.append(valorMensaje); buffer.append('"
emailFeedback: "'); buffer.append(valorEmailFeedback); buffer.append('"
Does someone know any other way to "inject" that parameter values to the renderURL?
There are two IBM guides on that topic.
Portal 6.1 and 7.0 Advanced URL Generation Helper classes
How to create a link to a portlet (Standard API) that passes parameters to that portlet
How are you redirecting to the other page? Is it a different portal page or just a new JSP page inside your portlet?
You don't need to inject any parameters to the render URL. Have a form whose action targets to a renderURL. Now to pass information to your portlet's doView() method, you can have hidden fields in the form ,then populate them using JavaScript and then submit the form. In the doView() method, you can use request.getParameter() to get the parameters.
Well, sometimes the most obvious things happen to be the way to the solutions.
I was too busy trying to find elaborated causes for that situation that I did not checked for this at all:
My form fields were correctly identified by different id, but they weren't set their name properties.
With the help of a work partner we could figure out that, so assigning the same value of id for name on each form field did the trick.
So, I ended up skipping that reassigning action thing, because the field values are being set as request parameters, as it should be.
Thanks for the help.
I'm using django and have a page of search results that I want to be able to filter by category with ajax (jquery) requests. There's a filter bar on the side of the page and when someone selects certain categories and clicks submit, those corresponding results should show up on the page. My code looks something like this:
<input type="checkbox" name="category1" value="1" />
<input type="checkbox" name="category2" value="2" />
<input type="button" name="submit" onclick="{
var cats = new Array();
$(input[type=checkbox]:checked).each(function() {
cats.push($(this).val());
});
$.getJSON('page.html', {'cats':cats}, function(data) {...});
}" />
But in the django view when I try to read the cats array it returns a 500 error. I can, however, pass scalars and strings to the django view with no problem.
Any thoughts? Is there a more elegant jQuery way to do this without using a javascript array?
Rather than getting the field values manually, you can use jQuery's serializeArray() method, which turns a set of fields into an array which can be sent as JSON. Note that you'll probably want both checkboxes to have the same name, so that when it's serialised it becomes something that Django will interpret as a list.
As Steve says, to help further we'll need to know what the view is doing and what the error is.
Got it working - I downloaded the jquery-json plugin, encoded my array as a json obect to send to django, and then used simplesjon.loads() in the django view to convert that json object to a python list. However, the fact that it took so many steps and jQuery on its own doesn't even come with json encode functionality still makes me think there must be a more elegant way - if anyone has any insight, I'd love to hear it.
Thanks Daniel for pointing me in the right direction.
I guess that a workaround would be transforming your array into a string, eg in javascript:
a = new Array(0,1,2,3,4);
[0, 1, 2, 3, 4]
a.join(" ")
"0 1 2 3 4"
Then you can pass this to the python back end, split it and reconstruct the data structure you need.....