storing an array of strings in a HiddenField asp.net
Asked Answered
K

4

18

I need to store an array of string in a HiddenField in my webform with asp.net. Can anybody please tell me how I can achieve that? Thanks

Kinglet answered 13/12, 2012 at 23:42 Comment(0)
C
18

Probably a few methods would work.

1) Serialize the String[] in JSON

This would be fairly easy in .NET using the JavaScriptSerializer class, and avoid issues with delimiter characters. Something like:

String[] myValues = new String[] { "Red", "Blue", "Green" };
string json = new JavaScriptSerializer().Serialize(myValues);

2) Come up with a delimiter that never appears in the strings

Delimit each string with a character such as ||| that will never appear in the string. You can use String.Join() to build this string. Something like:

String[] myValues = new String[] { "Red", "Blue", "Green" };
string str = String.Join("|||", myValues);

And then rebuild it like:

myValues = str.Split(new string[] { "|||" }, StringSplitOptions.RemoveEmptyEntries);

This might be the best option if you can trust your input, such as a series of numbers of pre-defined choices. Otherwise, you'd probably want to check your input strings to make sure they don't contain this delimiter if you wanted to be very safe. You could potentially use HttpUtility.HtmlEncode() to escape each string first.

Crosstree answered 13/12, 2012 at 23:48 Comment(2)
Since the HiddenField can only hold string data which is the different type from Array. To store the Array, we need to Serialize the Array to string. Which way to serialize the Array, it depends on the scenario.Burden
I think the answer would be better if you show how the value is stored in the hidden field. Also, as me, I think everyone looking to this answer would like to see the opposite way too: new JavaScriptSerializer().Deserialize<List<string>>(str). Anyways, thank you :) ... JavaScriptSerializer solved my problem +1Gangling
S
10

To store the array

string[] myarray = new string[] {"1","2"};

myHiddenField.Value = String.Join(",", myarray);

To get the array

string[] myarray = myHiddenField.Value.Split(',');
Stunsail answered 13/12, 2012 at 23:48 Comment(2)
This is of course problematic if an element in myarray actually contains a comma.Crosstree
That's true. Faced that issue before. Had to change to another character that would not appear in the string which is not also guaranteedStunsail
S
8

Do you actually want to store it in a single field?

If you put each value in it's own hidden field, and give all the hidden fields the name of your property then the model binding will treat this as an array.

foreach (var option in Model.LookOptions)
{
    @Html.Hidden(Html.NameFor(model => model.LookOptions).ToString(), option)
}
Selfexpression answered 25/11, 2015 at 16:3 Comment(0)
P
4

Existing Answers

I'd always rather use the default property and model binder than having to wrap an array into a CSV and having to worry about splitting it and joining it on every single round trip to the client (as in the answers by @Mike Christensen and @codingbiz). This is exactly what the model binder is there for.

@David's answer points us in the right direction, but I'd rather not inline that type of logic into your view and relegate it to an EditorTemplate instead.

Preferred Solution

So you can add the following view ~/Views/Shared/EditorTemplates/HiddenArray.cshtml

@model Array

@foreach (var value in Model)
{
    <input type="hidden" value="@value"
           name="@Html.NameFor(model => model)"
           id="@(Html.IdFor(model => model))_@value" />
}

Then call like this from your model:

@Html.EditorFor(model => model.FavoriteAnimals, "HiddenArray")

Alternative Strategies

Here's how I arrived at manually specifying the name and id variable for each hidden input:

Hidden For Array

  • A) Can't use HiddenFor() inside a loop because it thinks the property name now includes the value
  • B) When we call EditorFor, the current model is added to the Route Prefix so if we pass the current model name as a string to to Hidden() we'll actually double up and the property name won't be able to bind on the way back.
  • C) It feels odd, but we can just pass an empty string as the name and rely on the Route Prefix to do its job, but because we're inside a loop, the ID that gets produced isn't valid HTML
  • D) By grabbing the name and ID from the model and incrementing the dummy ID, we can continue to output valid HTML, even though it's probably not likely to affect anything but html linters and audits

Further Reading:

Prussiate answered 14/3, 2018 at 23:56 Comment(1)
Default model binding may work well on a very simple flat model example, but in commercial development its a different story (as usual) when your model is a composite of various models, each holding collections, and you just want to hide and post back one particular one. It this case the other solutions are easier and quicker to implement.Assimilable

© 2022 - 2024 — McMap. All rights reserved.