I have a 'Survey' page which is declared as follows:
#using (Html.BeginForm("Survey", "Home", new { questionList = Model.Questions }, FormMethod.Post))
{
<div class="survey">
<ol class="questions">
#foreach (Question q in Model.Questions)
{
<li class="question" id="#q.QuestionName">
#q.QuestionText<br />
#foreach (Answer a in q.Answers)
{
<input class="answer" id="#a.DisplayName" type="checkbox" /><label for="#a.DisplayName">#a.AnswerText</label>
if (a.Expandable)
{
<input type="text" id="#a.DisplayNameFreeEntry" maxlength="250" /> <span>(250 characters max)</span>
}
<br />
}
</li>
}
</ol>
</div>
<div class="buttons">
<input type="submit" value="Finish" />
</div>
}
When I'm stepping through my code, it hits the method I've set up to process their survey:
[HttpPost]
public ActionResult Survey( List<Question> questionList, FormCollection postData)
{
//Process Survey
}
However, when I step through I am finding that the variable questionList is null and the variable postData does not contain any data from the Form. Trying to access checkboxes via Request[a.Displayname also does not work.
Everything I've read indicates that this is the correct way to persist values from the Model to the submission method, and that I should be able to access the FormCollection this way.
What am I doing wrong?
You have to save questionList as a hidden field on the page. Non-primitive types do not get persisted simply by passing them in.
One way you can do that is
#Html.HiddenFor(m => m.Foo)
Or you could do it directly in HTML like this
<input type="hidden" name="Var" value="foo">
where m is your model.
The fact that the postData is empty is weird, since every input element with id inside a form tag should be passed with the POST request.
But the questionList won't be received that way, since its a list of complex class (not just a string or int), and the default ModelBinder (the thing that turns the HTTP Request Variables into parameters passed to the action method) don't support lists of complex classes.
If you want to be able to receive List you will have to implement your own binding mechanism with CustomModelBinder.
This article can help you implement it.
One problem is your checkbox and your textbox are not properly bound to your model.
You should be using #Html.CheckBoxFor and #Html.TextBoxFor
Related
I have a ToDo items dashboard page where I display the ToDo's, their status and some other app info.
I want to have one input where I can add a string value (the ToDo title) and on the button click
have that passed to the controllers Create get method, so it populates the Create views Title input field with that value.
I want to it without a form if that is possible as the dashboard page already has a model which is an IEnumerable, just pass that value as a querystring parameter to the Create pages get view (or is it doable in javascript?).
Im not an MVC expert and also not as familiar with the new tag helper methodologies. Any help in how to structure thiswould be helpful.
Here is the html
<!-- Add Task -->
<div class="input-group input-group-lg">
<input class="form-control" type="text" placeholder="Add task and press enter..">
<span class="input-group-addon">
<a asp-controller="ToDoItems" asp-action="Create" ><i class="fa fa-plus"></i></a>
</span>
</div>
<!-- END Add task -->
here is the new model
public Class MyModel{
public IEnumerable<your old model> Old Model {get; set;}
public string Title {get;set;}
}
You can create a form like so in html with razor syntax
#model MyModel
...
<form action="/Controller/PostTitle/" method="post">
#Html.TextBoxFor(m => m.Title,new {#class = "...", #placeholder="...",
#requried="required"})
<input id="export-btn" type="submit" value="Download" class="btn btn-info" />
</form>
The #TextBoxFor will create a textbox and the lambda lets you use your strongly typed model.
Here is the controller
[HttpPost]
public IActionResult PostTitle(string Title) {
...
}
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've been struggling for quite some time now with trying to maintain a list of objects when the ViewModel is submitted back to the controller. The ViewModel receives the list of objects just fine, but when the form is submitted back to the controller the list is empty. All of the non-collection properties are available in the controller, so I'm not sure what the issue is. I have already read the guide a few people have referenced from Scott Hanselman here
From what I can see, everyone solves this by building an ActionResult and letting the model binder map the collection to a parameter:
Controller:
[HttpPost]
public ActionResult Submit(List<ConfigurationVariable> variables)
{
}
View:
#for (int i = 0; i < Model.ConfigurationVariables.Count; i++)
{
<div class="row">
<div class="col-xs-4">
<label name="#Model.ConfigurationVariables[i].Name" value="#Model.ConfigurationVariables[i].Name" />
</div>
</div>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control" name="#Model.ConfigurationVariables[i].Value" value="#Model.ConfigurationVariables[i].Value" />
</div>
</div>
}
What I really want is to be able to pass my ViewModel back to the controller, including the ConfigurationVariables List:
Controller:
[HttpPost]
public ActionResult Submit(ReportViewModel report) //report.ConfigurationVariables is empty
{
}
View:
#for (int i = 0; i < Model.ConfigurationVariables.Count; i++)
{
<div class="row">
<div class="col-xs-4">
#Html.LabelFor(model => model.ConfigurationVariables[i].Name, new { #class = "form-control" })
</div>
</div>
<div class="row">
<div class="col-xs-4">
#Html.TextBoxFor(model => model.ConfigurationVariables[i].Value, new { #class = "form-control" })
</div>
</div>
}
This will be a complicated form and I can't just put every collection into the ActionResult parameters. Any help would be greatly appreciated
You need to hold the Name property in a hidden input so that it's submitted. Label values are lost.
#Html.HiddenFor(model => model.ConfigurationVariables[i].Name)
Alright, based on your comment you won't be able to utilize mvc's form binding. No worries.
Instead of this controller definition:
public ActionResult Submit(List<ConfigurationVariable> variables)
Use one of these two:
public ActionResult Submit()
public ActionResult Submit(FormCollection submittedForm)
In the first you can access the Request object, you'll need to debug and locate your variable, then you'll need some logic to parse it apart and used the values submitted.
In the second, the form collection will be made up of all the INPUT elements in your form. You will be able to parse through them directly on the object without interference from the other attributes of the Request object.
In both cases you will probably need to use #Html.TextBox, and not TextBoxFor, and you will need to dynamically populate your dropdowns in your view.
I'm not 100% sure about the Request object, but for sure on the FormCollection you will need to create an Input element for each value/collection you want submitted. Including hidden inputs for your textboxes
Your textboxes will need to be SelectListItem collections. those require a key and a value, and when they are submitted you can loop through the collection and check the .Selected attribute.
I would try with FormCollection first, and if that doesn't work fall back to the Request object.
Also note: you are not getting a viewmodel back from the form submission, you will need to rebuild it from the form elements. If you want to post prepopulated data to the view you will need to build a view model and do appropriate parsing on the view to display it.
I'm trying to post a model back to the controller but for some reason the controller always gets NULL back. I know I'm doing something really obviously wrong. What is it?
However if I post back a specific attribute from that model, it works just fine.
Controller:
[HttpPost]
public void MyAction(Company company)
{
System.Diagnostics.Debug.WriteLine("STUFF:" + company.dbName);
if(company.CompanyOptions!=null)foreach (var item in company.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList) System.Diagnostics.Debug.WriteLine("STUFF:" + item);
else System.Diagnostics.Debug.WriteLine("STUFF IS NULL");
}
View:
#model Domain.Entities.Company
#using (Html.BeginForm("MyAction", "Controller", FormMethod.Post))
{
foreach (var licensedFeature in Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList)
{
#Html.CheckBox(licensedFeature.LicenseName, licensedFeature.IsLicensed, checkboxHtmlAttributes);
#licensedFeature.LicenseName
}
<input type="hidden" name="company" value="#Model"/>
<input id="submit_licenses" type="submit" style="display:none;" />
}
#Model appears to be a complex type so you cannot assign to as the value of the input field.
The best you can do is use an #Html.EditorFor to generate the required html fields for the model and this will ensure that they are posted back as the Company object.
Replace this
<input type="hidden" name="company" value="#Model"/>
with
#Html.EditorFor(model => model)
I'm using MVC with Razor and C#. I would like to update an element... a counter with ajax. Here is my code:
#model Domain.CounterObject
#using (Ajax.BeginForm("Count", "CounterObject", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "my-control" }))
{
<div id="my-control" class="bid-object">
<div>
<span class="title">#Html.Encode(Model.Title)</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetFinalDate())</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetValue())</span>
</div>
<div>
<input type="submit" value="Count" />
</div>
</div>
}
In my controller I have this code:
[HttpPost]
public PartialViewResult Count(CounterObject counter)
{
// Special work here
return PartialView(counter);
}
The problem is that my CounterObject counter I receive in my Count method is always null. How can I pass a value from my page to the controller?
I receive in my Count method is always null
First of all you are not submitting anything from the form then how does the binding happens?
If the user is not allowed to edit the values but still you want to submit them through the form then you have to use hidden fields along with them.
For ex.
<div>
<span class="title">#Html.Encode(Model.Title)</span>
#Html.HiddenFor(m => m.Title)
</div>
Note that the hidden fields should have the same names as the properties to make the binding happen successfully.
It is better to have properties in the Model that store the GetFinalDate() and GetValue() results so you can easily bind the things like in Title.
You'll have to define a input field with a name and id that the ModelBinder can then Bind to your CounterObject.
You could use #Html.EditorForModel once and then inspect the generated Html to see what kind of name/id pairs it is generating. With those you can go on and handcraft your Html if you wanted to.
use
<span class="title">#Html.Encode(Model.Title)</span>
<div class="editor-field">#Html.EditorFor(Model => Model.Title)<div>
//For other fields
In this way you can bind to your object.