0

I am trying to get my partial view to display an object name as it iterates through a collection. This is no problem when I refresh the original page but as soon as I do an AJAX post and try to return the new object to the partial view, it cannot find a specific object.

I get a null object error on the FeeTypes object which should be included in the members object as Members.Fees(whateverno).FeeTypesG

Also the ajax post does not refresh the div on success because it never gets success back (or im doing it wrong) NOTE: It still posts everything correctly to the database and saves fine.

Models

public class Members
{
    [Key]
    public int MemberNo { get; set; }

    [Display(Name = "Member Fees")]
    public virtual ICollection<Fees> Fees { get; set; }


}    




public class Fees
{
    [Key]
    public int FeeNo { get; set; }
    public virtual FeeTypes FeeType { get; set; }
    [Display(Name = "Fee Type")]
    public int FeeTypesId { get; set; }
    [Display(Name = "Frequency of Fee")]
    public FeeOccurence FeeOccurence { get; set; }
    [Display(Name = "Fee Amount")]
    public float FeeAmount { get; set; }
    [Display(Name = "Fee Status")]
    public FeeStatus FeeStatus { get; set; }
    [Display(Name = "Date received (for billing)")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? FeeDate { get; set; }
    public virtual Members Members { get; set; }
    public int MemberNo { get; set; }

}

public class FeeTypes
{
    public int Id { get; set; }
    [Display(Name = "Fee Name")]
    public string FeeTypeName { get; set; }



}

Controller Action

    public ActionResult AddFees(Fees fees)
    {
        string result;
        Members members = db.Members.Find(fees.MemberNo);
        ViewBag.Fees = db.Fees
        .Include(x => x.FeeType)
        .Where(x => x.Members.MemberNo.Equals(x.MemberNo));

        ViewBag.FeeTypesId = new SelectList(db.FeeTypes, "Id", "FeeTypeName");
        if (ModelState.IsValid)
        {

            db.Fees.Add(fees);

            db.SaveChanges();

            return PartialView("~/Views/Members/_MemberDetails.cshtml", members);

        }

        ViewBag.MemberNo = new SelectList(db.Members, "MemberNo", "FirstName", fees.MemberNo);
        result = "Something went wrong!";
        return Json(result, JsonRequestBehavior.AllowGet);

    }

AJAX Post

        saveBtn.click(function () {
            var token = $('[name=__RequestVerificationToken]').val();
            var postData = {
                __RequestVerificationToken: token,
                FeeOccurence: feeOccField.val(),
                FeeAmount: amountField.val(),
                FeeStatus: statusField.val(),
                FeeTypesId: typeField.val(),
                FeeDate: dateField.val(),
                MemberNo: memberNo
            };
            $.ajax({
                url: '/Members/AddFees',
                type: 'POST',
                data: postData,
                success: function (members) {
                    alert(result);
                    $("#details").html(members);
                },
                error: function (result) {
                    alert(result);
                },
                traditional: true
            });

Partial view

    @using AccPortal.Models
    @model AccPortal.Models.Members

        <h5 class="md-fees-title">Fees</h5>
        <table cellpadding="0" cellspacing="0" class="md-fees-table">
            <thead>


                <tr>
                    <th>@Html.LabelFor(model => model.Fees.First().FeeDate)</th>
                    <th>@Html.LabelFor(model => model.Fees.First().FeeOccurence)</th>
                    <th>@Html.LabelFor(model => model.Fees.First().FeeTypesId)</th>
                    <th>@Html.LabelFor(model => model.Fees.First().FeeStatus)</th>
                    <th>@Html.LabelFor(model => model.Fees.First().FeeAmount)</th>
                    <th></th>
                </tr>

            </thead>
            <tbody>
                @{ int i = 0; }
                @foreach (var item in Model.Fees)
                {

                    <tr data-id="@i">
                        @Html.HiddenFor(model => model.Fees.ElementAt(i).FeeNo, new { @class = "md-fee-value", name = "md-fee-id", data_type = "testid", id = "testid" })
                        <td class="md-fee-value" data-type="date">@String.Format("{0:d}", item.FeeDate)</td>
                        <td class="md-fee-value" data-type="occ">@item.FeeOccurence.GetDisplayName()</td>
//ERROR HAPPENS ON THE NEXT LINE WHEN IT CANT FIND FEETYPES
                        <td class="md-fee-value" data-type="type">@item.FeeType.FeeTypeName</td>
                        <td class="md-fee-value" data-type="status">@item.FeeStatus</td>
                        <td class="md-fee-value" data-type="amount">@item.FeeAmount</td>
                        <td>
                            <button type="button" class="md-button md-button--edit" title="edit">
                                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
                            </button>
                            <button type="button" class="md-button md-button--remove" title="remove">
                                <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
                            </button>
                        </td>
                    </tr>
                    i++;
                }



            </tbody>

Top level view

@using AccPortal.Models
@using Newtonsoft.Json
@model AccPortal.Models.Members

@{
    ViewBag.Title = "Details";
    @Styles.Render("~/Content/jqueryui")
}




<h2>Details</h2>

<div>
    <h4>Members Details</h4>
<hr />
</div>
<div class="row">

    <div class="col-md-7 md-fees" id ="details">

        @Html.Partial("_MemberDetails")
    </div>

</div>
Catfingers
  • 23
  • 5
  • You have posted far to much irrelevant code (we only need to see the relevant details, not evrey property in every model etc. –  Apr 09 '17 at 09:23
  • And you cannot use a `foreach` loop to generate form controls for a collection (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943)) –  Apr 09 '17 at 09:24
  • And you assigning `Fees` to a `ViewBag` property, not your `members` model. –  Apr 09 '17 at 09:28
  • Good points. I will change the form controls to binding. How is Fees not included in the member model since Fees is in Members? This all works fine (apart from the ajax refresh) if it is done in one parent view however with the addition of the partial view, it no longer works. – Catfingers Apr 09 '17 at 09:45
  • Sorry, but I wont (and I doubt anyone else will) wade through all this code - refer [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) –  Apr 09 '17 at 09:50
  • I was editing the original post to provide a cleaner example as you were writing :). Hopefully it is easier to understand now. The ViewBag properties are there because I can't send a Fees type back to Members obviously. Does calling a partial view ignore ViewBag properties from the initial View? – Catfingers Apr 09 '17 at 09:55
  • What do you mean _I can't send a Fees type back to Members obviously._? (if you generate your view correctly it will bind correctly). And nowhere have you shown where you use the `ViewBag.Fees` property in your partial view. (and then there is other code that makes no sense such as your `ViewBag.MemberNo = new SelectList(...)` code - that is pointless if your returning json) –  Apr 09 '17 at 10:02
  • The views use @Models.Members to display the member details. Fees is a property of Members however you cannot pass a Fees object back to the view without ViewBag as far as im aware. (Conflicting type error). – Catfingers Apr 09 '17 at 10:14
  • Of course you can, but that is a separate issue. And you should be creating view models and stop your dreadful use of `ViewBag`, particularly for your `SelectLists` (and refer [this answer](http://stackoverflow.com/questions/37161202/will-there-be-any-conflict-if-i-specify-the-viewbag-name-to-be-equal-to-the-mode/37162557#37162557) for why you cannot use the same name for the property your using and the `SelectList`) –  Apr 09 '17 at 10:19
  • Then refer [this answer](http://stackoverflow.com/questions/34366305/the-viewdata-item-that-has-the-key-xxx-is-of-type-system-int32-but-must-be-o) for how to use a view model with a `SelectList` for binding to a dropdownlist –  Apr 09 '17 at 10:20
  • I understand the frustration, this is legacy code and I am having a bit of trouble with it as well. I am trying to avoid too much modification as the client has only requested the ajax post and refresh partial view functionality but it looks like I might have to go back and rewrite some significant chunks. Thanks for your time. – Catfingers Apr 09 '17 at 10:27
  • OK so I have spent a few hours trying different things. I stopped using Viewbag and instead and used methods to generate lists and return them. My issue is still the same. I still can't access Members.Fees.FeeType after posting to the controller and returning a member object to the partial view. It still renders correctly on a manual refresh of the parent view. – Catfingers Apr 09 '17 at 14:51

1 Answers1

0

The problem was with lazy loading in the end.

I was able to get the Fees to repopulate the bound Members.Fees.FeeType by adding

        members = db.Members.Find(fees.MemberNo);
        members.Fees = db.Fees.Include(x => x.FeeType).Where(x => x.Members.MemberNo.Equals(x.MemberNo)).ToList();
Catfingers
  • 23
  • 5