MVC.NET the ViewModel from Create POST is always null - c#

In my MVC.NET project I used scaffolding templates. Initially ther were binded to one DTO model. Now I decided I wanted to link it to a ViewModel, because I have two multiselects I need to use to pass values. This is how my ViewModel looks:
public class CreateQuestionModel
{
public Question Question { get; set; }
public List<int> PoliticianIds { get; set; }
public List<int> TopicIds { get; set; }
}
My Create POST method that is getting a ViewModel from the View:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Regular")]
public ActionResult Create(CreateQuestionModel question)
{
if (ModelState.IsValid)
{
int id = WebSecurity.CurrentUserId;
manager.CreateQuestion(question.Question, id, question.PoliticianIds, question.TopicIds);
return RedirectToAction("Index");
}
return View(question);
}
And my Create.cshtml looks like this:
#model PoliticiOnline.Models.CreateQuestionModel
#{
ViewBag.Title = "Stel een vraag!";
}
<head>
<link rel="stylesheet" href="~/Content/Questions.css" type="text/css" />
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
<script src="#Url.Content("~/Scripts/Extra/Chosen/chosen.jquery.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="#Url.Content("~/Scripts/Extra/Chosen/chosen.min.css")" type="text/css">
<script src="#Url.Content("~/Scripts/Extra/select2-3.4.6/select2.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="#Url.Content("~/Scripts/Extra/select2-3.4.6/select2.css")" type="text/css">
</head>
<h2>Stel een vraag!</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Vraag</legend>
<div class="general-question">
<div class="editor-label">
#Html.LabelFor(model => model.Question.GeneralQuestion, "Algemene Vraag")
</div>
<div class="editor-field">
#Html.TextBox("Question.GeneralQuestion", new { #class = "general-question-edit" })
#Html.ValidationMessageFor(model => model.Question.GeneralQuestion)
</div>
</div>
<div id="geadresseerde-politici">
#Html.LabelFor(model => model.PoliticianIds, "Geadresseerde Politicians:")
#Html.ListBox("PoliticianIds", (MultiSelectList)ViewBag.Politicians, new { #id = "polDrop" })
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Question.Explanation, "Extra Uitleg")
</div>
<div class="editor-field">
#Html.TextArea("Question.Explanation", new { #class = "explanation-textarea-edit" })
#Html.ValidationMessageFor(model => model.Question.Explanation)
</div>
<div>
#Html.LabelFor(model => model.TopicIds, "Kies je thema's (maximum 2):")
#Html.ListBox("TopicIds", (MultiSelectList)ViewBag.Topics, new { #id = "select2select", #style = "width: 500px"})
</div>
<p>
<input type="submit" value="Indienen!" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script type="text/javascript">
function format(topic) {
if (topic.css == 'optionGroup') {
return "<b>" + topic.text + "</b>";
} else {
return "<i> " + topic.text + "<i>";
}
}
$("#select2select").select2({
placeholder: "Selecteer een thema...",
maximumSelectionSize: 2,
formatResult: format,
escapeMarkup: function(m) {
return m;
}
});
</script>
The <script> section at the bottom doesn't really matter but I pasted it anyway, I'm using the jQuery plugin select2 for the ListBox.
This is a way of binding the textboxes and such to ViewModel properties, I found this on Stackoverflow. I also tried the classic way using #Html.EditorFor and #HtmlListBoxFor but the ViewModel's properties are always null.
What am I doing wrong/ what am I overlooking?
EDIT:
I put a constructor in the ViewModel, now the ViewModel (CreateQuestionModel) is not null anymore, but the values are still default values (not the ones from the form). My ViewModel now looks like:
public class CreateQuestionModel
{
public Question Question { get; set; }
public List<int> PoliticianIds { get; set; }
public List<int> TopicIds { get; set; }
public CreateQuestionModel()
{
Question = new Question();
PoliticianIds = new List<int>();
TopicIds = new List<int>();
}
}
SOLUTION
Commenter Yoeri provided the solution, you can see it below in my answer on this question!

My dumb error that caused all the properties in the ViewModel to be default values on POSTing to the Controller. I did not declare the {get; set;} for each property.
ERROR
public class ApplicationViewModel
{
public Application App;
public SelectList SelectSimple;
public ApplicationViewModel()
{
// Create/Init App & SelectSimple
}
}
CORRECT
public class ApplicationViewModel
{
public Application App { get; set; }
public SelectList SelectSimple { get; set; }
public ApplicationViewModel()
{
// Create/Init App & SelectSimple
}
}
COMMENT
It bears repeating that the Controller needs an [HttpGet] that passes non-null ViewModel to the View; and Controller needs an [HttpPost] to receive the ViewModel on the submit by the user.

Okay guys, I just found out what I was doing wrong. I made an extremely stupid mistake, can't believe I've been struggling for 2 days with this now.
The signature of my Create POST method was:
public ActionResult Create(CreateQuestionModel question)
{
...
}
It should be:
public ActionResult Create(CreateQuestionModel createQuestionModel)
{
...
}
I just had to change the parameter form CreateQuestionModel question to CreateQuestionModel createQuestionModel, it was as simple as that, now everything works.
UPDATE
Thanks to Yoeri I now understand why it was giving problems in the first place:
Initially I named the parameter CreateQuestionModel question, this didn't work because I have a model class named Question. So basically the parameter name has to be either the name of the model you are using in the Create View, or any other name as long as it's not a name of another model class!
Thanks Yoeri!

Try,
#using(Html.BeginForm("Create", "*controller-name*",FormMethod.Post))

Related

Why is my HttpPost method not firing from my Asp.Net Core Razor page?

New to Asp.Net Core Razor here.
I'm trying to hook up a simple button to save on my Razor page.
My [HttpPost]SaveDocument() method is not firing on the the "Save" button click.
Instead, the Index() method is firing.
I'm not sure what I've got hooked up incorrectly.
Here is a snippet of my Razor Page definition:
#model SampleViewModel
#{ Layout = "_DevExtremeLayout";
ViewBag.Title = "Sampe Title";}
<form method="post">
<div id="InputFormPanel" class="InputFormPanel">
<partial name="#Model.ChildViewName" model="#Model.ChildViewModel" />
</div>
<div class="row">
<div class="col-md-3">
<input id="ApprovedBy" class="form-control" asp-for="ApprovedBy" />
</div>
<div class="col-md-2">
<input class="form-control" asp-for="Title" />
</div>
</div>
<button id="SaveButton" type="submit" >Save Form</button>
</form>
Here is my model:
public class SampleViewModel
{
public object ChildViewModel { get; set; }
public string ChildViewName { get; set; }
public string ApprovedBy { get; set; }
public string Title { get; set; }
}
Here is a snippet of my controller:
public class SampleController : Controller
{
public async Task<IActionResult> Index(Guid documentTypeId)
{
SampleViewModel viewModel = new SampleViewModel()
{
};
return View(viewModel);
}
[HttpPost]
public async Task<IActionResult> SaveDocument(SampleViewModel sampleViewModel)
{
return RedirectToAction("Index");
}
}
Being new to this, I imagine I'm doing something foolish here/missing something.
What am I doing wrong here?
If you don't assign the action attribute on an HTML form it will post the request to the same page/route you're currently on, which in this case is your Index action.
So if you add an action attribute like so:
<form method="post" action="SaveDocument">
It should start working. Alternatively you can also rename the SaveDocument method to Index, there won't be any errors since the two method signature won't match. From a code organization point of view that's typically my preference since it makes it clear that the GET/POST actions are for the same page.

How to send the Model to a partial view and change it's value in the controller before it arrives to the partial view and update with ajax [duplicate]

The problem I will be describing is very similar to ones I already found (e.g. this post with nearly identical name) but I hope that I can make it into something that is not a duplicate.
I have created a new ASP.NET MVC 5 application in Visual Studio. Then, I defined two model classes:
public class SearchCriterionModel
{
public string Keyword { get; set; }
}
public class SearchResultModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
Then I created the SearchController as follows:
public class SearchController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult DisplaySearchResults()
{
var model = new List<SearchResultModel>
{
new SearchResultModel { Id=1, FirstName="Peter", Surname="Pan" },
new SearchResultModel { Id=2, FirstName="Jane", Surname="Doe" }
};
return PartialView("SearchResults", model);
}
}
as well as views Index.cshtml (strongly typed with SearchCriterionModel as model and template Edit) and SearchResults.cshtml as a partial view with model of type IEnumerable<SearchResultModel> (template List).
This is the Index view:
#model WebApplication1.Models.SearchCriterionModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SearchCriterionModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Keyword, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Keyword, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Keyword, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" id="btnDisplaySearchResults" value="Search" onclick="location.href='#Url.Action("DisplaySearchResults", "SearchController")'" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<div id="searchResults">
</div>
As you can see, I added a div with id="searchResults" below the standard template and edited the button. What I want is to display the partial view SearchResults.cshtml in the div on the bottom, but only after the button is clicked. I have succeeded in showing a partial view there by using #Html.Partial("SearchResults", ViewBag.MyData), but it is rendered when the parent view is loaded for the first time and I set ViewBag.MyData in the Index() method already, which is not what I want.
Summary: On clicking the button, I will obtain some List of SearchResultModel instances (via database access) and then the partial view should be rendered, using this newly obtained data as model. How can I accomplish this? I already seem fail at the first step, that is reacting to the button click with the above code. Right now, I navigate to the URL ~/Search/DisplaySearchResults, but of course there's nothing there and no code-behind method is called.
In traditional ASP.NET I'd just have added a server-side OnClick handler, set the DataSource for a grid and show the grid. But in MVC I already fail with this simple task...
Update: Changing the button to #Html.ActionLink I can finally enter the controller method. But naturally since it returns the partial view, it's displayed as the whole page content. So the question is: How do I tell the partial view to be rendered inside a specific div on the client side?
Change the button to
<button id="search">Search</button>
and add the following script
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('#search').click(function() {
var keyWord = $('#Keyword').val();
$('#searchResults').load(url, { searchText: keyWord });
})
and modify the controller method to accept the search text
public ActionResult DisplaySearchResults(string searchText)
{
var model = // build list based on parameter searchText
return PartialView("SearchResults", model);
}
The jQuery .load method calls your controller method, passing the value of the search text and updates the contents of the <div> with the partial view.
Side note: The use of a <form> tag and #Html.ValidationSummary() and #Html.ValidationMessageFor() are probably not necessary here. Your never returning the Index view so ValidationSummary makes no sense and I assume you want a null search text to return all results, and in any case you do not have any validation attributes for property Keyword so there is nothing to validate.
Edit
Based on OP's comments that SearchCriterionModel will contain multiple properties with validation attributes, then the approach would be to include a submit button and handle the forms .submit() event
<input type="submit" value="Search" />
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('form').submit(function() {
if (!$(this).valid()) {
return false; // prevent the ajax call if validation errors
}
var form = $(this).serialize();
$('#searchResults').load(url, form);
return false; // prevent the default submit action
})
and the controller method would be
public ActionResult DisplaySearchResults(SearchCriterionModel criteria)
{
var model = // build list based on the properties of criteria
return PartialView("SearchResults", model);
}
So here is the controller code.
public IActionResult AddURLTest()
{
return ViewComponent("AddURL");
}
You can load it using JQuery load method.
$(document).ready (function(){
$("#LoadSignIn").click(function(){
$('#UserControl').load("/Home/AddURLTest");
});
});
source code link

Kendo UI ASP.NET MVC ListView fails when trying to add or edit items

I'm struggling to set up a ListView which allows me to add new records and to update existing ones. Loading the items for the list works like a charm. Also showing the only relevant information Id and Line works perfectly.
Two problems:
1. Adding a new item to the list: I see the ugly form which allows to set the value for Id and Line. But there is no way for me to save it.
2. Updating an existing item: I see the ugly form which allows to set the value for Id and Line. But the fields are empty. They should be pre-filled with whatever has been shown before. Again, there is no way for me to save it.
My code looks pretty similar to what is provided in Telerik's Examples Project. Unfortunately, I fail to find the minor difference...
The extremely stripped code of the ListView (still not working as intended):
#using System.Collections
#using TestcaseRepositoryAPI.Model.Domain;
#model TemplateGeneratorItem
#{
ViewBag.Title = "VORLAGE";
ViewBag.SubTitle = "erstellen";
ViewBag.ShowMenu = true;
Layout = "~/Views/Shared/_LayoutMetro.cshtml";
}
#Html.Partial("_MetroPageHeader")
<div class="demo-section">
<a class="k-button k-button-icontext k-add-button" href="#"><span class="k-icon k-add"></span>Add new record</a>
</div>
<div class="demo-section k-header">
#(Html.Kendo().ListView<TemplateGeneratorItem.Record>(Model.Records)
.Name("RecordsList")
.ClientTemplateId("recordLinesTemplate")
.DataSource(d => d
.Events(e => e.RequestStart("requestStart").RequestEnd("requestEnd"))
.Create("RecordLineCreate", "Metro")
.Read("RecordLinesRead", "Metro")
.Update("RecordLineUpdate", "Metro")
.Destroy("RecordLineDelete", "Metro")
.Model(m => m.Id(o => o.Line))
)
.Editable()
//.Events(e => e.Remove("removeRecord"))
.HtmlAttributes(new { style = "border:none;" })
.TagName("div")
)
</div>
<script type="text/x-kendo-tmpl" id="recordLinesTemplate">
<div class="k-widget" style="margin:10px auto 10px auto;">
<fieldset>
<legend>Zeile #=Line#</legend>
<div class="edit-buttons">
<a class="k-button k-button-icontext k-edit-button" href="\\#"><span class="k-icon k-edit"></span></a>
<a class="k-button k-button-icontext k-delete-button" href="\\#"><span class="k-icon k-delete"></span></a>
</div>
<dl>
<dt>ID</dt>
<dd>#:Id#</dd>
</dl>
</fieldset>
</div>
</script>
<script type="text/javascript">
function requestStart(e) {
console.log("requestStart(e)", e);
}
function requestEnd(e) {
console.log("requestEnd(e)", e);
console.log("e.type", e.type);
if (e.response) {
console.log("e.response", e.response);
}
}
function getRecList() {
return $("#RecordsList").data("kendoListView");
}
$(".k-add-button").click(function (e) {
getRecList().add();
e.preventDefault();
});
</script>
The snippet of the controller which returns the data:
public JsonResult RecordLinesRead([DataSourceRequest] DataSourceRequest request)
{
List<TemplateGeneratorItem.Record> records = GetTemplateGeneratorItemFromSession().Records;
int line = 1;
foreach (TemplateGeneratorItem.Record record in records)
{
record.Line = line++;
}
return Json(records.ToTreeDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
And finally the classes of the model:
namespace TestcaseRepositoryAPI.Model.Domain
{
[DataContract]
public class TemplateGeneratorItem
{
[DataMember]
public List<Record> Records { get; set; }
public class Record
{
[DataMember]
//[ScaffoldColumn(false)]
public int Line { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
[ScaffoldColumn(false)]
public List<RecordField> Fields { get; set; }
public Record() { }
public Record(Record record)
{
Line = record.Line;
Id = record.Id;
Fields = record.Fields;
}
}
public class RecordField
{
[DataMember]
public string Name { get; set; }
...
}
}
}
Found it. The Telerik support asked the right questions.
The problem is quite simple: There is no editor template specified! There are (at least?) two ways to resolve this issue:
1. Specify the name of the editor template (e.g. .Editable(e => e.Editable(true).TemplateName("TemplateGeneratorRecord"))) and create the TemplateGeneratorRecord.cshtml in the EditorTemplates folder.
2. Or let some magic happen by creating an editor template in the EditorTemplates folder called Record.cshtml. That's the solution used in Telerik's examples.
I've chosen the first option. Now it is working as expected.

Form in Partial not binding to model

I've got a page basically displaying an article backed by a database.
Below that article, there is a comments section. This is provided by a #Html.Action call returning a _Comments partial.
Within that _Comments partial. There is an optional _AddComment #Html.Action call that renders a _AddComment partial within it.
The _AddComment partial is backed by _AddComment controller methods for GET and POST.
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult _AddComment(EditComment comment)
The GET method just returns an "EditComment" VM with the AssetID attached.
Whenever a comment is filled in and posted within the _AddComment view. It's controller method is called correctly, but the model isn't passed back.
If I look at the Request parameters I can see all the properties of the model being passed back correctly. However, it's not being bound into the Controllers method parameter.
I've tried specifying "Model" as the route params for the Html.Begin form. It's made no difference.
Have looked at a number of SO posts, none of which sort the issue I'm having!
Presumably the model binding is failing somewhere for some reason. But obviously without an exception I've no idea what's wrong!
View Model Code
public class EditComment
{
public Boolean HasRating { get; set; }
public int AssetID { get; set; }
public int CommentID { get; set; }
public int Rating { get; set; }
public string Comment { get; set; }
}
View Code
#model SEISMatch.UI.Models.Content.EditComment
<hr />
<h3><span class="colored">///</span> Leave a Comment</h3>
<div class="row" style="margin-top: 20px;">
#using (Html.BeginForm("_AddComment", "Content", Model, FormMethod.Post))
{
#Html.ValidationSummary(false)
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.AssetID)
#Html.HiddenFor(m => m.CommentID)
if (Model.HasRating)
{
#Html.EditorFor(m => m.Rating, "_StarRating")
}
<div class="span7">
#Html.TextAreaFor(m => m.Comment, new { #class = "span7", placeholder = "Comment", rows = "5" })
</div>
<div class="span7 center">
<button type="submit" class="btn btn-success">Post comment</button>
</div>
}
</div>
Your action parameter name is comment and class EditComment has Property Comment. Modelbinder gets confused.
Rename your action parameter and problem solved.
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult _AddComment(EditComment model)

ASP.NET MVC 3 complex model binding issue

I'm trying to teach myself MVC. I mocked up a dummy project to reflect a real problem I have at the moment.
My Model(s):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcPersistPartialView.Models {
public class RemarkModels {
public static List<RemarkTemplateModel> GetTemplateAll() {
return new List<RemarkTemplateModel>() {RemarkTemplateModel.Create(1),
RemarkTemplateModel.Create(2),
RemarkTemplateModel.Create(3)};
}
}
public class RemarkModel {
public int ID { get; set; }
public string Content { get; set; }
public int TemplateID { get; set; }
public List<RemarkTemplateModel> Templates { get; set; }
public static RemarkModel Create() {
return new RemarkModel() {
Content = "This is a dummy remark, to learn MVC.",
TemplateID = 1,
Templates = RemarkModels.GetTemplateAll()
};
}
}
public class RemarkTemplateModel {
public int ID { get; set; }
public string Name { get; set; }
public List<RemarkTemplateFieldModel> Fields { get; set; }
public static RemarkTemplateModel Create(int id) {
return new RemarkTemplateModel() {
ID = id,
Name = id.ToString(),
Fields = new List<RemarkTemplateFieldModel>() {RemarkTemplateFieldModel.Create("Label A" + id.ToString(),
id.ToString() + "..."),
RemarkTemplateFieldModel.Create("Label B" + id.ToString(),
id.ToString() + "..."),
RemarkTemplateFieldModel.Create("Label C" + id.ToString(),
id.ToString() + "...")}
};
}
}
public class RemarkTemplateFieldModel {
public string Label { get; set; }
public string Content { get; set; }
public static RemarkTemplateFieldModel Create(string label, string content) {
return new RemarkTemplateFieldModel() { Label = label,
Content = content };
}
}
}
What you see in the above models is a RemarkModel, representing a remark you can save on a person like: "This person hides issues with a big smile. Watch out for that!".
You also see a RemarkTemplateModel to accomodate a slightly complex wish of my endusers to fill in certain pieces of information like with surveys. So, this 'RemarkModel' could have template 'Testtemplate A'.
Templates consist of fields (RemarkTemplateFieldModel) which could look like: 'Testtemplate A' consists out of the fields: 'Field 'A', field 'B' and field 'C' (while ofcourse some 'Testtemplate B' could consist out of fields 'D', 'E', 'F', 'G'). I hope I made this clear. Please ask if it's not clear.
Last model is RemarkModels (the 's' at the back), that's just to retrieve all the mocked up templates quickly.
My controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcPersistPartialView.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
ViewBag.Message = "Welcome to ASP.NET MVC!";
Models.RemarkModel r = Models.RemarkModel.Create();
return View(r);
}
[HttpPost]
public ActionResult Index(Models.RemarkModel remark, Models.RemarkTemplateModel template, List<Models.RemarkTemplateFieldModel> fields) {
if (ModelState.IsValid) {
//Persist to database.
}
ViewBag.Message = "Welcome to ASP.NET MVC!";
Models.RemarkModel r = Models.RemarkModel.Create();
return View(r);
}
[AcceptVerbs("POST")]
public ActionResult TemplateChosen(string selectedTemplateID) {
Models.RemarkTemplateModel selectedTemp = (from temp in Models.RemarkModels.GetTemplateAll()
where temp.ID == Convert.ToInt32(selectedTemplateID)
select temp).FirstOrDefault();
return PartialView("RemarkTemplate", selectedTemp);
}
public ActionResult About() {
return View();
}
}
}
As you can see with parameterless 'Index' I create a RemarkModel and pass it in my strongly typed View Index.cshtml. This view looks like:
#model MvcPersistPartialView.Models.RemarkModel
#using (Html.BeginForm()) {
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Templates)
</div>
<div class="editor-field">
#Html.DropDownListFor(
m => m.TemplateID,
new SelectList(Model.Templates, "ID", "Name"),
new {
id = "templateDdl",
data_url = Url.Action("TemplateChosen", "Home")
}
)
<input type="button" value="Change template" id="template-button" />
</div>
<div id="template">
#Html.Partial("RemarkTemplate", Model.Templates.First())
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
So far so good. I've been on here before to ask help with the DropDownListFor, this works like a charm now (so thank you community). We are getting to the core of my question, thank you for your patience so far. The partial view 'RemarkTemplate' looks like:
#model MvcPersistPartialView.Models.RemarkTemplateModel
<div class="display-field">
#Html.Encode(Model.ID)
</div>
<div class="display-field">
#* #Html.Encode(Model.Name)*#
#Html.EditorFor(m => m.Name)
</div>
#foreach (MvcPersistPartialView.Models.RemarkTemplateFieldModel field in Model.Fields) {
#* <div class="editor-label">
#Html.Encode(field.Label)
</div>
<div class="editor-field">
#Html.TextBox("Content", field.Content)
</div>*#
#Html.Partial("RemarkTemplateField", field)
}
We'll get to the 2nd partial view. Because first I tried this without the partial view 'RemarkTemplateField' and only 2 parameters (remark + template) in the POST Action 'Index'. My problem is that the 'template' parameter's 'fields' property remained 'null'. I also noticed nothing was really posted about the template untill I used an 'EditorFor' for the name property of the template.
The 'remark' parameter however contained the correct template ID in it's TemplateID property, so I figured if I could atleast get the fields, the template doesn't matter. So that is when I added the 2nd partial view:
#model MvcPersistPartialView.Models.RemarkTemplateFieldModel
<div class="editor-label">
#Html.Encode(Model.Label)
</div>
<div class="editor-field">
#*#Html.TextBox("Content", Model.Content)*#
#Html.EditorFor(m => m.Content)
</div>
It al displays perfectly. Very nice. But the POSTback to the Index action keeps returning an empty 'template' (well the 'name' of the template is filled in since I made it an EditorFor which is not an option on the real website) and the 'fields' list is empty. As you can see I again changed the Textbox on Content to an EditorFor. But alas, no magic.
So my question is my dear experts, how does one get a more complex model like this bound properly in MVC? How can I get the filled in contents of the fields in the Action of my Controller, so I can ultimatly persist the remark with the correct filled in template to the database? I would be very grateful for your help. Point me to tutorials, if you don't want to spell it out, which can help me. Just give me some starters. I've been at it for a workday now...
I think what you are looking for is the binding of collections. This may help: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Categories