Reputation: 2066
I'm trying to pass a dictionary to an action method inside an Html.Post
Html.BeginForm("ProcessStage2", "Supplier", new {bookVars = Model.BookVars} , FormMethod.Post, new { name = "frmBook" })
I can pass other properties (int, string, ...) of the model but not the Dictionary. Is there any chance to achieve that? because the dictionary has 29 pairs, which seem to be too many to split and pass them separated.
Upvotes: 3
Views: 7594
Reputation: 17064
You can do that using for example json serialization. I recommend this because it is very flexible and looks elegantly.
Your model can contain any set of objects. In your case it's:
public class MyViewModel
{
public IDictionary<string, string> BookVars { get; set; }
}
In the controller you can stub some data for our needs:
public class HomeController : Controller
{
public ActionResult Index()
{
// mock data
var model = new MyViewModel
{BookVars = new Dictionary<string, string> {{"key1", "value1"}, {"key2", "value2"}}};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// the binded model is avaliable
return View(model);
}
}
The view contains a form, and includes a custom script for ajax submission. The values can be persisted and modified in any way. You can use for example hidden fields.
@model MyViewModel
<script src="/Scripts/script.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('form').frmBookSubmit();
});
</script>
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { name = "frmBook" }))
{
<div class="books">
@foreach (var item in Model.BookVars)
{
<input type="hidden" key="@item.Key" value="@item.Value" />
}
</div>
<input type="submit" />
}
Script.js, creates a simple jquery plugin for ajax submission using json serialization of your data:
(function ($) {
$.fn.frmBookSubmit = function () {
var $this = $(this);
if ($this != null && $this != 'undefined' && $this.length > 0) {
$this.submit(function (e) {
e.preventDefault();
var myviewmodel = new Object();
myviewmodel.BookVars = $this.find(".books").booksCollect();
var data = { model: myviewmodel };
var jsonString = JSON.stringify(data);
$.ajax({
url: $this.attr("action"),
type: 'POST',
dataType: 'json',
data: jsonString,
contentType: 'application/json; charset=utf-8'
});
});
}
};
$.fn.booksCollect = function () {
var books = new Array();
$(this).find("input").each(function () {
var k = $(this).attr('key');
var v = $(this).attr('value');
var item = {
Key: k,
Value: v
};
books.push(item);
});
return books;
};
})(jQuery);
If you find it useful, you can also write your custom json binder using for example Newtonsoft.Json library.
You're done.
Upvotes: 0
Reputation: 1038720
You could use hidden fields and editor templates. Let's take an example:
Model:
public class MyViewModel
{
public IDictionary<string, string> BookVars { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// fill the dictionary with some dummy data
BookVars = Enumerable
.Range(1, 5)
.ToDictionary(x => "key" + x, x => "value" + x)
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// the model.BookVars property will be properly bound here
return View(model);
}
}
View (~/Views/Home/Index.cshtml
):
@model MyViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.BookVars)
<button type="submit">OK</button>
}
Editor template (~/Views/Home/EditorTemplates/KeyValuePair`2.cshtml):
@model KeyValuePair<string, string>
@Html.Hidden("Key", Model.Key)
@Html.Hidden("Value", Model.Value)
Notice the name of the editor template which will automatically be rendered for each element of the dictionary: KeyValuePair`2.cshtml
Sorry I cannot use SO's editor to properly format this but the name of the file should be: KeyValuePair[grave accent]2.cshtml
where [grave accent]
is the grave accent character.
Also don't forget to read about the wire format for collections and dictionaries that the default model binder expects to better understand what's happening under the covers.
Upvotes: 3
Reputation: 9255
Serialize your dictionary and pass it as a string (possibly base64 encoded).
Upvotes: 3
Reputation: 1092
No,You can't pass object as parameter. Only way is store object in database and pass in POST only id for that object. You should create model containing that Dictionary:
public int id {get;set;}
public Dictionary<string, int> Dictionary {get;set};
and load it by id from server side.
Upvotes: 2