1

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...

5
  • possible duplicate of Best practices for debugging ASP.NET MVC Binding Commented Mar 8, 2013 at 9:09
  • Well, thank you for replying, but isn't this a bit too blunt? I already observed that the data is not posted back and I would like to know the proper way to set a complex model like this up in MVC. Or am I missing something? Sorry if I did. Commented Mar 8, 2013 at 9:42
  • I found that the default binder behaviour while doing what you expect most of the time, not very well documented. In a complex case like yours, I always found it's most instructive to step through the default binder code, as explained in the link I posted, this way you get first hand information, why it's not binding parameters the way you expect. If "blunt" is being attributed to my persona, I'm sorry I did not mean to upset. Commented Mar 8, 2013 at 9:54
  • No, not at all attributed to your persona. English is not my 1st language, so perhaps I made a mistake. I mean, the other topic is about debugging. My question is more about giving examples how to bind lists or models from partial views. So 'blunt' as in, isn't that conclusion too quick. But... No worries. I found a tutorial about binding lists in the topic you posted. So I'll try that. You have to understand that I could look at the debugger and still not understand what i'm seeeing. Because I'm a desktopdeveloper I find webdevelopment very hard. Commented Mar 8, 2013 at 10:10
  • @Zespri: You brought the initial info to help with my question, but I can't credit you as the answer since you commented. So... With this comment I would like to thank you again for your information. Commented Mar 11, 2013 at 10:50

1 Answer 1

0

I think what you are looking for is the binding of collections. This may help: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for replying. Yup, it had to do with how to bind the list. I used this url to figure it out: link. Plus what I didn't understand is that you can put all the entities from partial views in your action too aslong as the types are the same. So, i got the whole complex model to work. Case closed. Oh, p.s.: I also had to discover HiddenFor helpers to get IDs and other immutable values to the controller.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.