0

I have a view which contains a dropdown list and on dropdownlist item being selected I load a partial view. And when the form is submitted I want to be able to get both the values from main view and partial view during form submit. Here is the main view

@model AdminPortal.Areas.Hardware.Models.CreateModule
@{
    ViewBag.Title = "Create Module";
    Layout = "~/Views/shared/_BootstrapLayout.basic.cshtml";
}

@Html.ValidationSummary(true)


<fieldset class="form-horizontal">
    <legend>Add a Module <small>Create</small></legend>
    @using (Html.BeginForm("CreateModule", "Module", new{id="AddModuleForm"}))
    {
        @Html.ValidationSummary(true)
        <div class ="controls">
            <div class="input-block-level">@Html.TextBoxFor(model => model.ModuleId, new {@placeholder = "ModuleID"})</div>
            <br/>
            <div class ="input-block-level" id="selectedModuleTypeName">@Html.DropDownListFor(model => model.SelectedModuleTypeName, Model.TypeNames,"Select Moduletype", new{id = "ModuleList"})</div>

            <br/>
            <div id="partialDiv"></div>
        </div>
         <div class="form-actions" id="buttons">
        <button type="submit" class="btn btn-primary" id="Submit">Save changes</button>
        @Html.ActionLink("Cancel", "ModuleList", null, new { @class = "btn " })
    </div>

    }

</fieldset>
<div>
    @Html.ActionLink("Back to List", "ModuleList")
</div>
<script>
    $("#buttons").hide();
    $("#ModuleList").on("change", function() {
        var modId = $(this).val();
        $.get('@Url.Action("GetModulePropertyName", "Module")', { moduleTypeValue: modId }, function(result) {
            $("#partialDiv").html(result);
        });
        //uncomment following section to check if the partial view is working properly
        /*.done(function() { alert("done"); })
            .fail(function() { alert("fail"); })
            .always(function() { alert("completed"); });*/

    });
        $("#buttons").show();

</script>

and here is the partial view

    @model IEnumerable<string>

    @foreach(var names in Model)
    {
        <div class="input-block-level">@Html.TextBoxFor(m=>names, new{Value="", placeholder=names})</div>
        <br/>
    }

Here is my model

public class CreateModule
    {
        //Empty form to handle form serialization
        public CreateModule()
        {
        }

        [Required]
        public string ModuleId { get; set; }

        [DataType(DataType.DateTime)]
        public DateTime DateEntered { get; set; }

        [Required]
        public string SelectedModuleTypeName { get; set; }
        public IEnumerable<SelectListItem> TypeNames { get; set; }

        public List<Property> Properties { get; set; }
    }

public class Property
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }

Here is the method that script in main view forwards to

[HttpGet]
        public ActionResult GetModulePropertyName(string moduleTypeValue)
        {
            var moduleKindId = _repository.GetModuleKindId(moduleTypeValue);
            var modulePropertyNames = _repository.GetModuleKindPropertyNames(moduleTypeValue);
            return PartialView("GetModulePropertyName",modulePropertyNames);
        }

and finally here is httppost method for the main view

[HttpPost]
        public ActionResult CreateModule(CreateModule moduleV)
        {
            var module = new Module
                {
                    ModuleTypeId = Convert.ToInt64(moduleV.SelectedModuleTypeName),
                    ModuleId = moduleV.ModuleId,
                    DateEntered = moduleV.DateEntered,


                };
            if (ModelState.IsValid)
            {
               _repository.AddModule(module);
                Success("Module added successfully!");
                return RedirectToAction("ModuleList", "Module", new {area = "Hardware"});
            }


                Error("Something went wrong!");
                return RedirectToAction("CreateModule", "Module", new { area = "Hardware" });

        }

Current situation: When the form is posted, the properties value of the model that is being passed via partial view is null. I get other values, like typename, Module ID.

What I'd want: I also want to get the value of properties that is being passed via partial view.

Cybercop
  • 8,475
  • 21
  • 75
  • 135

3 Answers3

1

You don't have any input field for the Properties property anywhere in your form. So it will always be null. That's normal.

Here's how you could proceed. Start by setting the correct navigational property so that the helper generates correct names of the corresponding input fields.

Also make sure that you are passing an IEnumerable<Property> model to the partial if you want to be able to get them back correctly:

[HttpGet]
public ActionResult GetModulePropertyName(string moduleTypeValue)
{
    var moduleKindId = _repository.GetModuleKindId(moduleTypeValue);
    IList<Property> model = ...
    return PartialView("GetModulePropertyName", model.ToList());
}

and in your partial view use an editor template:

@model IList<Property>
@{
    // This indicates the current navigational context to the helpers
    ViewData.TemplateInfo.HtmlFieldPrefix = "Properties";
}

@Html.EditorForModel()

and the last step is to define a custom editor template for the Property class: ~/Views/Shared/EditorTemplates/Property.cshtml (note that the name and location of the template is important)

@model Property
<div class="input-block-level">
    @Html.HiddenFor(m => m.Name)
    @Html.TextBoxFor(m => m.Value, new { placeholder = Model.Name })
</div>
<br />
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I still get null value for properties :( This is what i've done in controller for [httpget] `public ActionResult GetModulePropertyName(string moduleTypeValue) { var temp = _repository.GetModuleKindPropertyNames(moduleTypeValue); IList model = temp.Select(item => new Property {Name = item}).ToList(); return PartialView("GetModulePropertyName",model); }` and the view is exactly as you have mentioned. – Cybercop Jul 16 '13 at 07:23
  • Could you paste the `name` of some of the hidden input fields that are generated? – Darin Dimitrov Jul 16 '13 at 07:31
  • You mean the hidden input field names that are generated by partial view? – Cybercop Jul 16 '13 at 07:40
  • If yes then, I ran the developer tools and checked the elements here is what is generated for partial view `` and `` – Cybercop Jul 16 '13 at 07:46
  • I see, there's a problem with the `name`. It should have been `Properties[0].Name` instead of `Properties.[0].Name`. I will see how to fix that and update my answer later. – Darin Dimitrov Jul 16 '13 at 07:49
  • Alright, see my updated answer in which I suggest you using a custom editor template in order to get correct names for the input fields. – Darin Dimitrov Jul 16 '13 at 07:58
  • Yup you saved the day again :) and I realize how important the name and location is, first I just created the view inside shared folder which didn't work, then i created a folder inside shared folder as you have mentioned and placed my view there and it worked!!! Cheers!!! – Cybercop Jul 16 '13 at 08:44
0

Try using the

List<Property> 

as a model in your partial view and pass the CreateModule.Properties as model from your View

Nilesh
  • 2,583
  • 5
  • 21
  • 34
  • Thanks, i was thinking the same. But in my `HttpGet` method that script in main view forwards to. How can I change my method right? what can I do there so that i can pass the value to my partial view and use the model of my view as u'e said? – Cybercop Jul 15 '13 at 13:03
0

The problem is model binder can not figure out there

@Html.TextBoxFor(m=>names, new{Value="", placeholder=names})

belongs to as the "names" is not a property on your model class. If you need to bind to the CreateModule.Properties you need to change the partial view to emit textboxes with aproprate names, like this one:

 @model IEnumerable<string>
@
{
 int i=0;
}
    @foreach(var names in Model)
    {
        <div class="input-block-level">@Html.TextBox("Properties[" + i + "].Value")</div>
        <br/>
    }
Alexandr Mihalciuc
  • 2,537
  • 15
  • 12