5

I have a controller which returns a Partial View with a Model.

The view that contains the partial View has a button, When clicking on the button, a function of the controller is called and it returns the same partial View with the model updated. The new model is loaded without any problem, but the page doesn't reload, the view is the same view as before the onclik.

The code of partial View

<div class="well">
    @if (publication.Coments != null) {
         foreach (var comments in publication.Coments) {
             <div class="row">
                  <div class="col-md-12">
                       <a href="../../Client/ProfilePerNick?nick=@comments.Nick">@comments.Nick</a>
                       <span class="pull-right">@comments.DateComment.ToShortDateString()</span>
                       <p>@comments.Message</p>
                   </div>
              </div>
         }
    }
</div>

The method of controller return the partial view with the next code :

   ViewData["publication"] = publication;
   return PartialView("details_comment");

I call the partial view in the view :

 @Html.Partial("../Home/ListPublication")

I debugged the page and the model is reloaded ok, but the partial view doesn't reload.

Ignacio Chiazzo
  • 947
  • 11
  • 25

4 Answers4

4

I mentioned on the comments I was having the same issue but later today I figured at MSDN that this is an expected behaviour if you are returning the same model and view types after a POST. For my scenario I had to use ModelState.Clear() before changing any values on the returning view model. To explain a little better, I'll try to describe my case as close as I can remember to try to contextualize:

view models

// ~/Models/SomeFeatureModels.cs
public class SomeViewModel {
    public int Id {get;set;}
    public string SomeField{get;set;}
    public string SomeOtherField{get;set;}
    public DateTime CreatedOn{get;set;}
}
public class SomeOtherViewModel {
    public int Id {get;set;}
    public string SomeField{get;set;}
    public string SomeOtherField{get;set;}
    public DateTime CreatedOn{get;set;}
}
public class IndexViewModel {
    public string FeatureTitle{get;set;}
}

templates

<!-- ~/Views/Some/SomeInfo.cshtml -->
@model.App.Models.SomeInfoViewModel
@using(Html.BeginForm("AddSomeInfo", "Some", FormMethod.Post, new { @id="frmAddSomeInfo" }) {
  <div id="some-info">
    @Html.DisplayFor(m=>m.SomeField)
    @Html.EditorFor(m=>m.SomeField)
    @Html.ValidatorFor...
    <input type="submit">Go</input>
  </div>
}

<!-- ~/Views/Some/SomeInfo.cshtml -->
@model.App.Models.SomeOtherInfoViewModel 
@using(Html.BeginForm("AddSomeOtherInfo", "Some", FormMethod.Post, new { @id="frmAddSomeOtherInfo" }) {
  <div id="some-other-info">
    @Html.DisplayFor(m=>m.SomeField)
    @Html.EditorFor(m=>m.SomeField)
    @Html.ValidatorFor...
    <input type="submit">Go</input>
  </div>
}

<!-- ~/Views/Some/Index.cshtml -->
@model App.Models.IndexViewModel
@{
   layout: "someLayout.cshtml"
}
<h2>Model.FeatureTitle</h2>

@{ RenderAction("SomeInfo") }
@{ RenderAction("SomeOtherInfo") }

@section scripts {
//bundle must include:
// jquery, jquery.unobtrusive.ajax, jquery.validate, jquery.validate.unobtrusive
<script>
    $(function() {
        $('#frmAddSomeInfo').submit(function(e) {

            e.preventDefault(); 

            var form = $(this);
            if (form.valid()) {
                $.ajax({
                    url: form.action,
                    type: form.method,
                    data: form.serialize()
                }).done(function(payload) {
                    $('#some-info').html(payload);
                }).fail(function(jqXHR, error, errorThrown) {
                    // handle
                });
            }
        });

        $('#frmAddSomeOtherInfo').submit(function(e) {

            e.preventDefault(); 

            var form = $(this);
            if (form.valid()) {
                $.ajax({
                    url: form.action,
                    type: form.method,
                    data: form.serialize()
                }).done(function(payload) {
                    $('#some-other-info').html(payload);
                }).fail(function(jqXHR, error, errorThrown) {
                    // handle
                });
            }
        });
    });
</script>
}

controller

// ~/Controllers/SomeController.cs
public class SomeController: Controller {
    // This would be the landing view of a given controller
    public ActionResult Index() {
        // for this view model I have basically typed the things that 
        // are a concern of Index, like page title and other things
        // but nothing related to the view models that I will be
        // updating or inserting
        var viewModel = somePrivateMethodToBuildMyViewModel();
        return View(viewModel);
    }

    public PartialViewResult SomeInfo() {
        // this is technically a fresh instance with normalized
        // or localized default data that I will be sending 
        // when the index requests this partial view
        var someViewModel = somePrivateMethodToBuildSomeViewModel();
        return PartialView(someViewModel);
    }

    [HttpPost]
    public PartialViewResult AddSomeInfo(SomeViewModel viewModel) {
        // this is where I am checking if my view model is alright
        // and then the "issue" will occur
        if (!ModelState.IsValid) {
            // ... handle  
        } else { 
            // I was doing "normal stuff" like 
            // translating view model to an entity (let's call it model)
            // committing changes with some ORM and get and id and timestamp back
            // and naturally assign these values to the view model 

            viewModel.Id = model.id;
            viewModel.createdOn = model.created_on; 
        }
        // then return the same view and same model **types** of the request
        return PartialView("SomeInfo", viewModel);
    }
}

This is the part that I had to use ModelState.Clear(). I've changed my POST action to this:

// ~/Controllers/SomeController.cs
public class SomeController: Controller {

    // ...        

    [HttpPost]
    public PartialViewResult AddSomeInfo(SomeViewModel viewModel) { 
        if (!ModelState.IsValid) {
            // ... handle  
        } else {  

            // Included this line for valid model state handling
            ModelState.Clear();

            // then persist, etc

            // then change view model
            viewModel.Id = model.id;
            viewModel.createdOn = model.created_on; 
        }
        // then returning the view model to the same partial should now work
        return PartialView("SomeInfo", viewModel);
    }
}

Sorry this got a little too much, but I just wanted to show how I got it working on my scenario.

MilkyWayJoe
  • 9,082
  • 2
  • 38
  • 53
  • This might not be the exact thing, as I don't remember the whole code. If I remember I'll check it against my actual code – MilkyWayJoe Jun 02 '15 at 01:45
  • This could be the problem as on postback the values are binded to model state – KrishnaDhungana Jun 02 '15 at 02:37
  • @KrishnaDhungana Could you expand on that? I'm not using Entity Framework so I think I'm ok. – MilkyWayJoe Jun 02 '15 at 15:01
  • Wow, had that issue, googled it, first result, just read `ModelState.Clear()` here and added it to my code. This resolved my issue, without even reading the question details or answer explanation. But I guess I know now what the problem was. Thank you! Solutions should always be so quick and easy… PS: Still applies to ASP.NET Core MVC. – ygoe Sep 15 '20 at 21:36
2

Try like below.

return PartialView("details_comment", publication);
emy
  • 664
  • 1
  • 9
  • 22
0

You need to pass the model's object with the partial view to see the value, as your model will get bound with the helpers to create a view

return PartialView("details_comment",publication);
Tushar Gupta
  • 15,504
  • 1
  • 29
  • 47
0

Updated

Instead of relative URL:

Try: @Html.Partial(@"~/Views/Home/ListPublication.cshtml") or use 
@{Html.RenderPartial("ListPublication");} 

The other thing I noticed is that you are using old ViewData. I am not saying you should not use it at all but a better approach is to use a strongly typed ViewModel. A View Model is a class that will have necessary properties and logic for your view to render. So you could have a class:

public class PublicationVM{public Publication publication {get; set;} }

and can have other necessary properties if needed by the view. SO has lot of information about using View Model. Please check What is ViewModel in MVC?

Community
  • 1
  • 1
KrishnaDhungana
  • 2,604
  • 4
  • 25
  • 37
  • @IgnacioChiazzo how does your model looks like in you partial view? – KrishnaDhungana May 25 '15 at 05:02
  • @IgnacioChiazzo I am suspecting your partial view does not have a model as you are using viewdata to send model to your view and use it. You have to change it slightly. ??? – KrishnaDhungana May 25 '15 at 05:06
  • 1
    The model is ok, in the partial view if I use a Breakpoint in the Line @if (publication.Coments != null) I can see the model is ok (publication was reload succesfully) but the partial view doesnt reload. – Ignacio Chiazzo May 25 '15 at 05:14
  • I'm having the same issue and I have tried this but also doesn't work. I have actually hard-coded the view model before passing to `PartialView(string, object)` – MilkyWayJoe Jun 01 '15 at 19:50
  • @MilkyWayJoe could you post a question with code so that I can have a look at it? – KrishnaDhungana Jun 01 '15 at 22:54
  • I think I've figured out. Not sure if this is the same scenario as the author of the question, but I've added my solution just in case – MilkyWayJoe Jun 02 '15 at 01:41