Adding more items to nested collections in MVC?

I have 2 models, employees1 and phone_manager. Employees1 has an ICollection called employee_phone_manager that contains all the rows with the matching employee ID.

Following a tutorial online, I integrated the two models together so that I could dynamically add and delete items from my create view. Inside my edit view, I can edit or delete phone numbers, but not add. The first thing I discovered was that the employee ID wasn't populating on the dynamically added items, so I modified the HTML helper to insert the proper employee ID, and this corrected an issue I was getting about foreign key constraints and referential integrity constraints. However, it appears that it doesn't actually insert the item into the collection.

Here is my post code for my edit controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "employee_id,assigned_id,all_id,first_name,last_name,birth_day,gender,social,address_line_1,address_line_2,city,state,zip,hire_date,termination_date,emergency_contact_name,emergency_contact_phone,notes,employee_phone_manager")] employees1 employees1)
    {
        if (ModelState.IsValid)
        {
            db.Entry(employees1).State = EntityState.Modified;
            db.SaveChanges();
            foreach (var item in employees1.employee_phone_manager)
            {
                if (item.phone_id == 0 && !item.deleted)
                {
                    db.phone_manager.Add(item);
                }
                else if (item.phone_id != 0)
                {
                db.Entry(item).State = EntityState.Modified;
                db.SaveChanges();
                }

            }
            return RedirectToAction("Index");
        }
        ViewBag.phonetype = new SelectList(db.phone_types, "phone_type_id", "phone_type_name");
        ViewBag.all_id = new SelectList(db.all_employees, "all_id", "all_id", employees1.all_id);
        return View(employees1);
    }

And my View

<div class="box border blue">
    <div class="box-title">
        <h4><i class="fa fa-phone"></i>Phone Number</h4>
        <div class="tools">
            <a href="javascript:;" class="collapse">
                <i class="fa fa-chevron-up"></i>
            </a>
            @Html.RemoveLink("<i class=\"fa fa-times\"></i>", "div.phoneNumber", "input.mark-for-delete")
        </div>
    </div>
    <div class="box-body">
        @Html.HiddenFor(x => x.phone_id)
        @Html.HiddenFor(x => x.employee_id)
        <div class="form-group">
            @Html.LabelFor(x => x.phone_type, new { @class = "control-label col-md-3" })
            @Html.DropDownListFor(x => x.phone_type, (SelectList)ViewBag.phonetype, new { @class = "form-control" })
        </div>
        <div class="form-group">
            @Html.LabelFor(x => x.phone_number, new { @class = "control-label col-md-3" })
            @Html.TextBoxFor(x => x.phone_number, new { @class = "phone  form-control", size = "10" })
        </div>
        <div class="form-group">
            @Html.LabelFor(x => x.phone_extension, new { @class = "control-label col-md-3" })
            @Html.TextBoxFor(x => x.phone_extension, new { size = "4", @class = "form-control" })
        </div>
        @Html.HiddenFor(x => x.date_added, new { @Value = System.DateTime.Now })
        @Html.HiddenFor(x => x.deleted, new { @class = "mark-for-delete" })
    </div>
</div>

And the HTML Helper

    public static IHtmlString AddLink<TModel>(this HtmlHelper<TModel> htmlHelper, string linkText, string containerElement, string counterElement, string collectionProperty, Type nestedType, string empID = "0")
    {
        var ticks = DateTime.UtcNow.Ticks;
        var nestedObject = Activator.CreateInstance(nestedType);
        var partial = htmlHelper.EditorFor(x => nestedObject).ToHtmlString().JsEncode();
        partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collectionProperty + "_" + ticks + "_");
        partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collectionProperty + "_" + ticks + "_");
        partial = partial.Replace(".employee_id\\\" type=\\\"hidden\\\" value=\\\"0", ".employee_id\\\" type=\\\"hidden\\\" value=\\\"" + empID);
        var js = string.Format("javascript:addNestedForm('{0}','{1}','{2}','{3}');return false;", containerElement, counterElement, ticks, partial);
        TagBuilder tb = new TagBuilder("a");
        tb.Attributes.Add("href", "#");
        tb.Attributes.Add("onclick", js + ";addMasks();");
        tb.Attributes.Add("class", "addNewItemsLink");
        tb.InnerHtml = linkText;
        var tag = tb.ToString(TagRenderMode.Normal);
        return MvcHtmlString.Create(tag);
    }

    private static string JsEncode(this string s)
    {
        if (string.IsNullOrEmpty(s)) return "";
        int i;
        int len = s.Length;
        StringBuilder sb = new StringBuilder(len + 4);
        string t;
        for (i = 0; i < len; i += 1)
        {
            char c = s[i];
            switch (c)
            {
                case '>':
                case '"':
                case '\\':
                    sb.Append('\\');
                    sb.Append(c);
                    break;
                case '\b':
                    sb.Append("\\b");
                    break;
                case '\t':
                    sb.Append("\\t");
                    break;
                case '\n':
                    break;
                case '\f':
                    sb.Append("\\f");
                    break;
                case '\r':
                    break;
                default:
                    if (c < ' ')
                    {
                        string tmp = new string(c, 1);
                        t = "000" + int.Parse(tmp, System.Globalization.NumberStyles.HexNumber);
                        sb.Append("\\u" + t.Substring(t.Length - 4));
                    }
                    else
                    {
                        sb.Append(c);
                    }
                    break;
            }
        }
        return sb.ToString();
    }
}

Any help is greatly appreciated! Thanks!

Answers:

Answer

After a few hours of tinkering, I finally figured out what I was doing wrong! It turns out I really should read some documentation. EntityState has several different properties, some of which are Modified, Added, and Deleted. By denoting one of these states I can insert and delete directly from the edit method.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(employees1 employees1)
    {
        if (ModelState.IsValid)
        {
            foreach (var item in employees1.employee_phone_manager)
            {
                if (item.deleted)
                {
                    db.Entry(item).State = EntityState.Deleted;
                }
                else if (item.phone_id == 0)
                {
                    db.Entry(item).State = EntityState.Added;
                }
                else
                {
                    db.Entry(item).State = EntityState.Modified;
                }

                db.SaveChanges();
            }

            db.Entry(employees1).State = EntityState.Modified;
            db.SaveChanges();

            return RedirectToAction("Index");
        }
        ViewBag.phonetype = new SelectList(db.phone_types, "phone_type_id", "phone_type_name");
        ViewBag.all_id = new SelectList(db.all_employees, "all_id", "all_id", employees1.all_id);
        return View(employees1);
    }

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.