Receiving an attempt was made to remove a relationship between x and x however one of the relationship's foreign keys - asp.net-mvc-3

I have an MVC project and I have a case where i need to update a parent and multiple child entities at the same time. In the post action I am receiving "an attempt was made to remove a relationship between x and x however one of the relationship's foreign keys" which is strange, all I'm doing is update, I'm not droping any entity whatsoever. I am using Linq to SQL and MVC3. The pseudocode is like the following:
#model Project.Models.ParentModel
...
#using (Html.BeginForm()) {
#Html.Label("Parent property")
#Html.EditorFor(model => model.ParentProperty)
#foreach (var child in Model.Childs)
{
Html.RenderPartial("_EditChild", child)
// Which is nothing more than a label and an editor for a property like:
// #model Project.Models.ChildModel
// #Html.Label("Child property")
// #Hteml.EditorFor(model => model.ChildProperty)
}
...
}
The Action looks like:
public ActionResult Edit(int id, FormCollection collection)
{
var parent = new Parent();
TryUpdateModel(Parent()); // which updates the parent and the child properties correctly
dataContext.SubmitChanges();
}
Can anybody explaing this behavior. Once again, I'm not removing or dropping any child entities!

The binding over a list can be pretty nasty, I had some problems with it myself. I modified my list editing code to work with childs and tested it, it worked and the data is correctly bound and visible in the post action:
#model MvcApplication2.Models.Parent
#using (Html.BeginForm())
{
<table>
#{
<tr>
<td>
#Html.TextBoxFor(m => m.Text)
#Html.HiddenFor(m => m.ID)
</td>
</tr>
for (int i = 0; i < Model.Children.Count; i++)
{
<tr>
<td>
#Html.TextBoxFor(x => x.Children[i].Title)
#Html.HiddenFor(x => x.Children[i].ID)
</td>
</tr>
}
}
</table>
<div class="button">
<input class="submit" type="submit" name="btnSave" id="btnSave" value="Save" />
</div>
}
Controller for my test looks like this:
[HttpGet]
public ActionResult EditingChildren()
{
Parent parent = new Parent() { Text = "" };
parent.Children = new List<Child>();
parent.Children.Add(new Child() { Title = "" });
parent.Children.Add(new Child() { Title = "" });
parent.Children.Add(new Child() { Title = "" });
return View(parent);
}
[HttpPost]
public ActionResult EditingChildren(Parent parent)
{
// save parent with children
}
Editing my post about saving data back with linq to sql:
If you are not binding the ID on the view, it will be left empty in the object in the post method. That gives you troubles saving back the data.
I usally bind therefore the ID to an hidden field so it will not be empty any more (view code above edited and added HiddenFor beneath TextBoxFor).
Have also a look about updating data with linq to sql on this website:
http://davedewinter.com/2009/04/07/linq-to-sql-updating-entities/ (under Attach an Entity, Change Properties, Update)
and this post:
enter link description here

Related

Updating only the partial view contained in a mvc 3 page?

I have a MVC 3 page that returns a list of user responses with a partial view called "memo" (which displays/add memos) for each response. When I add a memo to a response, it should update the db and the list of memos for that response. It should be partial page update via ajax, which effects only the partial view "memo".
The view Response.chtml that contains "memo":
#using (Html.BeginForm("Response", "User", FormMethod.Post, new { id = "UserResponse" }))
{
.... code removed ....
#foreach (var response in Model)
{
<div class="qna"><input type="text" id=#response.responseId value="#response.ResponseText" />
<div>#Html.Partial("_memo", response.responseId)</div>
}
.....
The partial page "_memo.chtml":
<div>add memo</div>
<ul id="memos">
#foreach (var memo in Model) {
<li>#memo.Text</li>
}
</ul>
<form method="post" id="memoForm"
action="#Url.Action("AddMemo")">
#Html.TextArea("Memo", new { rows = 5, cols = 50 })
<br />
<input type="submit" value="Add" />
</form>
Controller for view User/Response:
[HttpGet]
public ActionResult Response(id)
{
.....
return View(responses);
I just started with the code above, need help filling the blanks.
If I pass the response Id to the partial view, how do I pull the list of memos for that response? Will it involve ajax? (instead of ..Partial("_memo", response.memos))
How do I update the partial view via ajax call. What is ajax call (sample code) on the client side and how would the controller look? When the ajax call is successful, how do I update the list memos div="memos" to reflect the new memo?
Will the form action from Response conflict with form action of the partial view Memo?
Answers to Questions:
You shouldn't pass the responseId to the partial, you should pass the memo collection from your response object and make your partial view strongly typed to that collection.
See full code example below.
You don't need the form in the partial since you're making a simple ajax call to add the new memo. See full code example below.
This is a modified example from a project I am currently working on:
There is a bit of code to follow, so here goes:
This is my model. There are several sections on a career planning form, one of which is a section to select and update competencies. The SelectCompetencies model has a collection of competencies within it. The user will have the ability to add competencies. When they do, it will be added to the database and will update the list of competencies in the partial.
public class CareerPlanningFormViewModel
{
// code removed ...
public SelectCompetenciesModel SelectCompetencies { get; set; }
// code removed ...
}
public class SelectCompetenciesModel
{
public int CareerPlanningFormID { get; set; }
public IList<CompetencyModel> Competencies { get; set; }
public byte MaximumCompetenciesAllowed { get; set; }
}
public class CompetencyModel
{
public int CompetencyID { get; set; }
public int? CompetencyOptionID { get; set; }
public string ActionPlan { get; set; }
public IDictionary<int, string> CompetencyOptions { get; set; }
}
The main view of the career planning form: /Views/CPF/CareerPlanningForm.cshtml
#model MyNamespace.Models.CareerPlanningForm.CareerPlanningFormViewModel
<link rel="stylesheet" href="#Url.Content("~/Content/CreateCPF.css")" />
#using (Html.BeginForm())
{
// other sections loaded here...
// code removed for brevity...
#Html.Partial("SelectCompetencies", Model.SelectCompetencies)
// other sections loaded here...
// code removed for brevity...
}
The SelectCompetencies partial: /Views/CPF/SelectCompetencies.cshtml
The user will fill in the new action plan text and click the add competency button.
That will post via ajax to CPFController/NewCompetencyTemplate
#model MyNamespace.Models.CareerPlanningForm.SelectCompetenciesModel
#Html.HiddenFor(m => m.CareerPlanningFormID)
<h3>Select Competencies</h3>
<p class="guidance">
Select up to #Model.MaximumCompetenciesAllowed competencies to focus on improving.
</p>
<table id="CompetenciesTable">
<thead>
<tr>
<th>Competency</th>
<th>Action Plan:</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Competencies.Count(); i++)
{
#Html.EditorFor(m => m.Competencies[i])
}
</tbody>
<tfoot id="CompetenciesTableFooter" class="#(Model.Competencies.Count() < Model.MaximumCompetenciesAllowed ? "" : "hidden")">
<tr>
<td colspan="2">
#Html.TextArea("NewActionPlanText")
#Html.Button(ButtonType.Button, "Add Another Competency", "add", new { id = "AddCompetencyButton" })
</td>
</tr>
</tfoot>
</table>
#section script
{
<script>
jQuery(document).ready(function ($) {
var competenciesTableBody = $('#CompetenciesTable tbody'),
competenciesTableFooter = $('#CompetenciesTableFooter'),
addCompetencyButton = $('#AddCompetencyButton'),
newCompetencyTemplateUrl = '#Url.Content("~/CPF/NewCompetencyTemplate")',
count = competenciesTableBody.find('tr').length,
newActionPlanText = $('#NewActionPlanText'),
careerPlanningFormID = $('#CareerPlanningFormID');
addCompetencyButton.click(function () {
$.ajax({
url: newCompetencyTemplateUrl(),
type: 'POST',
data: {
careerPlanningFormID: careerPlanningFormID,
actionPlan: newActionPlanText,
itemCount: count
},
dataType: 'html',
success: function (data) {
var elements = $(data);
// other code removed here...
competenciesTableBody.append(elements);
// other code removed here...
}
});
});
});
</script>
}
Views/CPF/EditorTemplates/CompetencyModel.cshtml
#model MyNamespace.Models.CareerPlanningForm.CompetencyModel
<tr class="competency">
<td>
#Html.DropDownListFor(m => m.CompetencyOptionID, new SelectList(Model.CompetencyOptions, "Key", "Value"), "Select competency...")
</td>
<td>
#Html.TextAreaFor(m => m.ActionPlan, new { #class = "competencyActionPlan" })
#Html.HiddenFor(m => m.CompetencyID)
</td>
</tr>
The controller containing the action to add the new competency: /Controllers/CPFController.cs
This will call the CareerPlanningFormService to add the new competency and will return a partial view for NewCompetencyTemplate that will render out the new competency
public class CPFController : Controller
{
private readonly ICareerPlanningFormService careerPlanningFormService;
public CPFController(ICareerPlanningFormService careerPlanningFormService)
{
this.careerPlanningFormService = careerPlanningFormService;
}
[HttpPost]
public PartialViewResult NewCompetencyTemplate(int careerPlanningFormID, int itemCount, string newActionPlanText)
{
var count = itemCount + 1;
// Even though we're only rendering a single item template, we use a list
// to trick MVC into generating fields with correctly indexed name attributes
// i.e. Competencies[1].ActionPlan
var model = new SelectCompetenciesModel
{
Competencies = Enumerable.Repeat<CompetencyModel>(null, count).ToList()
};
model.Competencies[count - 1] = this.careerPlanningFormService.BuildNewCompetencyModel(careerPlanningFormID, newActionPlanText);
return this.PartialView(model);
}
}
My service class: CareerPlanningFormService.cs
This handles the business logic and makes the calls to the repository to add the item to the database and returns a new CompetencyModel
public class CareerPlanningFormService : ICareerPlanningFormService
{
private readonly IMyRenamedRepository repository;
private readonly IPrincipal currentUser;
public CareerPlanningFormService(
IMyRenamedRepository repository,
IPrincipal currentUser)
{
this.repository = repository;
this.currentUser = currentUser;
}
public CompetencyModel BuildNewCompetencyModel(int careerPlanningFormID, string newActionPlanText)
{
var competency = new Competency
{
CareerPlanningFormID = careerPlanningFormID,
CompetencyOptionID = null,
ActionPlan = newActionPlanText
};
this.repository.Add(competency);
this.repository.Commit();
return new CompetencyModel
{
CompetencyID = competency.CompetencyID,
CompetencyOptionID = competency.CompetencyOptionID,
ActionPlan = competency.ActionPlan,
CompetencyOptions = this.GetCompetencyOptionsForCareerPlanningFormID(careerPlanningFormID)
};
}
}
Now, the partial for NewCompetencyTemplate: Views/CPF/NewCompetencyTemplate.cshtml
This is very simple, it simply renders the same editor template as above, for the last competency in the collection (which we just added)
#model MyNamespace.Models.CareerPlanningForm.SelectCompetenciesViewModel
#Html.EditorFor(m => m.Competencies[Model.Competencies.Count() - 1])
When the ajax call succeeds, it will receive this partial back from the controller action method it called. It then takes the partial and appends it to the competencies table body
// snippet from ajax call above
competenciesTableBody.append(elements);
I hope this helps. Let me know if you have any additional questions.
While you're correct that you can do it just by returning a partial view containing the updated content, you may also consider using jQuery's load method.
Look here, in particular at the "loading page fragments" section. Basically you can just get the original page again and jQuery will "extract" the content you want as long as it can be targetted by a selector (such as a div id).
Note, this solution is not suitable in all cases as there will be redundant markup in the response from the server because you will be discarding the rest of the page content and just using the updated part.

The error of can not find View in Ajax form

I ask a similar question here
So I add Some OnComplete Functions and Id to Ajax Forms, And there is:
This is My View:
#foreach(var item in Model) {
<tr id="TR#(item.Id)">
#{Html.RenderPartial("_PhoneRow", item);}
</tr>
}
_PhoneRow:
#model PhoneModel
#using(Ajax.BeginForm("EditPhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteEditPhone"
}, new { id = "EditAjaxForm" + Model.Id})) {
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Edit" class="CallEditPhone" id="edit#(Model.Id)" /></td>
}
Controller:
public ActionResult EditPhone(long Id) {
//Get model by id
return PartialView("_EditPhoneRow", model);
}
public ActionResult SavePhone(PhoneModel model) {
//Save Phone, and Get Updatet model
return PartialView("_PhoneRow", model);
}
_EditPhoneRow
#model PhoneModel
#using(Ajax.BeginForm("SavePhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteSavePhone"
})) {
<td>#Html.EditorFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.EditorFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Save" class="SaveEditPhone" id="save#(Model.Id)" /></td>
}
And Oncomplete Scripts:
function OnCompleteEditPhone() {
$('input.SaveEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#SaveAjaxForm' + id).trigger('submit');
});
}
function OnCompleteSavePhone() {
$('input.CallEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#EditAjaxForm' + id).trigger('submit');
});
}
So Click Edit Worked perfect, Then Click Save Worked good also, But in second time when i click the Edit Button I have an Error in Post Action I copy the Firebug console here:
http://Mysite/members/editphone/7652 200 OK 582ms
http://Mysite/members/savephone/7652 200 OK 73ms
http://Mysite/members/editphone/7652 500 internal server error 136ms
<title>The view 'EditPhone' or its master was not found or no view engine supports the searched locations. The following locations were searched: ...
So where is the problem? If I remove OnCompleteSavePhone The Edit button for second time not worked, and with this function I have an error that not make any sense, How Can I fix it? I actually load partial views by Ajax, And need the buttons of this views worked correctly, at first every thing is fine but after Ajax result They don't, I think to add some Oncomplete functions, but there is an error also.
Your previous question is answered now. You had broken markup. As a consequence of this you no longer need to care about any OnComplete events and doing some auto triggers, form submissions and stuff. This will be handled by the Ajax.BeginForm infrastructure automatically for you.

passing data from view to controller on asp.net mvc 3

i have problem to pass data from view to controller , i have view that is strongly typed with my viewmodel "TimeLineModel", in the first i passed to this view my viewmodel from action on my controller
public ActionResult confirmation(long socialbuzzCompaignId)
{
return View(new TimeLineModel() { socialBuzzCompaignId = socialbuzzCompaignId, BuzzMessages = model });
}
with this i can get info from my action and display it on view , but i have other action POST which i won't get my view model to do some traitement
[HttpPost]
public ActionResult confirmation(TimeLineModel model)
{
}
i can get some propretie of the model but in others no , for example i can get the properti "socialBuzzCompaignId" of model , but other propertie like "IEnumerable BuzzMessages" i can't get it , i dont now why !!
this is the content of my view
#model Maya.Web.Models.TimeLineModel
#{
ViewBag.Title = "confirmation";
}
#using (Html.BeginForm())
{
<h2>confirmation</h2>
<fieldset>
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
</div>
<br />
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
You need to include BuzzMessages properties within a form element. Since it's not editable, you'd probably want to use hiddens. There are two ways to do this. Easiest is instead of doing a foreach loop, do a for loop and insert them by index.
#for (int i =0; i<Model.BuzzMessages.Count(); i++v)
{
<div class="editor-label">
#Model.BuzzMessages[i].LongMessage
#Html.HiddenFor(m => m.BuzzMessages[i].LongMessage);
</div>
<br />
}
but to do this you'd need to use an IList instead of an IEnumerable in your view model to access by index.
Alternatively, you could create an Editor Template named after your BuzzMessages class (whatever its name is).
#model BuzzMessagesClass
#Html.HiddenFor(m => m.LongMessages)
<!-- Include other properties here if any -->
and then in your main page
#Html.EditorFor(m => m.BuzzMessages)
Check out http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/ or search stack overflow if the details of editor templates confuse you.
Just like any HTML POST method, you have to get the data back to the Controller somehow. Just simply "showing" the data on the page doesn't rebind it.
You have to put the data in an input (or a control that will post back) to the appropriate model property name.
So, if you have a model property with name FirstName and you want this data to be rebound to the model on POST, you have to supply it back to the model by placing an "input hidden" (or similar control that postbacks) with the ID of FirstName will rebind that property to the model on POST.
Hope that explains it.
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
<input type="hidden" name="BuzzMessages.LongMessage" value="#msg.LongMessage" />
</div>
}
It will post array of LongMessages. Get values like this:
[HttpPost]
public ActionResult confirmation(TimeLineModel model, FormCollection collection)
{
var longMessages = collection["BuzzMessages.LongMessage"];
}

ASP.NET MVC 3 WITH RAZOR : How to pass selected checkbox' ids in a Partial view to controller action?

I have a partialview [_SearchProduct] within the main view, let's say [product] view. The Partialview has a number of checkboxes segregated into different sections like search by company,search by product etc. with one [search] button.
A User can select multiple checkboxes. When user clicks [search] button I need to pass ids of all selected checkbox to controller action and re-render the page again considering the user's selection . Please guide me how to pass selected checkbox ids to my controller action.
My partial view is something like below:
<fieldset>
<legend>By Company</legend>
<table style="border-style: none;">
<tr>
#{
int i = 0;
foreach (var item in Model.CompanyName)
{
i = i + 1;
<td style="border-style: none;text-decoration:none;" >
#Html.CheckBox("chkCompany",new {id="chkCompany_" + Model.CompanyId.Tostring()}) #Model.CompanyName
</td>
if (i == 5)
{
#:</tr><tr>
i = 0;
}
}
}
</tr>
</table>
</fieldset>
<fieldset>
<legend>By Product</legend>
<table style="border-style: none;">
<tr>
#{
i = 0;
foreach (var item in Model.Product)
{
i = i + 1;
<td style="border-style: none;text-decoration:none;" >
#Html.CheckBox("chkProduct",new {id="chkProduct_" + Model.CompanyId.Tostring()}) #Model.ProductName
</td>
if (i == 10)
{
#:</tr><tr>
i = 0;
}
}
}
</tr>
</table>
</fieldset>
checkboxes are dynamic
Checkbox id represent the primarykey of respective table based on which i do filtering.
Please guide me>>
So it sounds like you have a structure containing names (of companies/products), and ids.
I would create a View Model structure that looked like
public class PartialViewModel //Make sure this is included in your main view model
{
public List<ObjectsToInclude> Companies { get; set; }
public List<ObjectsToInclude> Products { get; set; }
}
public class ObjectsToInclude //Give this a better name
{
public string Name { get; set; }
public string Id { get; set; }
public bool Include { get; set; }
}
Then in order to bind them you could do
for (int i =0; i<Model.Companies.Count(); i++)
{
<td style="border-style: none;text-decoration:none;" >
#Html.HiddenFor(m => m.Companies[i].Id)
#Html.CheckBoxFor(m => m.Companies[i].Include) #Model.Companies[i].Name
</td>
if (i == 5)
{
#:</tr><tr>
i = 0;
}
}
Then provided your post takes a parameter of PartialViewModel (or some MainViewModel where that contains an instance of PartialViewModel), you'll have lists of companies and products binded. You can loop through the list, and take the respective ids of anything checked to be included.
Edit: If you wanted a single comma separated array to be posted, it would be possible by by creating an onclick event for your checkboxes, and then setting a value of a hidden input every time a checkbox is clicked. But then your code would only work with JavaScript enabled. If you need a comma separated string, you can create it server side with the view model I suggested.
string companyIds = String.Join(",", model.Companies
.Where(company => company.Include)
.Select(company => company.Id));
http://dotnetnsqlcorner.blogspot.in/2012/09/multiple-checkboxes-in-mvc-3-and-post.html

MVC3 Razor "For" model - contents duplicated

It has been intriguing that my MVC3 razor form renders duplicated values inside a foreach code block in spite of correctly receiving the data from the server. Here is my simple form in MVC3 Razor...
-- sample of my .cshtml page
#model List<Category>
#using (#Html.BeginForm("Save", "Categories", FormMethod.Post))
{
foreach (Category cat in Model)
{
<span>Test: #cat.CategoryName</span>
<span>Actual: #Html.TextBoxFor(model => cat.CategoryName)</span>
#Html.HiddenFor(model => cat.ID)
<p>---</p>
}
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
My controller action looks something like this -
[HttpPost]
public ActionResult Save(ViewModel.CategoryForm cat)
{
... save the data based on posted "cat" values (I correctly receive them here)
List<Category> cL = ... populate category list here
return View(cL);
}
The save action above returns the model with correct data.
After submitting the form above, I expect to see values for categories similar to the following upon completing the action...
Test: Category1, Actual:Category1
Test: Category2, Actual:Category2
Test: Category3, Actual:Category3
Test: Category4, Actual:Category4
However #Html.TextBoxFor duplicates the first value from the list. After posting the form, I see the response something like below. The "Actual" values are repeated even though I get the correct data from the server.
Test: Category1, Actual:Category1
Test: Category2, Actual:Category1
Test: Category3, Actual:Category1
Test: Category4, Actual:Category1
What am I doing wrong? Any help will be appreciated.
The helper methods like TextBoxFor are meant to be used with a ViewModel that represent the single object, not a collection of objects.
A normal use would be:
#Html.TextBoxFor(c => c.Name)
Where c gets mapped, inside the method, to ViewData.Model.
You are doing something different:
#Html.TextBoxFor(c => iterationItem.Name)
The method internall will still try to use the ViewData.Model as base object for the rendering, but you intend to use it on the iteration item. That syntax, while valid for the compiler, nets you this problem.
A workaround is to make a partial view that operates on a single item: inside that view you can use html helpers with correct syntax (first sample), and then call it inside the foreach, passing the iteration item as parameter. That should work correctly.
A better way to do this would be to use EditorTemplates.
In your form you would do this:
#model List<Category>
#using (#Html.BeginForm("Save", "Categories", FormMethod.Post))
{
#Html.EditorForModel()
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
Then, you would create a folder called EditorTemplates, either in the ~/Views/Shared folder or in your Controllers View folder (depending on whether you want to share the template with the whole app or just this controller), and in the EditorTemplates folder, create a Category.cshtml file which looks like this:
#model Category
<span>Test: #Model.CategoryName</span>
<span>Actual: #Html.TextBoxFor(model => model.CategoryName)</span>
#Html.HiddenFor(model => model.ID)
<p>---</p>
MVC will automatically iterate over the collection and call your template for each item in it.
I've noticed that using foreach loops within Views causes the name attributes of text boxes to be rendered the same for every item in the collection. For your example, every text box will be rendered with the following ID and Name attributes:
<input id="cat_CategoryName" name="cat.CategoryName" value="Category1" type="text">
When your controller receives the form data collection, it won't be able reconstruct the collection as different values.
The solution
A good pattern I've adopted is to bind your View to the same class you want to post back. In the example, model is being bound to List<Category> but the controller Save method receives a model ViewModel.CategoryForm. I would make them both the same.
Use a for loop instead of a foreach. The name/id attributes will be unique and the model binder will be able to distinguish the values.
My final code:
View
#model CategoryForm
#using TestMvc3.Models
#using (#Html.BeginForm("Save", "Categories", FormMethod.Post))
{
for (int i = 0; i < Model.Categories.Count; i++)
{
<span>Test: #Model.Categories[i].CategoryName</span>
<span>Actual: #Html.TextBoxFor(model => Model.Categories[i].CategoryName)</span>
#Html.HiddenFor(model => Model.Categories[i].ID)
<p>---</p>
}
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
Controller
public ActionResult Index()
{
// create the view model with some test data
CategoryForm form = new CategoryForm()
{
Categories = new List<Category>()
};
form.Categories.Add(new Category() { ID = 1, CategoryName = "Category1" });
form.Categories.Add(new Category() { ID = 2, CategoryName = "Category2" });
form.Categories.Add(new Category() { ID = 3, CategoryName = "Category3" });
form.Categories.Add(new Category() { ID = 4, CategoryName = "Category4" });
// pass the CategoryForm view model
return View(form);
}
[HttpPost]
public ActionResult Save(CategoryForm cat)
{
// the view model will now have the correct categories
List<Category> cl = new List<Category>(cat.Categories);
return View("Index", cat);
}

Resources