Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

post ignoring Model changes Razor ASP.NET

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/[email protected]">@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.

like image 624
Ignacio Chiazzo Avatar asked May 25 '15 03:05

Ignacio Chiazzo


2 Answers

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.

like image 160
MilkyWayJoe Avatar answered Oct 31 '22 20:10

MilkyWayJoe


Try like below.

return PartialView("details_comment", publication);
like image 2
emy Avatar answered Oct 31 '22 19:10

emy