I am currently working on a strongly-typed update view in ASP.NET MVC2. In addition to properties the user can update, there are also some properties that the user should not be able to update, but I would like to display on the page anyway (for example, a created on date).
Here is an example of how I am displaying these non-editable fields:
<td>Created on:</td>
<td><%= Html.DisplayTextFor(model => model.CreatedOn) %></td>
However, when I submit the form and then use a breakpoint on the controller method to see the model object that is being passed to the method via a POST request, the non-editable fields are set to a null or empty value (for example, the CreatedOn date is set to 1/1/0001). The editable fields are being passed back with the correct values. How can I display these non-editable fields while retaining the original value when I post the form back to the controller?
You don't need the original value. If you use UpdateModel (or TryUpdateModel) you can set which properties should be updated. This solution is also a lot safer because you explicitly tell MVC which properties should be updated.
You would need to use a hidden field like so:
<%= Html.HiddenFor(model => model.CreatedOn) %>
This would be in addition to your display field.
Related
My table has two columns CreatedBy and CreateTime. In my view form, I don't have these fields. Now when I update a record using ASP.NET MVC4 Edit (post) method, these columns are set to null. But I want to retain the values. I know in my Edit (post) method, I can retrieve the record from the database and set these manually. But I am wondering whether I can ask Entity Framework not to change the values of these fields.
No you can't, if you want to keep the old values then you have to get the record first and then manually assign the values that you want to update. The only other way is to go through your entity property by property and tag which ones you want to modify, like so:
db.MyEntity.Attach(myEntity);
db.Entry(myEntity).Property(e => e.MyProperty).IsModified = true;
db.SaveChanges();
either way you end up having to do the manual work yourself.
You have to choices here:
1) As #KennyZ mentioned, add to #Html.HiddenFor() somewhere in your view, into your form:
#Html.HiddenFor(m => m.CreatedBy)
#Html.HiddenFor(m => m.createTime)
2) You can manually update that entity and leave those two properties alone:
var ent = dbctx.Entities.Find(model.ID);
ent.Prop1 = model.Prop1;
// ... also for other properties except those two property
dbctx.SaveChanges();
Sure you can. I assume they are already in your model, just add them to the form with Html.HiddenFor(m => m.createdBy). Now they are in the form but not displayed, and still have values on Post methods.
Is there a way use DataAnnotations to tell Razor to render a DropDownList and populate the choices from a specific field in a specific entity?
Specifically I am capturing a "Calendar Year" property in my View and would like it to be a DropDownList. I am doing this currently by passing the years into my view via the ViewBag and then calling "DropDownListFor". I was hoping for a way to define it in my ViewModel and them simply call "EditorFor".
Thanks!
I can't find a way to do it with a DataAnnotation, but you don't need to use the ViewBag, you could pass the values in, like this:
#Html.ListBoxFor(m => m.SelectedFoos, Model.AllFoos.Select(f => new SelectListItem { Text = f.Name, Value = f.ID }))
(Note: This uses ListBox, taken from an answer here, but should be similar for DropDownList).
I created a class that implements the IModelBinder interface. Within a method of that class I basically retrieve some values and try to validate them. If the validation fails, I add update the model state with necessary information like below:
DateTime mydate;
if (!DateTime.TryParse(convValue,out mydate))
{
bindingContext.ModelState.AddModelError("Date", "Date was crap");
}
The problem is that Html.ValidationMessageFor(m => m.Model) returns no value. I looked at the MVC source code and found out that a proper key with id "Date" can't be found in the ModelState dictionary.
Why is that ? The controller that returns the view have access to the model state and can enumerate over ModelState.Errors
Thanks,
Thomas
Is "Date" the name of the property you are validating?
The first parameter of ModelState.AddModelError should either be the name of the property you want the validation message to display for, or left as string.Empty if you only want the error to display in in the validation summary.
If you want to display an error message that isn't tied to a specific property of your viewmodel, you could call <%: Html.ValidationMessage("Date") %> in your view to display that particular message if it has been set.
Edit: just realised how old this question is. Ah well, might come in handy anyway...
I have a form that will have dynamically created elements, one of those will be of date type. There can also be many fields of this type on my form, all which must be validated.
I am using a strongly typed view in Asp MVC, so the name will change based on various factors. What I would like to do is validate based on a class name instead, since that will be constant for that type of field.
Ie:
<%= Html.TextBox("questionAnswers[" + index + "].AnswerValue", qa.AnswerValue, new { #class = "DateTypeClass" })%>
So then I would need JQuery validation based on the classname DateTypeClass versus the Name.
Any ideas?
In your validation function you could check the value like so:
var dateFieldValue = $(".DateTypeClass").val();
//validate dateFieldValue here
Also you don't have to resort to selecting by class if you don't want to. If no other fields share this validation then you could select by partial id in jquery. That would look like this:
var dateFieldValue = $("[id^=someId]").val();
//validate dateFieldValue here
So you would if set someId on the field and ASP.Net adds some additional stuff to the id it will still select it properly. I don't use ASP.Net MVC so not sure where you are setting the ID (if at all)
Also if you want inline validation you can wireup the onBlur event like so:
$(".DateTypeClass").blur(function(){
//Call field validation function here
});
OK, let's start with the Html.Textbox. It is supposed to contain text read from a file. The file read is based on what the user picks from a dropdown list.
The first time it is fine. The user picks a value from the dropdown list. The controller uses that value to read some text from a file, and returns that text to the view via the view model. Everything is fine.
THen the user picks another value from the dropdown list. The controller reads a new value from a file and returns it via the view model. Debugging to the LINE BEFORE THE HTML.TEXTBOX is set in the view shows that the model contains the correct value. However, the textbox itself still shows the PREVIOUS value when the page displays!
If I switch from Html.Textbox to a plain input, type="text" html control, everything works fine. That's not so hard, but the same thing happens with my dropdown list -- I can't set the selected value in code. It always reverts to whatever was chosen last. Rendering a "select" tag with a dynamically-generated option list is a pain. I would love to be able to use Html.Dropdown.
What am I missing here?? This is such a simple thing in webforms!
When you post a form, the values that are posted are put into ModelState. When the HtmlHelper renders an html iunput element, e.g. Html.TextBoxFor(x => x.FirstName), it'll search various locations to get the value for the textbox... ModelState is before ViewData.Model in the list of locations. So there for, the previously posted value will appear in your textbox.
To fix this you could clear the ModelState value or update the ModelState value. BUT I would kinda view that as a hacky way of getting around the problem.
The real issue has more to do with the flow of the posts and requests. I would personally look into that and maybe implement the PRG (Post Redirect Get) pattern.
HTHs,
Charles
Following on from what Charles/Charlino said:
Model binding updates the ModelState object, which contains validation and model binding errors that are collected during model binding.
Inside an action method, model binding has occurred already to update the model, and generated the ModelState object. If you now update the value on the model inside the action, you must also manually update the model state (since the helpers use it to generate their HTML). Below is an example:
model.CaptchaIsValid = CaptchaService.ValidateAndExpireCaptcha(model.CaptchaAttempt);
if (!model.CaptchaIsValid)
{
ModelState.AddModelError("CaptchaAttempt", "Incorrect - please try again");
}
// I'll clear the value on each attempt, to force them to re-enter a CAPTCHA.
model.CaptchaAttempt = string.Empty;
// Since I updated the model, I must create a new ValueProvider result...
ValueProviderResult clearedValue = new ValueProviderResult(
model.CaptchaAttempt,
model.CaptchaAttempt,
CultureInfo.CurrentCulture);
// ... and update the ModelState's value.
ModelState.SetModelValue("CaptchaAttempt", clearedValue);
The biggest issue I see here is that you are trying to do a postback within MVC. That model is really not supported, and is actually way more trouble than it is worth (as it seems you are finding out). I would recommend using Ajax to update the contents of the dropdown dynamically.