I have a standard Edit scenario with GET and POST, the form has a Save button and a Lookup button that allows the user to lookup a postcode, which fills out the address and returns it in the form fields. The Lookup button posts back to the Edit controller method.
The following isn't real code but demonstrates my problem...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int CustomerId, string LookupButton)
{
Customer customer = new Customer();
UpdateModel(customer);
//customer.County = "Hello world!";
return View(customer);
...
}
This code does as expected, just returns the existing form data, however when I uncomment the line that manually changes the County field, those changes don't appear on the form. This has thrown me, because in the form
<%= ViewData.Eval("County") %>
will return "Hello world!" but
<%= Html.TextBox("County") %>
still retains the old value!
<input id="County" name="County" type="text" value="" />
Customer is an EF4 class.
Any help much appreciated.
That's because the Html.TextBox first looks in the posted request values and then in the model that you update in your controller. In the posted request values it finds the old value.
Related
I am a newbie and is making web application in Visual Studio 2010 using MVC2 + Entity framework.
I have a situation in which I want to put both operations i.e create user / update user at same view, I have also tried attaching relevant picture where I have made two portions one for create user and second for manage users.
My 'create user' fields are at top of website and when user click 'create button' page got refreshed and all enlisted users gets displayed on same view under second portion 'manage users' showing link to edit/delete them.
I want that when I click on edit link, that particular entity fields get populated on same view in first portion 'create user' where I can modify them and press 'update button'
VIEW
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Admin.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%# Import Namespace="MyNamespace" %>
<h4>Create New User</h4>
<form method="post" action="/Lignum/CUser">
<label for="inputEmail3">Full Name</label>
<input type="text" name="Fullname" id="txtFullname" >
<label for="inputEmail3">Email</label>
<input type="email" name="Email" id="Email1">
<button id="btnCUser" class="btn btn-primary">Create</button>
</form>
<h4>Manage Users</h4>
<table>
<tr>
<td>Sr#</td><td>Name</td><td>Email</td><td></td>
</tr>
<% int i=0;
foreach (MyWebsite.Models.User objUser in ViewData.Model as IEnumerable<MyWebsite.Models.User>)
{%>
<tr>
<td><%= ++i%></td>
<td><%= objUser.Fullname%></td>
<td><%= objUser.Email%></td>
<td>
Edit
</td>
</tr>
<%}%>
</table>
CONTROLLER
public ActionResult Index()
{
return View("UserMgt", _repositoryUser.SelectAll());
}
public ActionResult Edit(object Id)
{
if (Id != null && Id.ToString().Trim().Length > 0)
{
int param = int.Parse(Id.ToString());
return View("UserMgt", _repositoryUser.SelectByID(Id));
}
return View("404");
}
You will need to make use of JQuery & Ajax to achieve this. Your page is getting refreshed most likely because your are submitting a form. Instead of form submit, you need to attach a function to handle onclick event.
In that function you will know which item is clicked, load the data to be edited from the server sending an ajax request with item id.
When request return you can then open a JQuery popup window or update page's html to display data. User will be allowed to make changes and on Ok button click you can again send the data back to server to save.
I am looking for an example online to refer to you as my code is little complex. You can also look for an example online.
UPDATE:
i want that when i click on edit link, that particular entity fields
get populated on same view in 1st portion 'create user' where i can
modify them and press 'update button'
Ok, looked at your code. As I said earlier you will need to define an "id" for each html element, the value will be objUser.UserId (you can prefix something if you want). Now define a click event for all html elements i.e. .
For a working example refer this link.
I suggest you progress as you gain some insight and post updated code. We will suggest what's needed for next step. This way you would learn more.
You can try following:
Create a View model with whatever you need on the create page i.e. user details
strongly bind your view with this view model
Have three action methods in controller "Create","Populate" and "Update" with Update and Populate taking Id of the entity as input (you can choose better names)
Initially call Create method which will just return an empty view model with your View
Have a hidden variable in view which will store the Id of the entity (in case of create this will be zero)
on click of create just take the value of this hidden variable and do a post to Update action method.In this case if it is new entity id will be zero
On click of edit go call Populate method with id of the entity which again will return ViewModel with entity details loaded to the same create view (also set the hidden variable with id)
In your update method based on the id perform create or update operation i.e. Create for zero and Update for 1
If you post your code or other details I can give some more details using code.
EDIT: OK few more details in terms of code.
//This is the view model you need to bind to your view
public class UserViewModel
{
public int UserId { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
public List<Users> UserList {get;set;} //For binding to the grid
}
Below are the action methods in controller.
public ActionResult Create()
{
var viewModel = new UserViewModel();
//Logic: Create empty view model for create
return View("UserMgt", viewModel);
}
public ActionResult Edit(int id)
{
var viewModel = new UserViewModel();
//Logic: populate the view model based on the id
return View("UserMgt", viewModel);
}
// Call this method using Jquery ajax
public bool Update(UserViewModel user)
{
if (user.Id == 0)
//Logic : Create the user
else
//Logic : Edit the user
return Json(status); //Status = true if successful else false
}
Initially call create.On click of edit call Edit method.On click of save call Update.
For using jquery ajax follow below link
http://api.jquery.com/jquery.ajax/
Am almost embarassed that I can't get this to work. I have a model like this:
public class Test
{
public string Test1 {get; set; }
public string Test2 {get; set; }
}
I have a razor view which correctly displays both Test1 and Test2. Test1 is displayed just like this:
#Html.LabelFor(model => mode.Test1)
#Html.Test1
Test2 is displayed like this:
#Html.LabelFor(model => model.Test2)
#Html.EditorFor(model => model.Test2)
i.e. I just want to display Test1, but want the user to be able to edit Test2.
These are within a form:
#using(Hmtl.BeginForm("Action1", "Controller1", FormMethod.Post)
In Controller1.Action1 it receives the model:
public ActionResult Action1(Test m)
{
}
but in here m.Test1 is null, m.Test2 is correctly populated. m.test1 is correctly displayed in the view.
Am confused.com
Thanks in advance,
Ray
The model binder only sees the form values which are posted from the HTML form, which are only from form elements. This doesn't generate such an element:
#Html.Test1
That may display the value to which the view is bound (does it really? I've never seen it done like that, maybe that should be #Model.Test1?) but there needs to be an HTML form element of some kind to post a value back to the server. (input, select, hidden, etc.)
For fun, take a look at the HTML generated in the browser. They're just standard form elements with values, there's nothing storing the whole model anywhere. The model binder just tries to intelligently re-construct a model based on the name/value pairs sent from the HTML form.
Try adding a hidden field to the form as well:
#Html.LabelFor(model => model.Test1)
#Model.Test1
#Html.HiddenFor(model => model.Test1)
This should create an input type="hidden" in the form with that value, which would be included when posting the values to the controller action.
Basically I have a form that I am dynamically adding objects to. I am doing this with AJAX so can just initialise the object and return it with JSON. Each new object has a unique GUID assigned to it so we can identify each object in the model collection when it is passed back into the action.
However, I need to support non JavaScript so am trying to write a solution that will post back the model and add or remove the given object from the model. There can be any number of these new objects on the model so I need to pass back several things to find out which object to delete before returning the model back to the view. This could be either
a) The GUID for the object the user has deleted.
b) The button that has been clicked to identify which object to delete.
The problem is that the partial view is generic and I would like to keep it that way so I'm trying to pass the identifying GUID back with the input button on each partial view but don't know how. I can easily do this with JavaScript because I just remove the created AJAX object from the page before posting it when the user clicks the remove link but can't figure out how to do it with a submit. Basically I want to do something like this:
#using (Project.Namespace.Infrastructure.Helpers.HtmlPrefixScopeExtensions.HtmlFieldPrefixScope _scope = Html.BeginCollectionItem())
{
<ul class="ulMedicationsControl">
#Html.ActionLink("Remove This Object", "RemoveObject", null)
#Html.Input("RemoveObject", "Remove This Object", new { Prefix = _scope.Prefix, objectGUID = IdentifyingGUID })
#Html.HiddenFor(m => m.IdentifyingGUID);
<li class="liQuestion">
#Html.MandatoryLabelFor(m => m.myField)
#Html.TextBoxFor(m => m.myField)
</li>
</ul>
<div id="#(_scope.Prefix).ajaxPlaceholder"></div>
}
In the controller:
[ActionName("FormName")]
[AcceptParameter(Name = "RemoveObject", Value = "Remove This Object")]
public ActionResult RemoveObject(MyParentModel model, string Prefix, string objectGUID)
{
Guid ID = new Guid(objectGUID);
foreach (ObjectModel object in model.objects){
if (object.IdentifyingGUID == ID)
{
model.objects.Remove(object);
break;
}
}
return View(model);
}
Any help I would really appreciate as I simple can't figure out how to do this!
EDIT
Also just to add the prefix attribute simply identifies where in the form the object sits. This will be needed for me to find which object list to go through and remove the object from as there may be several lists in different placed in the model.
An HTML input only passes "name=value" when a form post occurs so that's all you have to work with. With <input type=submit> you're further limited by the fact that the button's value is its caption (i.e. "myControl=Click Me!" is posted), so you can't stick anything programmatically meaningful in the value.
Method 1: So you're left with encoding all the information you need into the input's name - an approach that works fine, but you'll have to have to go digging into the controller action method's FormCollection parameter rather than relying on model binding. For example:
<input name="delete$#(_scope.Prefix)$#objectGUID" type="submit" value="Delete me" />
Better, have a helper class that encapsulates the string format with a ToString override and has Parse/TryParse/etc static methods, which could be used like this:
<input name="#(new DeleteToken{Prefix=_scope.Prefix, objectGUID=IdentifyingGUID})" type="submit" value="Delete me" />
In your action method:
[HttpPost]
public ActionResult Foo(FormCollection formData)
{
var deleteTokens = DeleteToken.ParseAll(formData.AllKeys);
foreach (var token in deleteTokens)
{
//...do the deletion
}
}
Method 2: An alternative approach is to group each item into its own <form> (bear in mind you can't nest forms) - so when the submit happens, only its surrounding form is posted in which you can stash hidden inputs with the necessary data. e.g.
<ul class="ulMedicationsControl">
<form ... >
<!-- hidden field and submit button and whatever else here -->
...
</form>
</ul>
I have a multi-step file import process. I have a hidden form input in my view that I am trying to populate with the "CurrentStep" from the view model.
<% = Html.HiddenFor(model => model.CurrentStep) %>
CurrentStep is an Enum and I always get the default value rather than the one I provided to the view model. on the other hand this gets me the correct value:
<p><% = Model.CurrentStep %></p>
I realise I could just hand code the hidden input but I want to know: what am I doing wrong? Is there a better way to keep track of the current step between POSTs?
What you are doing wrong is that you are trying to modify the value of a POSTed variable in your controller action. So I suppose you are trying to do this:
[HttpPost]
public ActionResult Foo(SomeModel model)
{
model.CurrentStep = Steps.SomeNewValue;
return View(model);
}
and html helpers such as HiddenFor will always first use the POSTed value and after that the value in the model.
So you have a couple of possibilities:
Remove the value from the modelstate:
[HttpPost]
public ActionResult Foo(SomeModel model)
{
ModelState.Remove("CurrentStep");
model.CurrentStep = Steps.SomeNewValue;
return View(model);
}
Manually generate the hidden field
<input type="hidden" name="NextStep" value="<%= Model.CurrentStep %>" />
Write a custom helper which will use the value of your model and not the one that's being POSTed
My solution was to use Darin's second option, because option 1 (clearing from the model state) means hard coding a string (and the naming convention can be tricky with complex models), and wanted to avoid option 3 because I already have so many custom helpers.
<input type="hidden" name="#Html.NameFor(x => Model.SomeId)" value="#Model.SomeId" />
Just a reminder that you can use Html.NameFor to keep things clean.
Make sure you model property has a "set" operator.
This won't get updated on post-back:
#Html.HiddenFor( m => m.NoSeq)
public Class MyModel
{
int _NoSeq;
public NoSeq
{
get { return _NoSeq };
}
}
I have a dropdownlist that I populate with some stuff:
In my controller
ViewData["SourceModelList"] = new SelectList(_modelService.GetAllModels(), "Id", "Description");
in my view
<% using (Html.BeginForm("Compare", "Home")) { %>
<p>
<%=Html.DropDownList("SourceModelList")%>
</p>
<p>
<input type="submit" value="Compare" />
</p>
<% } %>
And this renders lovely. Now when I post back to my 'compare' action, how do I find out which item was selected in the drop down?
The name "SourceModelList" should correspond with the name of a field in your ViewModel, so that the binder has something to bind the value of the dropdown to.
Alternatively, you can pluck the value out of the FormCollection object, if your view is not strongly-typed.
The NerdDinner Tutorial goes into this process in greater detail:
NerdDinner Step 5: Create, Update, Delete Form Scenarios
http://nerddinnerbook.s3.amazonaws.com/Part5.htm
You can use any of the regular methods for getting items from a form in ASP.NET MVC: FormCollection, Request object, binding to a specific model or having an action which takes a string SourceModelList parameter.
You can do:
int value = Convert.ToInt32(Request.Form["SourceModelList"]);
Or by ModelBinders just making sure that your model have a property
public int SourceModelList {get; set;}
And the ModelBinder will get it for you.
Or, but less likely:
public ActionResult Name(FormCollection f, int SourceModelList)