MVC changing Create form dynamically depending on selected option and saving it in database
<p>I have 4 <code>Models</code> Post, Car, Category, SubCategory. Car has a few extra attributes and also inherits everything from Post, Post <code>Model</code> includes attributes for CategoryID and SubCategoryID. I need to create one <code>View</code> that can change dynamically to be able to save cars as well. The user first see two <code>dropdown</code> list for categories and subcategories, after both selected, it loads the right <code>PartialView</code>. Its all fine, however I can not save it in the database for a few reasons.</p>

<p>Firstly I dont know where to declare the <code>model</code> for the page, should it be in the create <code>View</code> - meaning it can not be changed as I only want the input fields to appear and change dynamically but page should not be reloaded. It also means as <code>Car Model</code> has a few extra attributes, both <code>string</code> and <code>int</code>, I can not create a <code>ViewModel</code> that has all possible attributes as <code>string</code> is not <code>nullable</code>. 
If the <code>model</code> is declared in the <code>PartialView</code>, it means I can create separate <code>ViewModel</code> for Car and Post but the form tag will be in the <code>PartialView</code> and the <code>dropdown</code> lists for categories and subcategories are outside this form tag in the Create <code>View</code> as it should not change. When form posted I get an error as before I used <code>Request.Form["..ID"];</code> to get CategoryID and SubCategoryID. I need to get around this somehow.</p>

<p>I tried using <code>Ajax</code>, but this got an error saying null entry for CategoryID and SubCategoryID, only pass values within the form tag.</p>

<p><code>Models</code></p>

<pre><code>public class Category
{
    public int CategoryID { get; set; }
    public string Name { get; set; }        

}
public class SubCategory
{        
    public int SubCategoryID { get; set; }
    [Required]
    public string Name { get; set; }
    [ForeignKey("CategoryID")]
    public virtual Category Category { get; set; }
    public int? CategoryID { get; set; }        
}
public class Post
{
    public int PostID { get; set; }
    public string Title { get; set; }
    public string Msg { get; set; }
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }
    public string PostCode { get; set; }
    [DataType(DataType.ImageUrl)]
    public string MainPhotoPath { get; set; }
    public DateTime PostedAt { get; set; }
    public bool Active { get; set; }        
    public string ApplicationUserId { get; set; }
    [ForeignKey("SubCategoryID")]
    public virtual SubCategory SubCategory { get; set; }
    public int SubCategoryID { get; set; }        
    public int CategoryID { get; set; }
    public string CityName { get; set; }

}
public class Car : Post
{
    public string Make { get; set; }
    public int Year { get; set; }
    public int EngineSize { get; set; }
    public int Mileage { get; set; }
    public string FuelType { get; set; }
    public string Transmission { get; set; }
}
</code></pre>

<p>Create <code>View</code></p>

<pre><code>@using Mvc.CascadeDropDown

@{
    ViewBag.Title = "Create";
}
&lt;div class="row"&gt;
&lt;div class="col-lg-12"&gt;
    &lt;div class="text-center"&gt;
        &lt;h2&gt;Add a new Post&lt;/h2&gt;
        &lt;h3 id="CityDiv"&gt;City: @ViewBag.Location&lt;/h3&gt;
    &lt;/div&gt;
    &lt;div class="col-lg-12"&gt;
        @Html.Action("Menu")
        &lt;div id="createNewPost"&gt;

        &lt;/div&gt;
    &lt;/div&gt;        
&lt;/div&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
$("#SubCategoryID").click(function () {
    var selectedSubCategory = $("#SubCategoryID").val();
    if (selectedSubCategory == 4) {
        var url = "/Posts/CarPartial/";

        $.ajax({
            url: url,
            cache: false,
            type: "POST",
            success: function (data) {
                $("#createNewPost").html(data);
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    }        
    else {
        var url = "/Posts/PostPartial/";

        $.ajax({
            url: url,
            cache: false,
            type: "POST",
            success: function (data) {
                $("#createNewPost").html(data);
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    }
});
$("#CreatePostFormID").submit(function () {
    var _categoryId = $("#CategoryID").val();
    var _subcategoryId = $("#SubCategoryID").val();
    var url = "/Posts/Create/";

    $.ajax({
        url: url,
        data: { cId: _categoryId, subId: _subcategoryId },
        cache: false,
        type: "POST",
        success: function (data) {
            alert("ok");
        },
        error: function (reponse) {
            alert("error : " + reponse);
        }
    });
});
&lt;/script&gt;
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
</code></pre>

<p>Menu to select categories and subcategories</p>

<pre><code>@model PostIt.Models.DropDown

&lt;h4&gt;
Please choose a category first
&lt;/h4&gt;
@using (Html.BeginForm())
{
    @Html.DropDownListFor(m =&gt; m.CategoryModel, new SelectList(Model.CategoryModel, "CategoryID", "Name"), new { @id = "CategoryID", @class = "form-control col-md-offset-2 margin-bottom" })
&lt;select id="SubCategoryID" name="SubCategoryID" class="form-control col-md-offset-2 margin-bottom"&gt;&lt;/select&gt;

}
&lt;script language="javascript" type="text/javascript"&gt;
$(window).load(function () {
    $("#CategoryID").click(function () {
        var _categoryId = $("#CategoryID").val();
        var procemessage = "&lt;option value='0'&gt; Please wait...&lt;/option&gt;";
        $("#SubCategoryID").html(procemessage).show();
        var url = "/Posts/GetSubCategoryById/";

        $.ajax({
            url: url,
            data: { categoryid: _categoryId },
            cache: false,
            type: "POST",
            success: function (data) {
                var markup = "&lt;option value='0'&gt;Select a subcategory&lt;/option&gt;";
                for (var x = 0; x &lt; data.length; x++) {
                    markup += "&lt;option class='selectedSubCategory' value=" + data[x].Value + "&gt;" + data[x].Text + "&lt;/option&gt;";
                }
                $("#CategoryID").val(_categoryId);
                $("#SubCategoryID").html(markup).show();
            },
            error: function (reponse) {
                alert("error : " + reponse);
            }
        });
    });
});
&lt;/script&gt;
</code></pre>

<p><code>PartialView</code> loaded inside <code>createNewPost</code> <code>div</code> if subcategory only requires a Post <code>Model</code></p>

<pre><code>@model PostIt.Models.PostViewModel
@using (Html.BeginForm("Create", "Posts", FormMethod.Post, new { enctype = "multipart/form-data", id = "CreatePostFormID" }))
        {
@Html.AntiForgeryToken()

&lt;div class="form-horizontal"&gt;
        &lt;div class="form-group"&gt;
            @Html.LabelFor(model =&gt; model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
            &lt;div class="col-md-10"&gt;
                @Html.EditorFor(model =&gt; model.Title, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model =&gt; model.Title, "", new { @class = "text-danger" })
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="form-group"&gt;
            @Html.LabelFor(model =&gt; model.Msg, htmlAttributes: new { @class = "control-label col-md-2" })
            &lt;div class="col-md-10"&gt;
                @Html.EditorFor(model =&gt; model.Msg, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model =&gt; model.Msg, "", new { @class = "text-danger" })
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="form-group"&gt;
            @Html.LabelFor(model =&gt; model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
            &lt;div class="col-md-10"&gt;
                @Html.EditorFor(model =&gt; model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model =&gt; model.Price, "", new { @class = "text-danger" })
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="form-group"&gt;
            @Html.LabelFor(model =&gt; model.PostCode, htmlAttributes: new { @class = "control-label col-md-2" })
            &lt;div class="col-md-10"&gt;
                @Html.EditorFor(model =&gt; model.PostCode, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model =&gt; model.PostCode, "", new { @class = "text-danger" })
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="form-group"&gt;
            @Html.LabelFor(model =&gt; model.MainPhotoPath, htmlAttributes: new { @class = "control-label col-md-2" })
            &lt;div class="col-md-10"&gt;
                @Html.TextBoxFor(model =&gt; model.MainPhotoPath, new { type = "file" })
                @Html.ValidationMessageFor(model =&gt; model.MainPhotoPath, "", new { @class = "text-danger" })
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="form-group"&gt;
            &lt;div class="col-md-offset-2 col-md-10"&gt;
                &lt;input type="submit" value="Create" class="btn btn-default" id="SubmitID" /&gt; | @Html.ActionLink("Cancel", "Index")
            &lt;/div&gt;
        &lt;/div&gt;
&lt;/div&gt;
}
</code></pre>

<p><code>ActionMethod</code> to create a Post.</p>

<pre><code>public ActionResult Create([Bind(Include = "Title,Msg,Price,PostCode,MainPhotoPath")] PostViewModel post, HttpPostedFileBase image, int cId, int subId)
    {
        Post newPost = new Post();
        //var cId = Request.Form["CategoryModel"];
        //var subId = Request.Form["SubCategoryID"];
        newPost.CategoryID = Convert.ToInt32(cId);
        newPost.SubCategoryID = Convert.ToInt32(subId);
        newPost.Title = post.Title;
        newPost.Msg = post.Msg;
        newPost.Price = post.Price;
        newPost.PostCode = post.PostCode;
        newPost.PostedAt = DateTime.Now;
        newPost.Active = false;
        newPost.ApplicationUserId = User.Identity.GetUserId();
        newPost.CityName = Server.HtmlEncode(Request.Cookies["location"].Value);
        Debug.WriteLine(Request.Files.Count);

        HttpPostedFileBase file = Request.Files[0];
        string fileName = file.FileName;
        int fileSize = file.ContentLength;
        if (fileSize &gt;= 10)
        {
            string path = Server.MapPath("~/Upload_Files/images/");
            newPost.MainPhotoPath = "~/Upload_Files/images/" + fileName;

            if (!Directory.Exists(path))
            {
                Debug.WriteLine("Creating new directory");
                Directory.CreateDirectory(path);
            }
            file.SaveAs(Server.MapPath("~/Upload_Files/images/" + fileName));
        }
        else
        {
            newPost.MainPhotoPath = "~/Images/no_image.png";
        }



        if (ModelState.IsValid)
        {
            db.Posts.Add(newPost);
            db.SaveChanges();
            return RedirectToAction("Index", "Home");
        }

        return View("Create", post);
    }
</code></pre>