11
votes

I have a partial view in MVC that goes something like:

<div id="comments">
    ...
</div>

Inside that div there's a form that calls a controller using AJAX and gets back that same partial view. The problem is that the results of calling the view replaces the contents of the div, not the whole div, and I end up with:

<div id="comments">
    <div id="comments">
        ...
    </div>
</div>

The only solution I can think about with my week of experience in ASP.Net MVC and AJAX is to put the div outside the partial view and make the partial view only contain the inside part, but then the form would refer to an id outside the view where the form is located breaking the little encapsulation I have left there. Is there any better solution?

6

6 Answers

6
votes

The unobtrusive Ajax library that ships with .NET MVC 3 uses callbacks that are based on the four callbacks from jQuery.ajax. However, the InsertionMode = InsertionMode.Replace from the Ajax.BeginForm method does not result in jQuery's replaceWith being called. Instead, .html(data) is used to replace the contents of the target element (and not the element itself).

I have described a solution to this problem on my blog: http://buildingwebapps.blogspot.com/2011/11/jquerys-replacewith-and-using-it-to.html

3
votes

Are you using an AjaxHelper.Form or jQuery. If you are using jQuery, have you tried using replaceWith()? Using AjaxHelper are you using AjaxOptions { InsertionMode = InsertionMode.Replace }? I would think that using either you would be able to replace the entire DIV with the results from the partial view.

3
votes

Using

AjaxOptions { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace } 

should replace the whole content of '#myDiv' element, as tvanfosson says. Your problem is where is '#myDiv' located. Here's an example:

<div id="myDiv">
    <% Html.RenderPartial("MyPartialView"); %>
</div>

where MyPartialView is:

<div id="comments">
    <% using (Ajax.BeginForm(new AjaxOptions() { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace } )) {%>        
    ...
    <input type="submit" value="Submit comment" />
    <% } %>
</div>

If you include '#myDiv' div inside the partial view, it will be rendered right after receiving the response (together with its content), and then it's content will be replace with the response which is the same partial view (including its own '#myDiv' div), and that's why you always end up with 2 nested divs.

You should always use a container for your partial views and then set the UpdateTargetId to the container id.

Edit: I updated the code to represent the exact situation you describe in your question.

2
votes

I had this same problem in Asp.Net MVC 5.

I did not want the PartialView to have some knowledge about what div it might be contained within, so I did not accept that work around.

Then, I noticed the other answers referring to ReplaceWith and found the simple solution:

InsertionMode = InsertionMode.ReplaceWith

Now, the mvc partial view can completely replace itself with the ajax helpers without having any dependencies on names outside itself.

1
votes

Your should try with jQuery too (from my answer on MS MVC form AJAXifying techniques):

<script type="text/javascript">
    $(document).ready(function() {
        ajaxify($('div#comments'));
    });

    function ajaxify(divWithForm) {
        var form = $('form', divWithForm);
        $(':submit', form).click(function (event) {
            event.preventDefault();
            $.post(form.attr('action'), form.serialize(),
                function(data, status) {
                    if(status == 'success') {
                        var newDivWithForm = $(data);
                        ajaxify(newDivWithForm);
                        divWithForm.after(newDivWithForm).remove();
                    }
                }
            );
        });
    }
</script>
0
votes

Did you solved the problem? I had the same issue but I found this:

http://buildingwebapps.blogspot.ro/2011/11/jquerys-replacewith-and-using-it-to.html

I hope it helps you.