Change model property in post request asp.net mvc - c#

I have one problem.
This is short example.
This is model.
public class MyModel
{
string Title{get;set;}
}
In view I write
#Html.TextBoxFor(model => model.Title)
This is controller.
public ActionResult EditNews(int id)
{
var model = new MyModel;
MyModel.Title = "SomeTitle"
return View("News/Edit", model);
}
//for post
[HttpPost]
public ActionResult EditNews(MyModel model)
{
//There is problem.When I do postback and
// change Title in this place,Title doesn't change in view textbox
//Only when I reload page it change.
model.Title = "NEWTITLE"
return View("News/Edit", model);
}

It won't change because by default (many think this is a bug) MVC will ignore the changes you make to the model in a HttpPost when you're returning the same View. Instead, it looks in the ModelState for the value that was originally served to the view.
In order to prevent this, you need to clear the ModelState, which you can do at the top of your HttpPost by doing:
ModelState.Clear();

Related

Accessing model from razor view in MVC

I have the following code in controller and razor view.
When Upload() is called I want to return another view with the model as the parameter so it's accessible within the view.
But I keep getting "Object reference not set to an instance of an object" on #Model.PhoneNumber
Another question is that does the model has to be strongly typed? It seems when I pass in new { PhoneNumber = "123456" } the property can't be accessed from view either.
[HttpGet]
[Route("{code}/CertificateValidation")]
public ActionResult CertificateValidation()
{
return View();
}
[HttpPost]
public ActionResult Upload(FormCollection file)
{
return View("CertificateValidation", new IndexViewModel { PhoneNumber = "123456" });
}
View:
model WebApplicationMVC.Models.IndexViewModel
<p>#Model.PhoneNumber </p>
Problem is with your get Method.
Your following method does not return any model. So Model is null so it gives error.
[HttpGet]
[Route("{code}/CertificateValidation")]
public ActionResult CertificateValidation()
{
var model = new IndexViewModel();
return View(model);
}
The way you are returning the view with the model is correct and should not have any issue.
return View("CertificateValidation", new IndexViewModel { PhoneNumber = "123456" });
That said, most probably your actual code would not be like this and might be fetching data from some source like a database probable, which could be returning null which you can investigate by debugging or writing null checks.
For the second answer, if you are specifying the type of the model in the view with the #model directive, you have to provide an instance of this type in the return View() method call. Alternatively you can use the #model dynamic which would allow you to pass anything as the model. See this link

Update view after form submit

In my MVC controller I have two action methods.
The first one is Index method:
public IActionResult Index()
{
return PopulateViewModel();
}
The "PopulateViewModel" Action Method is used for updating of the view model and then showing these updated values on the Index view.
public IActionResult PopulateViewModel()
{
ViewModel viewModel = new ViewModel()
{
//updating values in the view model
//the values are received when the form in the view is submitted
};
return View("Index", viewModel);
}
The problem that I have is that on my Index view the updated values are not shown immediately after submitting the form in the view. When I submit the form I must then once again refresh the page to see the updated values.
What could be the reason for such behavior and how can I correct that?
You misunderstand the conceptual notion. The index is supposed to represent the initial page state. Other actions within the controller will modify the output by rendering the page with the adjusted model. Or handling server side model binding, but the concept is fundamentally achieving the same result.
Your controller logic should be within the following constraints.
public class SampleController : Controller
{
public IActionResult Index() => new View("...", ...);
public IActionResult SubmitSample(string location)
{
var model = service.GetLabLocations(location);
return View("...", model);
}
}
The index is simulating a GET request, returning the initial page in the required state. The form portion, should POST data, outlined in the SubmitSample portion of the code. This will change the state of the page, but the server will need to render with those changes. So the page will load with the attached model, for you to display.
This would represent Razor more than likely on the server side.
#if(Model != null)
foreach(var sample in Model)
{
// Markup, with the data
}

ASP.NET MVC HttpPost posting null model

Form posts from webpage MakeBooking to FinalBooking to ascertain certain information such as number of guests, so the FinalBooking page can give you enough textboxes to input guest information for all guests required.
When in debug mode, both models in MakeBooking post are populated. After post, in FinalBooking, model is null.
[HttpPost]
public ActionResult MakeBooking(BookingModel model)
{
return RedirectToAction("FinalBooking", "Booking", new { model = model });
}
public ActionResult FinalBooking(BookingModel model)
{
return View(model);
}
Any info would be appreciated.
It should work
return RedirectToAction("FinalBooking", "Booking", model);
You can not pass a model with RedirectToAction like that. you need to use either TempData or Session to transfer the model object between your calls.
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
The below example shows how to transfer data using TempData.
[HttpPost]
public ActionResult MakeBooking(BookingModel model)
{
TempData["TempBookingModel"]=model;
return RedirectToAction("FinalBooking", "Booking");
}
public ActionResult FinalBooking()
{
var model= TempData["TempBookingModel"] as BookingModel;
return View(model);
}
Internally TempData is using Session as the storage mechanism.

Post method that calls another one for returning the view

In an MVC4 project I need to "refresh" the page depending on some messages that can be present, otherwise I just redirect to a page, and if presenting again the page if them messages are present I would like to avoid just returning the View as it will cause then the double submission when the user tries to refresh it.
What I'm trying to do is this
[HttpGet]
public ActionResult SampleMethod()
{
viewModel = _builder.Build();
return View(viewModel);
}
[HttpPost]
public void SampleMethod(SampleViewModel viewModel)
{
if (ModelState.IsValid)
{
var response = serviceCall;
var errorMessages = response.ErrorMessages;
if (!errorMessages.Any())
{
//Redirect to proper view
}
else
vm = _builder.Build();
}
else vm = _builder.Build(); //There is some validation error I rebuild
CashbackOffersConfirmation(vm);
}
public ActionResult SampleMethodConfirmation(SampleViewModel viewModel)
{
return View("SampleMethod", viewModel);
}
It goes through the process
but the final page is .../SampleMethod instead of .../SampleMethodConfirmation and is blank,
Is this something to do with the routing (quite lost in this)? Is this a correct approach?
Thanks
In order to pass the object model from the view to the controller, you need to make a post request. Make sure you use a form that will generate the post request.
Also make the SampleMethodConfirmation method a post.
E.g.: add [HttpPost] on top of the method in the controller

ASP.NET MVC Url.Action creating Get not Post

I have:
public ActionResult Create(Guid appId)
{
var vm = new CreateViewModel(appId);
return View(vm);
}
[HttpPost]
public ActionResult Create(CreateViewModel vm)
{
// this does some stuff
}
Now, in the View I use this for creating the Form:
#using(Html.BeginForm())
{
}
Standard.
How ever, it produces the wrong HTML:
<form action="/SomeController/Create?appId=414FDS-45F2SF-TEF234">
This is not what I want posted back, I don't want appId what so ever. Just the Create
How do you get around this?
You can use another overload of Html.BeginForm to explicitly specify the action you want:
#using(Html.BeginForm("Create", "SomeController"))
{
}
This will not append anything to the URL by default.

Categories