TextBoxFor is not refreshing after postback - c#

I'm probably making a stupid mistake somewhere. I would appreciate your help in the following.
I have sample MVC3 application with a single editable field that is displayed to user with TextBoxFor method. In the Index(POST) action I change the value but it still remains the same. What am I doing wrong?
My code:
Model:
public class TestModel
{
public string Name { get; set; }
}
View:
using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Name)
<input type="submit" />
}
Controller:
public ActionResult Index()
{
return View("Index", new TestModel() { Name = "Before post" });
}
[HttpPost]
public ActionResult Index(TestModel model)
{
model.Name = "After post";
return View("Index", model);
}
If I replace TextBoxFor with TextBox or DisplayTextFor then it works correctly.

I believe you must call ModelState.Clear() inside your [HttpPost] action, before you set the new value.
According to this answer, which has a very good explanation: How to update the textbox value #Html.TextBoxFor(m => m.MvcGridModel.Rows[j].Id)
See this too: ASP.NET MVC 3 Ajax.BeginForm and Html.TextBoxFor does not reflect changes done on the server
Although it seems you're not using Ajax.BeginForm, the behavior is the same.
Including an example as suggested by #Scheien:
[HttpPost]
public ActionResult Index(TestModel model)
{
ModelState.Clear();
model.Name = "After post";
return View("Index", model);
}

Related

POST controller action method is having a NULL ViewModel parameter

My POST controller isn't able to capture the ViewModel parameter I set and I'm very confused as I have a different set of POST controller and it can capture the ViewModel parameter.
My code looks like this,
View Page
#model MyProject.Web.ViewModels.MyViewModel
#{
ViewBag.Title = "Home";
ViewBag.Description = "My Project";
ViewBag.SubDescription = "My Project Tool";
Layout = null;
}
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Filter)
<input type="submit" class="btn btn-primary btn-inline-right input-tab" value="Search" />
}
Controller
using MyProject.Web.ViewModels;
[HttpGet]
[Route("Home/Index")]
public async Task<ActionResult> Index()
{
...await API integration code here...
return View(MyViewModel);
}
[HttpPost]
[Route("Home/Index/{viewmodel}")]
public ActionResult Index(MyViewModel viewmodel) <-- all properties of viewmodel are NULL
{
return View();
}
View Model
using MyProject.Web.Models;
using System.Collections.Generic;
namespace MyProject.Web.ViewModels
{
public class MyViewModel
{
public User UserInfo;
public List<Client> Clients;
public string Filter;
}
}
I feel this is a very small mistake, maybe due to overlooking too much. Hopefully someone could take a look and help.
The problem is with the route you have defined on the top of your Post action [Route("Home/Index/{viewmodel}")]
You don't need that {viewmodel} in that URL as you are not posting anything in the query string, you are posting a complex object inside the body of your HTTP Post.
Remove that route and it should work.
also, ASP.NET mvc maps the inputs to the Model properties based upon the name attributes on them like <input name="abc"> will map this input to a property named abc on a ViewModel or just a parameter. In your case #Html.TextBoxFor(m => m.Filter) does that automatically.
Hope this helps.
use this I hope useful:
#using (Html.BeginForm("Index", "HomeController", FormMethod.Post))
Change from public string Filter to property public string Filter {get;set;}
and change route to [Route("Home/Index")] instead of [Route("Home/Index/{viewmodel}")].
I tested and it worked.
public class MyViewModel
{
public User UserInfo { get; set; }
public List<Client> Clients { get; set; }
public string Filter { get; set; }
}
[HttpPost]
[Route("Home/Index")]
public ActionResult Index(MyViewModel viewmodel)
{
return View();
}

ASP #Html.HiddenFor not posting data

So I've got a simple model called BaseModel that has properties all models need. Like for example my Provider class.
public Provider Provider { get; set; }
And I have a SearchModel that derives from BaseModel. It just has an extra string and list.
Now in my html file I have this:
In the top I declared my model:
#model SearchModel
And in my page, I have this form.
#using (Html.BeginForm("Search", "Home", FormMethod.Post))
{
#Html.EditorFor(model => model.SearchText)
#Html.HiddenFor(model => model.Provider)
<button id="BtnSearch" type="submit">Search</button>
}
And finally this is my controller:
public ActionResult Search(SearchModel model)
{
Session["Provider"] = model.Provider;
if (!string.IsNullOrEmpty(model.SearchText)) model.Search();
return View(model);
}
Only what seems to happen is, Provider is null when it reaches my POST action. The weird thing is, it worked in the past and I don't recall changing anything.

MVC3 : Overriding the Model values in HTTPPost action method

I am trying to learn MVC3. I have used TextBoxFor HTML helper control to persist the value over multiple post backs.
Surprisingly the value is persisting, but not reflecting in the view.
My Model class looks like this :
public class FileViewModel
{
public string FileName { get; set; }
public string ValidationMsg { get; set; }
}
My Actions methods in controller looks something like this :
public ActionResult DemoFormElements()
{
return View();
}
[HttpPost]
public ActionResult DemoFormElements(FileViewModel fVM)
{
fVM.FileName = "Overridden Text" + fVM.FileName ;
return View(fVM);
}
My View looks like this :
#using (#Html.BeginForm())
{
if (Model != null)
{
#Html.LabelFor(b => b.FileName)
#Html.TextBoxFor(n => n.FileName, Model.FileName)
}
else
{
#Html.LabelFor(b => b.FileName)
#Html.TextBoxFor(n => n.FileName)
}
<input type="submit" id="SubmitBtn" value="Ok" />
}
When I post back by clicking the OK button, I am able to get the value what I entered in the
textbox, but in the controller I am trying to append that value to "Hi" & expecting the appended value in my view, which is not happening...
I am seeing the value of the control is persisting (whatever I ve entered), but not changing :(
Please help me with giving some clue if its an expected behavior or I m doing any mistake here?
There are a couple of problems with this. You can't overwrite the values in the model during a postback because MVC will override that and retain the old values in order to redisplay them in the case of an error. You also should not, generally speaking, be returning a view from the POST handler, you should use a PRG (Post - Redirect - Get) pattern. That's done so that if the user clicks Refresh in their browser it doesn't POST again. So, having said all that, I would change the controller as follows:
public ActionResult DemoFormElements()
{
var viewModel = new FileViewModel();
if( TempData.ContainsKey( "UpdatedFilename" )
{
viewModel = TempData["UpdatedFilename"];
}
return View( viewModel );
}
[HttpPost]
public ActionResult DemoFormElements(FileViewModel fVM)
{
TempData["UpdatedFilename"] = "Overridden Text" + fVM.FileName;
return RedirectToAction( "DemoFormElements" );
}
This will also simplify your View because you don't have to do that null check for model, you will always have a model.
#using (#Html.BeginForm())
{
#Html.LabelFor(model => model.FileName)
#Html.TextBoxFor(model => model.FileName)
<input type="submit" id="SubmitBtn" value="Ok" />
}
The straight forward solutions to your problem could be:
In controller Post method, use ModelState.Remove("[Mode's Property Name]") before it is assigned new value with the Controller. Here it should be : ModelState.Remove("FileName");
Or Use ModelState.Clear(): this forces the page to forget all previous values & clears all the previous entries.
Or on the view page, change Html.TextBoxFor() to Html.TextBox() for the particular model property.
Or use PRG pattern : (Post-Redirect-Get pattern) as suggested by Craig above.
Choose one among these alternative solutions which fits to your need.
I would return a viewModel for the get action
public ActionResult Index()
{
return View(new FileViewModel());
}
I would simplify the view to this
<span>#Model.FileName</span>
#using (#Html.BeginForm())
{
#Html.LabelFor(m => m.FileName)
#Html.TextBoxFor(m => m.FileName)
<input type="submit" id="SubmitBtn" value="Ok" />
}
Please also read this
MVC2 TextBoxFor value not updating after submit?

MVC Dropdownlist returns null to HttpPost

My problem is that I am trying to setup a drop down list and when a new item is selected it will update a table of information that I have but every time HttpPost function gets called the parameter is always null. Here is index function of my home controller:
public ActionResult Index()
{
Project[] projects = db.Projects.ToArray();
List<SelectListItem> dropList = new List<SelectListItem>();
BurndownSprintTable[] TableToShow = db.BurndownSprintTables.ToArray();
for (int index = 0; index < projects.Length; ++index)
{
dropList.Add(new SelectListItem { Text = projects[index].Name, Value = projects[index].Id.ToString(), Selected = projects[index].Selected });
if (projects[index].Selected == true)
{
int ProjectId = projects[index].Id;
TableToShow = db.BurndownSprintTables.Where(x => x.ProjectId == ProjectId).ToArray();
}
}
ViewBag.Projects = dropList;
return View(TableToShow);
}
TableToShow is used to show sprint information per project.
Here is the post function:
[HttpPost]
public ActionResult ProjectUpdate(string strProjectId)
{
return View("Index");
}
I realize this post function will cause an error which I believe I can fix on my own but I need strProjectId to not be null.
Here is the html:
#model IEnumerable<TableauConfigWebService.Models.BurndownSprintTable>
#using (Html.BeginForm("ProjectUpdate", "Home", FormMethod.Post))
{
<h5>#Html.DropDownList("Id", (IEnumerable<SelectListItem>)ViewBag.Projects)
<input type="submit" value="Update" /></h5>
}
There is more to it but the rest of the html is setting up a table for the sprint information which works fine.
I have looked around and found a bunch of posts on this but none of them seem to help. I am new to mvc so I know its probably something simple but I cant figure it out.
Thank you for any help.
Change to this
[HttpPost]
public ActionResult ProjectUpdate(string Id)
{
return View("Index");
}
Or change the control Name to
#Html.DropDownList("strProjectId", (IEnumerable<SelectListItem>)ViewBag.Projects)
Try this simple way , and check it ,
Must be same names are dropdown and model property .
But you can try this simple way
[HttpPost]
public ActionResult ProjectUpdate()
{
**string strProjectId=Request.Form["strProjectId"].ToString();**//Or use Request["strProjectId"].ToString();
return View("Index");
}
#Html.DropDownList("**strProjectId**", (IEnumerable<SelectListItem>)ViewBag.Projects)
or
Simply, you can use FormCollection like,
[HttpPost]
public ActionResult ProjectUpdate(FormCollection collection)
{
**string strProjectId=collection["strProjectId"].ToString();**
return View("Index");
}
#Html.DropDownList("**strProjectId**", (IEnumerable<SelectListItem>)ViewBag.Projects)
And check my code with using break points !
Use the same parametre name at both the place in view and controller.
either change in controller.
public ActionResult ProjectUpdate(string Id)
{
return View("Index");
}
or else change in view dropdown code to this.
#Html.DropDownList("strProjectId", (IEnumerable<SelectListItem>)ViewBag.Projects)
hope this helps...

sending a model in mvc3 using html.beginform

I have an HttpPost and HttpGet version of the action method Rate() :
http://pastebin.com/embed_js.php?i=6x0kTdK0
public ActionResult Rate(User user, Classified classified)
{
var model = new RatingModel
{
CurrentUser = user,
RatedClassified = classified,
};
return View(model);
}
[HttpPost]
public ActionResult Rate(RatingModel model)
{
model.RatedClassified.AddRating(model.CurrentUser, model.Rating);
return RedirectToAction("List");
}
The view that HttpGet Rate() returns:
#model WebUI.Models.RatingModel
#{
ViewBag.Title = "Rate";
}
Rate #Model.RatedClassified.Title
#using(Html.BeginForm("Rate","Classified", FormMethod.Post))
{
for (int i = 1; i < 6; i++)
{
Model.Rating = i;
<input type="submit" value="#i" model="#Model"></input>
}
}
I'm trying to find out to send a Model through the Form to the Post method, and my thinking was that the value "model" in the submit button's tag would be the parameter to do so, however null is being passed through if i breakpoint inside of the Post method. The for loop is trying to create 5 buttons to send the proper rating.
Thanks
Them model binding works on the name attribute as #Ragesh suggested you need to specify the name attributes matching the RatingModel properties in the view. Also note that the submit button values dont get posted to the server, there are hacks through which you can achieve that, one way is to include a hidden field.
Also in your provided code the loop runs six times and at the end Model.Rating will be equal to 5 always... what are you trying to achieve?. Say for example you have a model like
public class MyRating{
public string foo{get;set;}
}
in your view
#using(Html.BeginForm("Rate","Classified", FormMethod.Post))
#Html.TextBoxFor(x=>x.foo) //use html helpers to render the markup
<input type="submit" value="Submit"/>
}
now your controller will look like
[HttpPost]
public ActionResult Rate(MyRating model)
{
model.foo // will have what ever you supplied in the view
//return RedirectToAction("List");
}
hope you will get the idea
I think there are two things you need to fix:
The input tag needs a name attribute
The name attribute should be set to model.Rating

Categories

Resources