Amit Kaushal
Amit Kaushal

Reputation: 439

render partial view through ajax

I have a dashboard view. In this dashboard I want to render number of partial views. I started this exercise just for learning purpose. Actually I am not sure what I am doing wrong. Here is my code:

My DashboardController:

public ActionResult DashboardIndex()
        {
            return View();
        }

        public ActionResult DebitAndCreditExpensesPV()
        {
            DashboardModel objGet = new DashboardModel();
            DashboardViewModel objVM = new DashboardViewModel();
            DateTime date = new DateTime();
            objVM.StartDate = new DateTime(date.Year, date.Month, 1);
            objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
            objVM.ExpenseType = objGet.GetExpensesByDebitAndCredit(objVM.StartDate, objVM.EndDate);
            return PartialView(objVM);
        }

My DashboardIndex.cshtml

@model GPI.ViewModel.DashboardViewModel
@{
    ViewBag.Title = "DashboardIndex";
}


<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="col-md-4">
                   @{
                       Html.RenderPartial("DebitAndCreditExpensesPV");
               }
            </div>
            <div class="col-md-8"></div>
        </div>
    </div>
</div>

<script>
    $(document).ready(function () {

        $.ajax({

            type: "get",
            url: "/Dashboard/DebitAndCreditExpensesPV",
            data: {
                'startDate': $('#StartDate').val(),
                'endDate': $('#EndDate').val()
            },
            dataType: 'json',
            success: function () {
                alert('success');
            },
            error: function () {
                alert('failure');
            }
        });
    });
</script>

DashboardModel.cs

public class DashboardViewModel
    {
        public double ExpenseAmount { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public ExpenseList ExpenseType { get; set; } 
    }

    public class ExpenseList 
    {
        public double TotalDebits { get; set; }
        public double TotalCredits { get; set; }
    }

My Partial View: DebitAndCreditExpensesPV.cshtml

@model GPI.ViewModel.DashboardViewModel
<div class="row">
    <div class="col-sm-4 col-md-12">
        <div class="stat-panel">
            <div class="stat-row">
                <div class="stat-cell bg-pa-purple padding-sm">
                    <div class="col-xs-6">
                        <div class="text-xs" style="margin-bottom:5px;">
                            Debit EXPENSES
                        </div>
                        <div style="width:100%;display:inline-block;margin-bottom:-2px;position:relative;">
                            <span class="text-xlg">
                                <span class="text-lg text-slim">&#8377;</span>
                                <strong>@Model.ExpenseType.TotalDebits</strong>
                            </span>
                        </div>
                    </div>
                    <div class="col-xs-6">
                        <div class="text-xs" style="margin-bottom:5px;">
                            Credit EXPENSES
                        </div>
                        <div style="width:100%;display:inline-block;margin-bottom:-2px;position:relative;">
                            <span class="text-xlg">
                                <span class="text-lg text-slim">&#8377;</span>
                                <strong>@Model.ExpenseType.TotalCredits</strong>
                            </span>
                        </div>
                    </div>

                </div>
            </div>
            <div class="stat-row">
                <div class="stat-counters bordered no-border-t text-center">
                    <div class="stat-cell col-xs-12 padding-sm">
                        <div class="input-daterange input-group" id="datepicker">
                            @Html.TextBoxFor(m => m.StartDate,"{0:d}", new { @class = "input-sm form-control" })
                            <span class="input-group-addon">to</span>
                            @Html.TextBoxFor(m => m.EndDate, "{0:d}", new { @class = "input-sm form-control" })
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

I put two break points in my controller: one at 'DashboardIndex' action and other at 'DebitAndCreditExpensesPV'. The first one executes but later one does not. After first breakpoint, I got 'object null reference ' exception in my partial view at this line <strong>@Model.ExpenseType.TotalDebits</strong>.

I want to know why second breakpoint is not executing. I this break point executes, I can not get this exception. Please tell me where I am going wrong.

Upvotes: 1

Views: 1964

Answers (1)

Shyju
Shyju

Reputation: 218702

In the RenderPartial method, you are calling the DebitAndCreditExpensesPv partial view. This view is strongly typed to your DashboardViewModel and you are using different properties of this Model inside the view (Ex :Model.ExpenseType.TotalDebits).

But in your Index view, you are not passing any model object to your RenderPartial method. If you do not pass any object in this method, It will try to use the Model of the parent view(Index). In your case, You Index view does not have any model, So the essentially the Model which the partial view now has is NULL. You are trying to access the ExpenseType property of NULL and that is the reason you are getting the exception.

Even if you fix your index view to pass the model, You are doing it twice. Once via RenderPartial and again you are making a call to the DebitAndCreditExpensesPV method via ajax on the document ready event. May be you can get rid of the RenderPartial call.

So in your index view, Add a div to show the result of the ajax call.

<div id="divDebitAndCredit"></div>

And your script to load the markup to this div. I removed the datatype:"json" as we do not want receive the data in json format.

$(function () {

    $.ajax({
        type: "get",
        url: "@Url.Action("DebitAndCreditExpensesPV","Home")",
        data: {
            'startDate': $('#StartDate').val(),
            'endDate': $('#EndDate').val()
        },           
        success: function (r) {
            $("#divDebitAndCredit").html(r);
        },
        error: function (a,b,c) {
            alert('Error ! See browser console');
            console.log(b,c);
        }
    });

});

Now in the above code, you are trying to send the startDate and endDate to the action method. So update your action method to accept those.

public ActionResult DebitAndCreditExpensesPV(DateTime? startDate,DateTime? endDate)
{          
    DashboardViewModel objVM = new DashboardViewModel();
    DateTime date = DateTime.Now; 
    if(startDate!=null)
    {
        objVM.StartDate = startDate.Value;
    }
    else
    {
        objVM.StartDate = new DateTime(date.Year, date.Month, 1);
    }
    if(endDate!=null)
    {
        objVM.EndDate = endDate.Value;
    }
    else
    {
        objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
    }       
        objVM.ExpenseType = new ExpenseList { TotalCredits = 45.00, TotalDebits = 634.00 };
    return PartialView(objVM);
}

But the startDate and endDate input fields are part of the partial view. so when you make the ajax call in the ready event of the index view, those fields won't be part of your page. You can either keep the Partial view inside our div and pass a DashboardViewModel object to the Partial view

@model DashboardViewModel
<div id="divDebitAndCredit">
    @{ Html.RenderPartial("DebitAndCreditExpensesPV",Model) }
</div>

This means your Index action should send an object of DashboardViewModel to the index view with whatever default values you want to render.

public ActionResult Index()
{
    var objVM = new DashboardViewModel();
    DateTime date = DateTime.Now;
    objVM.StartDate = new DateTime(date.Year, date.Month, 1);
    objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
    objVM.ExpenseType = new ExpenseList { TotalCredits = 45.00, TotalDebits = 634.00 };

    return View(objVM);
}

Upvotes: 1

Related Questions