I have a view-model "MyClass" that contains a dictionary:
Dictionary<string, bool> columns {get; set;}
and it has keys and values
columns.Add("Name", true);
columns.Add("Type", true);
now, I want to let the user edit MyClass and its dictionary.
For every key I want to show its key and to enable to check\unchek its value (true\false), such that the input's name will be the right name for editing. since the dictionary has many keys, I need to to it with "foreach" or "for".
How can I do that?
You can start from http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-1
You need to write something like this in your View
#using (Html.BeginForm()) {
<fieldset>
<legend>MyClassViewModel</legend>
#foreach (var item in Model.Columns){
#Html.Label(item.Key)
#Html.CheckBox(item.Key, item.Value)
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
and your view must be bind to model in that case
#model MvcDemoApp.Models.MyClassViewModel
or as an alternative
#foreach (var item in Model.Columns)
{
#item.Key
<input type="checkbox" id="#item.Key" checked="#item.Value" />
<input type="hidden" value="#item.Value" />
<br />
}
or try using CheckBoxList custom helper by community
http://weblogs.asp.net/gunnarpeipman/archive/2011/05/05/asp-net-mvc-implementing-checkboxlist.aspx
http://www.codeproject.com/Articles/292050/MVC3-Html-CheckBoxList-custom-extension
In your case you want something like this, for the default binder to understand the name="" format:
<input type="checkbox" name="columns[0].Value" value="Key0 string value" />
<input type="checkbox" name="columns[1].Value" value="Key1 string value" />
Unfortunately the default helpers don't fully support this so you've to write the name="" explicitly. Something like:
#Html.CheckBox("columns[" + i + "].Value", new { value = columns[i].Key });
Read more about these kind of bindings on this blog post.
Related
Here am pressing the pay button i have to pass ids and the form data
in my view am displaying some data using for each loop,and when i click a button i have to pass the number of ids which returns in model class and some form data(which is outside the model class) to the controller,i have tried my maximum,But i failed,please help me to make this?
view.cshtml
#foreach (var item in Model) {
<input type="hidden" value="#item.vid" name="abc" />//i need these ids in my controller
<tr>
<td>
<td> #Html.DisplayFor(modelItem => item.vid)</td>
.........
...........//some more displaying
}
#Html.BeginForm("makepayment","home",FormMethod.Post)
{
<h3>Card Holder Name</h3>
<input type="text" name="cname" />
<h3>Account Name</h3>
<input type="text" name="number" />
<h3>CVC</h3>
<input type="text" name="securitycode" />
<h3>Expiery Date</h3>
<input type="text" name="expdate" />
<input type="submit" id="sub" name="sub" value="pay" />
}
controller
public ActionResult makepayment(FormCollection values,????)
{
......
.......//codes
}
i know i may have to use array or something,but i dont know how,somebody please help
Now, following semantics, you should create a separate viewmodel class that can hold such information, but that is not always the case.
So here is my understanding. You have a model class which you are what your form consists of, but you also want to send the ids that are just related to something else. In you post action, you get an instance of your model class with model binding.
//Please ignore the [] chars
public ActionResult makepayment([Name of you model class] modelInstance)
{
//modelInstance will contain the fields of the model.
//The remaining field, you can access using.
//Request.Form["{name of the input field}"]
var id = Request.Form["abc"]
}
Hope this helps you out. Otherwise, hit me with up and we can easily go through it in more detail.
P.S :- I am not a sir.
I have a model with say 10 properties. A, B, C and so on...
Property A is an array.
For each value in array I generate one tag like this:
<div class="col-sm-10 row">
#foreach (var item in Model.A)
{
<div class="col-sm-1 right-buffer">
<i class="" aria-hidden="true">#item.Text</i>
</div>
}
</div>
When user clicks on some link I should redirect it to the same page, but with Some model property changed. For example:
Current url: my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=
with model ?name=Alex&age=20&from=fr&CurrentA=
If user clicks on <a> with text foo it should be redirected on my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=foo
then is clicks on <a> with text bar and it should be now redirected on my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=bar
So entire query string (except one parameter) should be preserved to send current model state to server while I want to set one value and redirect it to the same page but with new value.
Eventually, it should acts like postback with one extra value setted to model
Is it possible or I should use JS and perform everything myself?
Manually i solved it like this:
First, create hidden fields for every property in model:
<form asp-controller="search" asp-action="index" method="get" role="form" id="searchForm" asp-antiforgery="false">
<input asp-for="SessionId" type="hidden" name="sessionId" value="#Model.SessionId" />
<input asp-for="Quantity" type="hidden" name="quantity" value="#Model.Quantity"/>
<input asp-for="SortField" type="hidden" name="sortField" value="#Model.SortField"/>
<input asp-for="IsAscending" type="hidden" name="IsAscending" value="#Model.IsAscending" />
<input asp-for="Offset" type="hidden" name="offset" value="0" />
...
</form>
Then, use JS to replace value in hidden field and then submit form. Values from inputs will be autimatically converter in query string, so everything works fine:
function sortDocuments(sortField) {
var sField = document.getElementById('SortField');
var isDescending = document.getElementById('IsAscending');
if (sField.value === sortField) {
if (isDescending.value.toUpperCase() === 'FALSE') {
isDescending.value = 'TRUE';
} else {
sField.value = 'rank';
isDescending.value = 'FALSE';
}
} else {
sField.value = sortField;
isDescending.value = 'FALSE';
}
document.getElementById('searchForm').submit();
}
Not very elegant, but it does its job.
I'm having following view page,
#using (Html.BeginForm())
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1"><b>Associate Id : </b>#item.Var_AssoId </label>
<label class="Detail1"><b>Vertical :</b>#item.Var_Vertical</label>
<label class="Detail1"><b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom </label><br /><br />
<label class="Detail2"><b>Associate Name :</b>#item.Var_AssociateName</label>
<label class="Detail2"><b>Account Name :</b>#item.Var_AccountName</label>
<label class="Detail2"><b>Visa ValidDate :</b>#item.Dt_VisaValidTill</label><br /><br />
<label class="Detail3"><b>Grade HR :</b>#item.Var_Grade</label>
<label class="Detail3"><b>Project Name :</b>#item.Var_Project_Desc</label><br />
}
<h2> Response Details</h2><br />
Supervisor Response :<input type="radio" class="radi"
name="radio" value="yes" onclick="javascript:Getfunc(this.value);">Yes
<input type="radio"
name="radio" value="no"
onclick="javascript:Getfunc(this.value)">No
<div id="es"></div>
<input type="submit" id="insert" value="Submit"
name="Submit" onclick="javascript:InsertDetails(item);"/>
</fieldset>
}
I want pass all the values of this view page to the controller as parameters for inserting these values into the new table.How can i Achieve this?
Use #Html helpers for your controls.
Have a look at this blog entry from Scott Gu. It's about MVC2 but still applies to MVC4.
For a more concrete example, have a look at this question regarding #Html.RadioButtonFor().
Also, I would recommend hooking your events using jquery instead of inline onclick= html attributes.
<script type="text/javascript">
$("form radio").click(function(){ // or whatever selector you need
Getfunc($(this)[0].value);
});
</script>
Finaly, you will need to make sure your #Html.BeginForm posts to an [HttpPost]-decorated action on your controller that takes your Model as parameter.
What is the Problem in Existing code ?
There is no Input Type Text Control in the form and that's the reason information is not being sent to server. TextBox like controls forwards the data for sending the information to Controller Action Method.
Corrective Action
Let's say TextBox is not Required in you case. Then, you can place Hidden Fields for those View Model Properties which are required to be sent to Controller Post Action method.
Example
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1">
<b>Associate Id : </b>#item.Var_AssoId
</label>
#Html.HiddenFor(i=> item.Var_AssoId) //Added Hidden Field to send this to server
<label class="Detail1">
<b>Vertical :</b>#item.Var_Vertical</label>
#Html.HiddenFor(i => item.Var_Vertical) //When post this Hidden Field will send
<label class="Detail1">
<b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom
</label>
#Html.HiddenFor(i => item.Dt_VisaValidFrom)
<br />
}
<h2>
Response Details</h2>
<br />
</fieldset>
}
For explaining point of view, I excluded some of the controls. Now, You can add Hidden Fields for those Properties which are required to be sent to Action Method.
Also you should use View Models instead of Passing Individual parameter to Action Method.
Hope this will help you.
Hi try like this,
View
#using (Html.BeginForm("SaveAudit", "Controller", FormMethod.Post)
{
}
Controller
[HttpPost]
public ActionResult SaveAudit(AuditModel model, FormCollection collection)
{
}
I try to bind an OrderedDictionary to a view but when the post method gets invoked the Dictionary is always empty.
Here is my code:
[HttpGet]
public ViewResult Edit(string username, string password)
{
Xml test = new Xml(#"c:\Users\pc\Desktop\xml - Copy.xml");
XmlNode userNode = test.GetUserNodeByUsernameAndPassword(username, password);
User user = new User();
user.BindData(userNode);
return View(user.user);
}
[HttpPost]
public ViewResult Edit(OrderedDictionary attributes)
{
return View(attributes);
}
And here is the view:
#using (Html.BeginForm("Edit", "Users")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<p>
<input type="submit" value="Save" />
</p>
#{int counter = 0;}
#{string name = "";}
#foreach (DictionaryEntry attribute in Model)
{
{ name = "[" + counter + "].key"; }
<input type="hidden" name=#name value=#attribute.Key />
#attribute.Key #Html.TextBoxFor(m => attribute.Value)
counter++;
<br />
}
</fieldset>
}
And the result Html looks like this is:
<input type="hidden" value="Username" name="[0].key">
Username
<input id="attribute_Value" type="text" value="Anamana" name="attribute.Value">
So the content of the OrderedDictionary appears fine in the view but when I make a post back the binding isn't working and the directory remains empty.
Concept
To bind a dictionary you have to change the name attribute in the html input tag. Something like this:
In your controller:
[HttpPost]
public ActionResult Edit(IDictionary<string, string> attributes)
{
}
In your HTML:
<input type="text" name="attributes[0].Key" value="A Key" />
<input type="text" name="attributes[0].Value" value="A Value" />
<input type="text" name="attributes[1].Key" value="B Key" />
<input type="text" name="attributes[1].Value" value="B Value" />
The attributes name should be before the index [0] on ther name attribute, because your action expect it.
Tips
I would use the HiddenFor and TextBoxFor HTML Helper of the Asp.Net MVC.
#Html.HiddenFor(model => model[i].Key)
#Html.TextBoxFor(model => model[i].Value)
And it will render in the format that the asp.net mvc will understand and get it working.
For more samples about databind take a look at this link.
Meantime I have found the solution.
I can pass an OrderedDictionary to the view page.
It process it by the following Razor code:
#model System.Collections.Specialized.OrderedDictionary
(...)
#{int counter = 0;}
#{string name = "";}
#foreach (DictionaryEntry attribute in Model)
{
{ name = "[" + counter + "].key"; }
#Html.Hidden(name, attribute.Key)
{name = "[" + counter + "].value";}
#attribute.Key #Html.TextBox(name, attribute.Value)
counter++;
<br />
}
The result HTML's structure fits to the samples which is found in a book, the values from the dictionary appears fine on the page.
After POST was invoked the POST handler function gets the modified values in a Dictionary.
[HttpPost]
public ViewResult Edit(Dictionary<string, string> attributes)
{}
I don't know why but I can't use OrderedDictionary here.
Currently I am attempting to create a mass update based on a series of checkboxes. I can't seem to find the correct way to do it using the entity framework.
I am using ASP.Net 4 with MVC3 and Razor.
Here is the code I have so far.
View Page (Working Properly)
#model List<LeagueCounters.Models.champion>
<form name="setFree id="setFree" method="POST" action="/Champion/SetFree">
#foreach (var item in Model)
{
if (item.isFree == true)
{
<input type="checkbox" id="#item.id" checked="checked" /> #Html.DisplayFor(modelItem => item.displayName)
}
else
{
<input type="checkbox" id="#item.id" /> #Html.DisplayFor(modelItem => item.displayName)
}
}
<p><input type="submit" value="Save" /></p>
Controller (Errors)
[HttpPost, Authorize(Roles = "Admin")]
public ActionResult SetFree(FormCollection fcMain)
{
var sortedList = from c in _db.champions
orderby c.name
select c;
int counter = 0;
foreach (champion champ in sortedList)
{
if (fcMain[counter].Contains("true"))
champ.isFree = true;
else
champ.isFree = false;
_db.champions.Attach(champ);
_db.ObjectStateManager.ChangeObjectState(champ, EntityState.Modified);
counter++;
}
_db.SaveChanges();
return View();
}
Errors
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Question
How do I properly cycle through the checkboxes in the controller? And will my mass update code work once I get to that point?
Thanks in Advance.
The problem here is that only the checked checkboxes are posted to the server. So you can't expect all of your checkbox keys to be present in the form collection. To workaround this behavior Html.CheckBoxFor creates an additional hidden field with checkbox so the result could be read on the server side. I am not sure how would you use strongly typed helper here because you are rendering data in a loop. I think you can have a look at this google search
i think this line
fcMain[counter].Contains("true")
is causing the errors..are you using some kind of constraint selection(Where) when providing the model to the View
also you should add a hidden field after every checkbox by doing
<input type="hidden" value="false" id="#item.id" name="#item.id"/>
this way all the checkboxes will be submitted successfully
and you will have to split the values and take the first value thats present on the server side.
or you can skip both and directly use #Html.Checkbox(item.Id,item.isFree) this way the code will be cleaner and no need to manually add additional Hidden Input will be added automatically by the Razor engine
there are also some other improvements you can do to keep code DRY.
change this
if (item.isFree == true)
{
<input type="checkbox" id="#item.id" checked="checked" /> #Html.DisplayFor(modelItem => item.displayName)
}
else
{
<input type="checkbox" id="#item.id" /> #Html.DisplayFor(modelItem => item.displayName)
}
to
<input type="checkbox" id="#item.id" name="#item.id" #(!Item.isFree?"checked=\"checked\":\"\"") /> #Html.DisplayFor(modelItem => item.displayName)
and i dont think you need these
_db.champions.Attach(champ);
_db.ObjectStateManager.ChangeObjectState(champ, EntityState.Modified);