6
votes

I am currently using an Ajax call on my ASP MVC3 view to append a new list item to the page. The view makes the Ajax call, which calls a controller ViewResult action, which returns the partial view. The Ajax is then set to call the .append(html) method on the <div> element the call originated from.

The problem is that instead of appending the new row, the entire view goes away and only the partial is displayed.

Here is the code in the view. This view uses a view model with a list object of a separate model. This portion of the code calls the partial view to display each of the items in the list object.

@model Monet.ViewModel.BankListViewModel
@using (Html.BeginForm())
{
    <fieldset>
        <legend>Stat(s) Fixed</legend>
        <table>
        <th>State Code</th>
        <th>Agent ID</th>
        <th></th>
            <div class="fixedRows">
                @foreach(var item in Model.Fixed)
                {
                    if (!String.IsNullOrWhiteSpace(item.AgentId))
                    {

                            @Html.Partial("FixedPartialView", item) 

                    }      
                }
            </div>
        </table>
        <br />
        @Html.ActionLink("Add another", "BlankFixedRow", null, new { id = "addFixed"})
    </fieldset>
}

Here is the addFixed Ajax call

$("#addFixed").click(function () {
    $.ajax({
        url: this.href,
        cache: false,
        success: function (html) { $("#fixedRows").append(html); }
    });
    return false;
});

and this is the ViewResult controller action that the Ajax calls

    public ViewResult BlankFixedRow()
    {
        SelectList tmpList = new SelectList(new[] { "AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NA", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "US", "VT", "VI", "VA", "WA", "WV", "WI", "WY" });
        ViewBag.StateCodeList = tmpList;

        return View("FixedPartialView", new BankListAgentId());
    }

Finally, this is the partial view.

@model Monet.Models.BankListAgentId


@using (Html.BeginCollectionItem("Fixed"))
{
    <tr id="[email protected]">
        <td>
            @Html.DropDownListFor(model => model.StateCode,
                (SelectList)ViewBag.StateCodeList, Model.StateCode)
        </td>
        <td>
            @Html.EditorFor(model => model.AgentId)
            @Html.ValidationMessageFor(model => model.AgentId)
        </td>
        <td>
        <a href="#" onclick="$('#[email protected]').parent().remove();" style="float:right;">Delete</a></td>
    </tr>
}

When the Add another link is selected the page goes from looking like this

enter image description here

to this

enter image description here

Per comments below here is the HTML for the page:

<input type="hidden" name="Fixed.index" autocomplete="off" value="6dd1b028-14f7-4400-95d1-a803c2521b68" />
        <tr id="item-">
            <td>
                <select id="Fixed_6dd1b028-14f7-4400-95d1-a803c2521b68__StateCode" name="Fixed[6dd1b028-14f7-4400-95d1-a803c2521b68].StateCode"><option>AL</option>
<option>AK</option>
<option>AS</option>
<option>AZ</option>

.
.
. <-removed list of all 50 states for clarity
</select>
            </td>
            <td>
                <input class="text-box single-line" id="Fixed_6dd1b028-14f7-4400-95d1-a803c2521b68__AgentId" name="Fixed[6dd1b028-14f7-4400-95d1-a803c2521b68].AgentId" type="text" value="" />

            </td>
            <td>
                <a href="#" class="deleteRow">delete</a>
            </td>

        </tr>
                    </section>

EDIT

After reading the comments below I changed the table tag to <table id="fixedRows">, however, this returned the same result. I then changed the success attribute of the Ajax call to include some basic HTML like so

success: function (html) { $("#fixedRows").append("<tr><td>New</td></tr>"); }

but again, got the same result. After setting a breakpoint both in Visual Studio and Chrome's debugger, I was able to see that the Ajax is never being called. Instead the call to the controller action is made, and the partial view is loaded on it's own, instead of being appended to <table id="fixedRows">.

Still working of getting around this, however, if anyone has any ideas. Thx!

4
Is there a reason you want to use Ajax to do the partial call? When you use Ajax you have to remember the state of the previous page in order for Ajax to redisplay the pageRobert
I'm following this blog post: blog.stevensanderson.com/2010/01/28/…NealR
Can you inspect the rendered markup of the table after clicking 'Add another' and post that?Ant P
probably doesn't solve your problem but <div class="fixedRows"> doesn't match your selector $("#fixedRows").append(html)Jasen
Good Question you helped me a lot thanks NealRMustafaP

4 Answers

2
votes

So the reason this was happening wound up being pretty simple. Due to the ActionLink that was being used, the controller action would fire before the jQuery. This was causing the partial view to wipe out the entire Edit view. By binding the jQuery to a hyperlink within a $(document).ready block, the jQuery functioned like normal. Below is the tag and the updated jQuery

<a href="#" class="addFixed">Add Another</a>

jQuery:

$(document).ready(function () {

    $(".addFixed").click(function () {
        //alert('test');
        event.preventDefault();        
        $.ajax({
            url: '@Url.Action("BlankFixedRow", "BankListMaster")',
            cache: false,
            success: function (html) { $("#fixedRows").append(html); }
        });
    });

    $("#addVariable").click(function () {
        event.preventDefault();
        $.ajax({
            url: '@Url.Action("BlankFixedRow", "BankListMaster")',
            cache: false,
            success: function (html) { $("#variableRows").append(html); }
        });
    });

});
0
votes

The only way this could occur with the code you have is if it's not replacing the page content with that simple bit of HTML, but rather directly loading that action in the browser tab. Which your action link will do by default.

  1. Make sure that your click handler for that "Add another" link employs event.preventDefault() or simply returns false; If you don't prevent the default action of the link, you AJAX code will do it's thing, and then the browser will load the link like normal, making it look like it didn't work.

  2. Make sure there's no JavaScript errors on the page. If the JS stops working, then the default behavior, again, will take over and you get the result you see.

0
votes

I think that your usage of divs inside your <table> tags is confusing jQuery.append.

Try the following instead:

<fieldset>
    <legend>Stat(s) Fixed</legend>
    <table id="fixedRows">
        <tr>
            <th>State Code</th>
            <th>Agent ID</th>
        </tr>
        @foreach(var item in Model.Fixed)
        {
            if (!String.IsNullOrWhiteSpace(item.AgentId))
            {
                @Html.Partial("FixedPartialView", item) 
            }      
        }
    </table>
    <br />
    @Html.ActionLink("Add another", "BlankFixedRow", null, new { id = "addFixed"})
</fieldset>

Note, also, that I have used id="fixedRows" instead of class="fixedRows" as this is what you're specifying in your jQuery.

Compare:

0
votes

I try an avoid doing AJAX calls on partial views. AJAX requires you remember the state of the last page in order to redisplay the information. That being said you can go back to the controller and call the partial view and just have the server call display the partial in tandem with your view:

 @Html.Partial("FixedPartialView", new BankListAgentId(){/*Construct the View Model Here here. assign the properties to your view model */  AgentId = /*however your creating this*/})

I do not think AJAX is the way to go with this problem.