This question already has answers here:
The model item passed into the dictionary is of type .. but this dictionary requires a model item of type
(7 answers)
Closed 4 years ago.
I have a composite ViewModel as below:
public class HomeListViewModel
{
public HomeSearchRequestViewModel SearchRequest { get; set; }
public List<BasicAdSummaryViewModel> AdSummayResults { get; set; }
}
In my View, I want to render 2 PartialViews as below:
#model MyNameSpace.HomeListViewModel
<div>
#Html.Partial("_SearchRequest", Model.SearchRequest)
#Html.Partial("_AdSummary", Model.AdSummayResults)
</div>
This is my _SearchRequest PartialView
#model MyNameSpace.HomeSearchRequestViewModel
<div>
#Html.EditorFor(m => m.Keyword, new { htmlAttributes = new { #class = "form-control", #type = "text"} })
</div>
And this is my _AdSummary PartialView:
#model IEnumerable<MyNameSpace.BasicAdSummaryViewModel>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
</tr>
The first PartialView renders fine, But I get the this error on second PartialView:
System.InvalidOperationException: 'The model item passed into the
dictionary is of type
'MyNameSpace.HomeListViewModel', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[MyNameSpace.BasicAdSummaryViewModel]'.'
I only get this error while rendering a partial view with a List view model...
This error message happens when calling
#Html.Partial("_AdSummary", null)
MVC seems to get confused by null view-models; it cannot tell what null's type is, so assumes the type is the same as the current view-model.
The solution is to make sure that Model.AdSummayResults is never null.
Related
This question already has answers here:
Submit a List from View to Controller
(2 answers)
Closed 5 years ago.
View has a list of items, each with a checkbox. Purpose of the form is to check the boxes then return the list to the db. I expect to see the PickList model in the ViewModel populated with the hidden seedid and the checkbox values, but the form always submits with the PickList as null.
#model Inventory.ViewModels.ExtractionViewModel
<div class="col-md-4">
<button class="btn btn-primary" type="submit" form="pick-list-form">Update Pick List</button>
</div>
#using (Html.BeginForm("UpdatePickList", "Extraction", FormMethod.Post, new { #id = "pick-list-form" }))
{
<table class="table">
<tr>
<th>
Seed Reference
</th>
<th>Extracted?</th>
</tr>
#foreach (var item in Model.PickList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.ExtractionId)
#Html.HiddenFor(modelItem => item.SeedId)
#Html.DisplayFor(modelItem => item.SeedId)
</td>
<td>
#Html.CheckBoxFor(modelItem => item.IsExtracted)
</td>
</tr>
}
</table>
}
View Model
public class ExtractionViewModel
{
public ExtractionDTO Extraction{ get; set; }
public List<PickListDTO> PickList { get; set; }
}
Pick list model
public class PickListDTO
{
public int ExtractionId { get; set; }
public int SeedId { get; set; }
public bool IsExtracted { get; set; }
}
Using #Html.DisplayFormay cause the model to be sent back as NULL. You can use #Html.TextBoxFor.
And just to remind:
Use HiddenFor when you want to provide posted data that the user does not need to be aware of.
Use DisplayFor when you want to show records but not allow them to be editted.
Use TextBoxFor when you want to allow user input or allow the user to edit a field.
I hope it helps you!
This question already has an answer here:
Html.DisplayFor not posting values to controller in ASP.NET MVC 3
(1 answer)
Closed 5 years ago.
View shows proper value (OrderId = 3):
// GET:
public ActionResult ConfirmOrder()
{
//simplified code here
var model = new ConfirmOrderViewModel()
{
OrderId = 3,
};
return View(model);
}
View works fine one way (value visible on the screen) Html-part below:
#model Test.Models.Views.ConfirmOrderViewModel
#{
ViewBag.Title = "My title";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm("ConfirmOrder", "Client", FormMethod.Post, new {
#class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<div class="row" style="padding:10px; margin:15px">
<div>
<div class="col-sm-3">
#Html.DisplayFor(m => m.OrderId)
</div>
</div>
</div>
}
ConfirmOrderViewModel class looks like this:
public class ConfirmOrderViewModel
{
public int OrderId { get; set; }
}
4. But when it comes to post it back, only null I'm having:
// POST:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ConfirmOrder(ConfirmOrderViewModel ViewModel)
{
//at this moment: ViewModel.OrderId = null
return RedirectToAction("Index");
}
Controller Name is ok, Methods works... no errors. Just null after clicking the OK button on page. What can cause bad model binding here?
The DisplayFor helper method will just render the value of the OrderId property. As the name suggests, It is more for displaying to the user. If you want the value for OrderId to be posted to the http post action method, you need to keep that in in a form field inside the form.
You can keep in a hidden field inside the form
#using (Html.BeginForm("ConfirmOrder", "Client"))
{
#Html.DisplayFor(m => m.OrderId)
#Html.HiddenFor(a=>a.OrderId)
<input type="submit" value="Confirm" />
}
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
After post I am getting List in model is null
my model is has a property which is the list of vwLog.
public class CreateLogViewModel
{
public List<vwLog> LogData;
}
In view I used that model and used foreach loop to assign the value in text control
#model CreateLogViewModel
#using (Html.BeginForm("CreateLog", "Log", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
foreach (var item in Model.LogData)
{
<table>
<tr>
<td>
#Html.HiddenFor(modelItem => item.LogID)
#Html.TextBoxFor(modelItem => item.AgencyBillingCode)
</td>
<td>
#Html.TextBoxFor(modelItem => item.LicenseNumber)
</td>
</tr>
</table>
}
<div class="col-xs-12" align="center">
<input class="btn btn-default" type="submit" name="Submit" value="Save" id="Submit">
</div>
}
My Controller is
In Get method I am assigning the value in LogData object which is the collection of vwlog.
public ActionResult CreateLog(CreateLogViewModel model)
{
model.LogData = GetDate();
return View(model);
}
I update some value of the list on the screen and try to save that, but I am getting model.LogData null in Post.
[HttpPost]
public ActionResult CreateLog(CreateLogViewModel model, string submit)
{
if (model.LogData != null)
{
do this...
}
}
I update some value of the list on the screen and try to save that, but I am getting model.LogData null in Post. model is not null, but the collection object is null.
Please let me know where I am wrong.
The MVC model binder doesn't work with class fields:
public class CreateLogViewModel
{
// This is a field
public List<vwLog> LogData;
}
you must use properties:
public class CreateLogViewModel
{
// This is a property
public List<vwLog> LogData { get; set; }
}
NOTE: You also need to make sure your vwLog type has public read-write properties for it to work.
I have a textarea that represents a description field. The descriptions have commas so when trying to split the field's descriptions the data is not parsed correctly. How can I get each row's description correctly.
var DescList = FormValues["Item.Description"].Split(',').Select(item => item).ToList<string>();
//will not work for obvious reasons. Comma delimited FormCollection has commas to identify separate row data.
It seems like Microsoft designed the FormsCollection without the textarea control in mind. A text area with commas will not work when trying to access each value. What is interesting is that the _entriestables property has it in the perfect format but they chose to make it a private property. Very frustrating.
`
Here is the important part of my viewmodel.
public class TenantViewModel
{
public Tenant Tenant { get; set; }
public Site Site { get; set; }
}
My view is populated like this:
if (Model != null && Model.Tenant != null && Model.Tenant.Site != null && Model.Tenant.Site.Count() > 0)
{<div class="detailsbox_view">
<table id="tblTenantSites">
<tr>
<th>#Html.LabelFor(item => item.Site.Title)</th>
<th>#Html.LabelFor(item => item.Site.Description)</th>
</tr>
#foreach (var Item in Model.Tenant.Sites)
{
<tr>
#Html.HiddenFor(modelItem => Item.SiteId)
<td>
#Html.EditorFor(modelItem => Item.Title)
</td>
<td>
#Html.TextAreaFor(modelItem => Item.Description, new {#width="400" })
</td>
</tr> }
</table>
As you see this site table is a child of Tenant object. This child record does not get automatically updated using this method but the Tenant data does automatically get updated. This is the reason I tried the FormColelction instead.
Is there something I am missing to make this work?
try with this useful function
ValueProviderResult Match=FormCollection.GetValue("ValueProvider");
When you have multiple fields with the same name attribute, they'll come back into your FormCollection as an array. So upon posting a view like this:
<form action="/Home/MyAction">
<textarea id="row_one_description" name="description">
First row's description
</textarea>
<textarea id="row_two_description" name="description">
Second row's description
</textarea>
<input type="submit" value="Submit" />
</form>
you could do something like this in your action
[HttpPost]
public ActionResult MyAction(FormCollection collection)
{
var descriptionArray = collection["description"];
string firstRowDescription = descriptionArray[0];
string secondRowDescription = descriptionArray[1];
}
I must note that this is not the recommended way of dealing with posted data. You should instead be building your view using data from a view model and using strongly typed html helpers to render your controls. That way when you post, your action can take the ViewModel as a parameter. Its properties will be automatically bound and you will have a nice object to play with.
[HttpPost]
public ActionResult MyAction(MyViewModel viewModel)
{
foreach (var row in viewModel.Rows)
{
string description = row.Description;
}
}
EDIT
I'm still assuming a lot about your ViewModel but perhaps try this:
<table id="tblTenantSites">
<tr>
<th>#Html.LabelFor(model => model.Site.Title)</th>
<th>#Html.LabelFor(model => model.Site.Description)</th>
</tr>
#for (var i = i < Model.Tenants.Sites.Count(); i++) {
<tr>
#Html.HiddenFor(model => model.Tenants.Sites[i].SiteId)
<td>
#Html.EditorFor(model => model.Tenants.Sites[i].Title)
</td>
<td>
#Html.TextAreaFor(model => model.Tenants.Sites[i].Description, new { #width="400" } )
</td>
</tr>
}
</table>
You could also try ,
string Match=FormCollection.GetValue("ValueProvider").AttemptedValue;
I noticed what seems to me a bug in asp.net MVC or simply I am doing something wrong. I am currently using 1.0 so maybe this is something that will be addressed in the 2.0 release. But either way, here we go.
When I my view model has a property which is the same name as the declared id for a drop down list, the selected item is ignored and the rendered html has nothing selected.
Not sure if I did something wrong, but changing the name of the id fixes the problem. I simplified the example, hope it is clear, otherwise please let me know.
Here is my view where the declared ID is the same name as my list in the model:
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<%= Html.DropDownList("IsMultipleServicers", Model.IsMultipleServicers) %>
</td>
</tr>
</table>
And the rendered Html
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<select id="IsMultipleServicers" name="IsMultipleServicers">
<option value="false">No</option>
<option value="true">Yes</option>
</select>
</td>
</tr>
</table>
Now lets make a small change. I will change the declared id to be something different.
Here is my View:
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<%= Html.DropDownList("MultipleServicers", Model.IsMultipleServicers) %>
</td>
</tr>
</table>
And now the rendered html:
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<select id="IsMultipleServicers" name="IsMultipleServicers">
<option value="false">No</option>
<option selected="selected" value="true">Yes</option>
</select>
</td>
</tr>
</table>
Notice that now I get a selected option which would be the second element in the List.
Here is my ViewModel just to tie everything together:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCProject.Models.ViewModels.Service
{
public class ServiceViewModel : ViewModel
{
public List<SelectListItem> IsMultipleServicers { get; set; }
}
}
Here is my action:
[AcceptVerbs(HttpVerbs.Get)]
public virtual ActionResult Service()
{
return View(new ServiceViewModel()
{
IsMultipleServicers = BuildBooleanSelectList(true)
};
}
private List<SelectListItem> BuildBooleanSelectList(bool isTrue)
{
List<SelectListItem> list = new List<SelectListItem>();
if (isTrue)
{
list.Add(new SelectListItem() { Selected = false, Text = "No", Value = "false" });
list.Add(new SelectListItem() { Selected = true, Text = "Yes", Value = "true" });
}
else
{
list.Add(new SelectListItem() { Selected = true, Text = "No", Value = "false" });
list.Add(new SelectListItem() { Selected = false, Text = "Yes", Value = "true" });
}
return list;
}
I think the problem is a confusion regarding the DropDownList overloads:
Html.DropDownList(string name) looks for a view model property of name and type IEnumerable<SelectListItem>. It will use the selected item (SelectListItem.Selected == true) from the list, unless there is a form post value of the same name.
Html.DropDownList(string name, IEnumerable<SelectListItem> selectList) uses the items from selectList, but not their selected values. The selected is found by resolving name in the view model (or post data) and matching it against the SelectListItem.Value. Even if the value cannot be found (or is null), it still won't use the selected value from the list of SelectListItems.
Your code uses the second overload, but specifies a "value" property that doesn't exist ("MultipleServicers").
To fix your problem, either use the first overload:
<%= Html.DropDownList("IsMultipleServicers") %>
Or, add a string MultipleServicers property to your view model and populate it in your controller. I'd recommend this solution as it gets around several problems with initial display, post display and mapping the post data to a view/post model:
public class ServiceViewModel : ViewModel
{
public string MultipleServicers { get; set; }
public List<SelectListItem> IsMultipleServicers { get; set; }
}
Then for your HTML:
<%= Html.DropDownList(Model.MultipleServicers, Model.IsMultipleServicers) %>
This technique maps into MVC2, as well:
<%= Html.DropDownListFor(x => x.MultipleServicers, Model.IsMultipleServicers) %>
I encountered this same problem using the Html.DropDownList(string name, IEnumerable selectList) overload. It appears that my model has a property of the same name as the name of the drop down list. This being the case, MVC favored the property value of my Model over the Selected property of each entry in the IEnumerable.
The solution was to use a name for the dropdown list that does not match up to a property name. Another solution would be to write my own extension method that ignores model and view state and instead always honor the selected property.
The DropDownList helper pulls the default value from the model. In the first case, the value in the model corresponding to the name is a SelectList -- this doesn't match any of the items in the list, it is the list, so no value is chosen. In the second example, your model does not include a property with that name so the value from the model can't be used and it defaults to the state indicated in the SelectList itself. Typically, I will have a property on the model for the selected value -- this becomes the default -- and another property representing the potential values for the list.