Search code examples
c#asp.net-mvcasp.net-mvc-3icollection

Creating and editing a collection of strings using MVC3


Having some trouble understanding how to create and edit a collection of strings using a form. I've tried using EditorFor but it seems to have no luck and instead puts the following text into the form. I'm trying to edit the collection "Keywords".

System.Collections.Generic.HashSet`1[MVCModuleStarter.Models.Module]System.Collections.Generic.HashSet`1[MVCModuleStarter.Models.Module]

This is the Html I'm using the EditorFor in with a working EditorFor being used on a string for reference.

<div class="form-group">
            @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Category, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Category, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group">
        @Html.LabelFor(model => model.Keywords, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Keywords, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Keywords, "", new { @class = "text-danger" })
        </div>
    </div>

This is the Edit method inside my controller;

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ModuleId,ModuleTitle,ModuleLeader,ModuleDescription,ImageURL,Category,Keywords")] Module module)
        {
            if (ModelState.IsValid)
            {
                int moduleId = module.ModuleId;
                repository.UpdateModule(module);
                repository.Save();
                return RedirectToAction("Details", new { Id = moduleId });
            }
            return View(module);
        }

This is the Model for reference;

[Required, StringLength(20), Display(Name = "Category")]
        public string Category { get; set; }

        public virtual ICollection<Keyword> Keywords { get; set; }

Model for Keyword

    public class Keyword
    {
        [Key, Display(Name = "ID")]
        public int KeywordId { get; set; }

        [Required, StringLength(100), Display(Name = "Keyword")]
        public string KeywordTerm { get; set; }

        public virtual ICollection<Module> Modules { get; set; }
    }
}

Any help would be amazing, still new to this! Thanks!


Solution

  • You need to create an EditorTemplate for Keyword, for example

    In /Views/Shared/EditorTemplates/Keyword.cshtml (add divs, class names etc as required)

    @model Keyword
    @Html.HiddenFor(m => m.KeywordId)
    @Html.LabelFor(m => m.KeywordTerm)
    @Html.TextBoxFor(m => m.KeywordTerm)
    @Html.ValidationMessageFor(m => m.KeywordTerm)
    

    Then in the main view

    Html.EditorFor(m=> m.Keywords)
    

    Note I have omitted the collection property Modules, but if you also want to edit them, the add another EditorTemplate for Modules

    Alternatively you can use a for loop in the main view. This would mean the collection need to be IList<T>

    for(int i = 0; i < Model.Keywords.Count, i++)
    {
      @Html.HiddenFor(m => m.Keywords[i].KeywordId)
      // other properties of Keyword
      for (int j = 0; j < Model.Keywords[i].Modules.Count; j++)
      {
        @Html.TextBoxFor(m => m.Keywords[i].Modules[j].SomeProperty)
        // other properties of Module
      }
    }