I can't seem to get the inputted text of a textarea. When I do :
die($request->getPostParameter('comment'))
It outputs the word "array". When I print_r() it does show the textarea is an array and its value is stored in the array. But I don't know how to get that value so I can put it into a field in a table.
#greg0ire: I am doing this because I am trying to save data to two different tables. My html page displays a form that is actually made up of two forms from two different classes/models. I have managed to save all fields to both tables except for the comment field. I then tried getting the value and realising it was an array, wondered if this was what was causing my data not to save. This is why I am asking this question. I have asked another question which explains the context.
These are the functions that run on clicking the submit button
public function executeUpdateInlineForm(sfWebRequest $request)
{
$overdueInvestigation = Doctrine_Core::getTable('investigation')->find( $request->getParameter('id'));
$investigationForm = new investigationInlineForm($overdueInvestigation);
$commentForm=new commentForm();
$investigationForm->bind($request->getParameter($investigationForm->getName()), $request->getFiles($investigationForm->getName()));
$commentForm->bind($request->getParameter($commentForm->getName()), $request->getFiles($commentForm->getName()));
$this->processInlineForm($investigationForm, $commentForm);
}
protected function processInlineForm(sfForm $investigationForm, sfForm $commentForm)
{
if ($investigationForm->isValid())
{
$investigation = $investigationForm->save();
$comment = $commentForm->updateObject();
$comment->setInvestigation_id($investigationForm->getObject()->getId());
$comment->setComment($commentForm->getObject()->getComment());
$comment->setuserId($investigationForm->getObject()->getCreatedUserId());
$comment->setDateEntered(time());
$comment->save();
$this->redirect('investigation/overdue/');
}
}
you could simply store $request->getPostParameter('comment') in an array and use array_pop() on this array, but I think it would be better to understand why you're getting an array. I think the name of the textarea must be comment[], when it should probably be just comment.
UPDATE
After reading your update and your other question it seems you need to have this naming convention for your fields:
<input type="text" name="investigation[field1]"/>
<input type="text" name="investigation[field2]"/>
<input type="text" name="investigation[field3]"/>
<input type="text" name="comment[content]"/>
Use the setNameFormat() method on the widget schema of your forms to achieve this, then bind your investigation form to the investigation request parameter, and your comment form to the comment parameter and you will be fine.
Good luck!
Related
normally I use command objects to work with submitted values. But if multiple values of the same property are submitted via AJAX (using jQuery) I was not able to use command objects.
In my GUI the user can click on checkboxes to mark some objects. Let's assume the name of the checkboxes is provider, i.e.
<input type=checkbox name=provider value=1>
<input type=checkbox name=provider value=2>
and so on...
When the clicked values are submitted via AJAX, in the Grails controller these values are in an map:
params.'provider[]'
where the key is provider[] and the value is an array of Strings if multiple checkboxes are clicked, otherwise it's just a String.
The problem is, that I can not create a command object with a property named provider[]. What I tried was:
class MyCommand {
Long[] provider
// or
List<Long> provider
}
but that didn't work.
So, my question is, how can I use a command object in this case? I want Grails to do the mapping, I do not want to do the mapping myself.
I am using Grails 2.3.11.
Thanks in advance,
best regards,
Daniel
To use command object, change your check box name to provider[index]
<input type="checkbox" name="provider[0]" value=1>
<input type="checkbox" name="provider[1]" value=2>
and so on...
and change your command object --
import org.apache.commons.collections.FactoryUtils
import org.apache.commons.collections.ListUtils
class MyCommand {
List<Provider> provider = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Provider))
}
I have a small problem.
I want to have dropdown list with some objects. After clicking on one I want to add it to list with textfield for naming it. I don't want to limit quantity of this fields. I want to receive in controller ID (stored in dropdown list) and name (given by user) for each selected item. How can I do it?
I was thinking about storing it in some fields as a text, and parsing in cotroller but I think it's not elegant.
EDIT.
Ok, Thansk for your help, but it's not working for me correctly.
I generate html like this:
<input type="hidden" value="96" name="Inputs[0].Key">
<input type="text" name="Inputs[0].Value">
In my controller I'm receiving this dictionary. The problem is that quantity of elements is correct, but all values are null. What is wrong here?
The best way to go about this is by using array-style model binding.
So, for each element you wish to name you create a hidden field to store the drop down value plus a text field to store the user-given name. You name them as follows:
<input type="hidden" name="element[0].Key" /><input type="text" name="name[0].Value" />
increasing the index value each time. This is easily achieved with a bit of JavaScript. You then create an action method which takes a KeyValuePair<string, string>[] as a parameter. You will then be able to parse through your values no problem with a loop or LINQ expression.
Use IEnumerable<KeyPairValue<string,string>> MySelectedItem = new List<KeyPairValue<string,string>>(); on model, and when adding it to the list, name it like an array:
MySelectedItem[1].Key, MySelectedItem[1].Value, MySelectedItem[2].Key...
(I haven't tested this, but it should work)
Edit: check out this blog post with better explanation on how to do it: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
I have a collection of objects on my Model that I'm rendering in a View by using EditFor function, and I have an EditorTemplate which is responsible for actually rendering each object.
#Html.EditorFor(model => model.MyObjects)
This has worked well for a while now, and when you check the html, my text boxes are prefixed with the model property, followed by the index of the collection they came from.
<input class="text-box single-line" id="MyObjects_2__SomeProperty"
name="MyObjects[2].SomeProperty" type="Text" value="" />
However I've recently started using the ShowForEdit and ShowForDisplay properties in the model metadata for the collection, and in the first line of my editor template if the ShowForEdit is not true, I just skip it.
#if (!ViewData.ModelMetadata.ShowForEdit)
{
return;
}
But because these are all indexed in the html, when I try to save this collection back to the viewmodel via a postback, it fails because of a reliance on the indexing numbers. Every item in the collection after the missing index is missing from my view model when I check it's value.
In this case it's actually my first item in the collection that I'm skipping since I don't want it to be visible on the edit view, but because of this when I postback the first index in the html is 1 (instead of 0 like it normally would be), but this is a problem when you try to save the changes. This is also a problem when altering the DOM using javascript.
Has anyone else encountered a problem with the default model binder's ability to read data posted back when one or more indexes in the html represented collection are not present?
Are there model binders that handle this problem?
Ran into this issue recently and solved it by converting the List to a Dictionary<string, model> with GUIDs as the key.
#foreach (var index in Model.EmailAddresses.Keys)
{
<label asp-for="#Model.EmailAddresses[index].Email">Email</label>
<input asp-for="#Model.EmailAddresses[index].Email" type="text" />
}
This avoided having to include hidden inputs that map to the index value.
There are some very good blog posts that allow you to modelbind to a list without the need to provide zero based contiguous index. plz have a look at
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
http://zahidadeel.blogspot.com/2011/05/master-detail-form-in-aspnet-mvc-3-ii.html
Furthermore, if you are interested in MVVM pattern and knockout js you can check this great work by steve sanderson
For more reading put "editing varibale length list mvc style" in google and it will give u a dozen useful links
I have seen lots of questions relating to this topic.
I am using asp.net MVC 1.0
Problem area
If I use
<%= Html.CheckBox("Status", true) %>
Then why It renders like
<input checked="checked" id="Status" name="Status" type="checkbox" value="true" /><input name="Status" type="hidden" value="false" />
I put this in foreach loop and I have 5 rows.
when I submit form with true,true,true,false,false
then I get true,false,true,false,true,false,false,false
i.e. for false => false.
for true => true,false
If I use
<input type="checkbox" value="true" name="Status" checked="checked" />
Then I don't get unchecked one's.
so how do I overcome form this problem?
Please don't post answer with using loop in formcollection object and checking each key!
I know this isn't the elegant one but this is what I did:
collection["response"].Replace("true,false", "true").Split(',').ToList();
In your example, when you submit form with true,true,true,false,false and you get
true,false,true,false,true,false,false,falseit is interesting to note that you are not actually getting eight values back, but five arrays that merely looks like this is the case because all of the values are joined.
I know you asked to not get a loop for your answer, but I can use one to demonstrate what is really happening here:
foreach (string key in postedForm.AllKeys) {
// "value" will contain a joined/comma-separated list of ALL values,
// including something like "true,false" for a checked checkbox.
string value = postedForm[key].GetValue;
// "values" will be an array, where you can access its first element,
// e.g., values[0], to get the actual intended value.
string[] values = postedForm.GetValues(key);
}
So, for your checked boxes, you'll get a values array with two elements, and for unchecked boxes, you'll get just a single-element array.
Thus, to answer your question how do you overcome this problem, the answer lies in using GetValues rather than GetValue, and thinking of your posted fields as arrays rather than strings.
Best of luck!
Personally I think having to check for "true,false" everywhere on the server is a pain. I wrote a jquery fix that will remove the extra hidden field created by the Html.Checkbox helper when a box is checked, then add it back if the box is unchecked. Server values will always be "true" or "false". Checkbox lists are kind of subjective in how you want them to act, which I discuss, but I'm removing "false" from the value set, which means the form value will be excluded if all boxes in the list are unchecked.
http://www.mindstorminteractive.com/blog/?p=386
I've had pretty good success using this technique. Please let me know if you try it out and have issues.
You'll have to do your own model binding for the CheckBox values.
Get the list of values from the FormCollection or Request.Form for that CheckBox id and replace true,false with true:
string chkBoxString = Request.Form["checkboxID"].Replace("true,false", "true")
Now you have a list of whether a CheckBox was selected or not.... do the rest yourself :)
It renders so because default binder requires the FormCollection to have a value for nonnullable parameters. Using this technique we are sure that the value will be sent even the checkbox is not checked (by default the value sent only when it's checked). If you use this controller method with just one html input you'll get error on form post with unchecked checkbox (value of checkbox will not be posted and binder will not know what to use for value of isItemSelected):
public ActionResult SomeActionMethod(bool isItemSelected)
You can try use something like this with just one html input:
public ActionResult SomeActionMethod(bool? isItemSelected)
But in this case isItemSelected will be null or will be true. And it will never become false.
Well there are couple of ways you can do based on your requirement.
I use this method.
<input type="checkbox" value="<%= item.ID %>" name="check" checked="checked")" />
This is may checkboxes.
On server side I will also have array of ID's of item in the model.
So I check it whether it is in array
var strArray = form["checkbox"]; //Request.form["checkbox"] or "FormCollection form" in action parameter; array of ID's in comma separated string.
Different people have different tests.
this was intended to use for just just simple CheckBox, what you want is checkboxList, which is not yet cover in the API of ASP.net MVC
If you looking for some thing like checkboxlist, maybe you should write your own helper, provide you understand HTML well..
That's it! :)
Easier just to check whether AttemptedValue.Contains("true") - it will, if it's checked, not if it's unchecked....
in the View :
<input id="radio5" type="checkbox" name="rb_abc" value="5"/>
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult YourForm(FormCollection fc)
{
if (fc["rb_abc"] == "on")
{
//Hey .. you have selected a Radio Button.. just kidding.. its a CheckBox
}
}
To get checkbox value even it is true or false
var boolValue = bool.Parse(collection.GetValues("checkboxID")[0])
Say you create a form using ASP.NET MVC that has a dynamic number of form elements.
For instance, you need a checkbox for each product, and the number of products changes day by day.
How would you handle that form data being posted back to the controller? You can't set up parameters on the action method because you don't know how many form values are going to be coming back.
Just give each checkbox a unique name value:
<input class="approveCheck" id="<%= "approveCheck" + recordId %>"
name="<%= "approveCheck" + recordId %>" type="checkbox" />
Then parse the list of form values in the Action, after submit:
foreach (var key in Request.Form.Keys)
{
string keyString = key.ToString();
if (keyString.StartsWith("approveCheck", StringComparison.OrdinalIgnoreCase))
{
string recNum = keyString.Substring(12, keyString.Length - 12);
string approvedKey = Request.Form["approveCheck" + recNum];
bool approved = !String.IsNullOrEmpty(approvedKey);
// ...
You don't need to pass form values as arguments; you can just get them from Request.Form.
One other option: write a model binder to change the list into a custom type for form submission.
Per Craig's answer.. that is safer. There are quirks to posting multiple form elements with the same name. I would add that it would be wise to wrap the logic that makes the "collection" of controls in a way similar to WebForms. Web Forms prepend the container control's name and adds an index. For example, in a Repeater the form elements inside would be named (something like) RepeaterName_Element1, RepeaterName_Element2. When you go to get the elements out, you have to use FindControl or something of the sort.
Depending on the binders you are using, this should work:
<%var i = 0;
foreach (var product (IList<ProductSelection>)ViewData["products"]) {%>
<%=Html.Hidden(string.Format("products[{0}].Id", i), product.Id)%>
<%=Html.Checkbox(string.Format("products[{0}].Selected", i))%>
<%=product.Name%><br/>
<%}%>
...which will result in HTML something like this (notice the array notation on the names):
<input name="products[0].Id" type="hidden" value="123">
<input name="products[0].Selected" type="checkbox">
Widget
<input name="products[1].Id" type="hidden" value="987">
<input name="products[1].Selected" type="checkbox">
Gadget
...and the controller method that handles the post:
public ActionResult SelectProducts(IList<ProductSelection> products)
{
...
}
Upon binding, products parameter will contain two instances of ProductSelection.
One caveat is that I have not used the new default binding for complex objects. Rather I am using either the NameValueDeserializer or CastleBind, both from MvcContrib. They both behave this way. I am guessing binding in the Beta will work the same way.
Depending on your data, you could either output a 'CheckboxList' (which is not possible in the newer versions any more) and use a string[] parameter, or you could set up multiple forms and just modify the action.