First of all, am I the only developer on the planet that is attempting to use MVC with VB? I have searched tons of forums and read many posts and everyone that asks a question gives an example in C#. Anyway, now that I've got that out of the way, I've got a simple database table (User) with some columns (UserId, Username, FirstName, LastName). I am using the entity framework and on my edit view, I'm changing a value (Username) and clicking Save. In my Edit http post, I tell it to return to the Index and the value was not saved. Although, in my constructor for the http post, I return the object and it shows the new value...but that value doesn't make it to the db...any help?
My Controller:
Function Edit(ByVal ID As Guid) As ActionResult
'get the user
Dim usr = (From u In db.Users
Where u.UserId = ID
Select u).Single
Return View(usr)
End Function
<HttpPost()> _
Function Edit(ByVal ID As Guid, ByVal usrInfo As User, ByVal formValues As FormCollection) As ActionResult
' Dim usr As User = db.Users.Single(Function(u) u.UserId = ID)
If ModelState.IsValid Then
TryUpdateModel(usrInfo, "User")
Return RedirectToAction("Index")
Else
Return View(usrInfo)
End If
End Function
My view:
<h2>Edit</h2>
<%-- The following line works around an ASP.NET compiler warning --%>
<%: ""%>
<% Using Html.BeginForm() %>
<%: Html.ValidationSummary(True) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.UserId) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.UserId) %>
<%: Html.ValidationMessageFor(Function(model) model.UserId) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Username) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.Username) %>
<%: Html.ValidationMessageFor(Function(model) model.Username) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.FirstName) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.FirstName) %>
<%: Html.ValidationMessageFor(Function(model) model.FirstName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.LastName) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.LastName) %>
<%: Html.ValidationMessageFor(Function(model) model.LastName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.CreatedDate) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.CreatedDate, String.Format("{0:g}", Model.CreatedDate)) %>
<%: Html.ValidationMessageFor(Function(model) model.CreatedDate) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.CreatedBy) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.CreatedBy) %>
<%: Html.ValidationMessageFor(Function(model) model.CreatedBy) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.LastLogin) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.LastLogin, String.Format("{0:g}", Model.LastLogin)) %>
<%: Html.ValidationMessageFor(Function(model) model.LastLogin) %>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% End Using %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
Ok, so, aparently I AM the only VB developer using MVC. Anyway, I found the answer. It was in one of the beginner tutorials for MVC on the ASP.Net Site (Found Here). The answer was to change my Edit function (HttpPost) so that it utilizes the formvalues that were posted:
<HttpPost()> _
Function Edit(ByVal id As Guid, ByVal collection As FormCollection) As ActionResult
Dim rest = (From r In db.Restaurants
Where r.RestaurantId = id
Select r).Single()
Try
TryUpdateModel(rest, collection.ToValueProvider())
db.SaveChanges()
Return RedirectToAction("Index")
Catch
Return View(rest)
End Try
End Function
Related
//UPDATE : Described problem occurs only in Firefox Browser
I've written small app in mvc 2.0, which uses aspnetdb to manage users and standard Account controllers / views etc.
My problem is when i try to change password for user sometimes after typing old password and putting new password, another window opens where i can (?) choose user to change password.
It is very strange, it happens only to some users in application while for other it works quite fine.
Could anyone give me any suggestion what's going on ?
Update:
I don't know whats the difference at first I thought it depends on roles they have defined in application but then this pattern failed.
I don't use any js here
My controller actions looks like:
[Authorize]
public ActionResult ChangePassword()
{
ViewData["PasswordLength"] = this.MembershipService.MinPasswordLength;
return View();
}
[Authorize]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model)
{
if (ModelState.IsValid)
{
if (this.MembershipService.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword))
{
return RedirectToAction("ChangePasswordSuccess");
}
else
{
ModelState.AddModelError(String.Empty, "Błędne hasło aktualne lub nowe nie spełnia wymagań.");
}
}
// If we got this far, something failed, redisplay form
ViewData["PasswordLength"] = this.MembershipService.MinPasswordLength;
return View(model);
}
And ChangePassword.aspx
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<TheApp.Web.Models.ChangePasswordModel>" %>
<asp:Content ID="changePasswordTitle" ContentPlaceHolderID="TitleContent" runat="server">
Change Password
</asp:Content>
<asp:Content ID="changePasswordContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>Change Password</h2>
<p>
Min password length: <%= Html.Encode(ViewData["PasswordLength"]) %>.
</p>
<% using (Html.BeginForm()) { %>
<%= Html.ValidationSummary(true, "Message.") %>
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
<%= Html.LabelFor(m => m.OldPassword) %>
<%= Html.HiddenFor(m => m.UserName) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.OldPassword) %>
<%= Html.ValidationMessageFor(m => m.OldPassword) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(m => m.NewPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.NewPassword) %>
<%= Html.ValidationMessageFor(m => m.NewPassword) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(m => m.ConfirmPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.ConfirmPassword) %>
<%= Html.ValidationMessageFor(m => m.ConfirmPassword) %>
</div>
<p>
<input type="submit" value="Change Password" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
... and weird window with users list (which is incomplete btw) shows even before
public ActionResult ChangePassword(ChangePasswordModel model)
invocation.
I've added in my view autocomplete="off" in all input fields and it helped :)
Yet another compile error for me:
Error 1 'Model' conflicts with the declaration 'System.Web.Mvc.ViewUserControl.Model' c:\Users\Kevin\Documents\Visual Studio 2010\Projects\HandiGamer\HandiGamer\Views\Shared\EditorTemplates\AdminGameReviewViewModel.ascx 10 51 HandiGamer.WebUI
I'm trying to use a partial view to handle both Create and Edit functionality. So, my Create view is:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<HandiGamer.WebUI.ViewModels.AdminGameReviewViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Create New Review
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Create New Review</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Create New Review</legend>
<%: Html.EditorForModel() %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to Menu", "Index") %>
</div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="CSSandJavaScript" runat="server">
</asp:Content>
And the partial view is:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<HandiGamer.WebUI.ViewModels.AdminGameReviewViewModel>" %>
<p>
<%: Html.Label("Game Title") %>
<%: Html.TextBoxFor(Model => Model.GameData.GameTitle) %>
<%: Html.ValidationMessageFor(Model => Model.GameData.GameTitle) %>
</p>
<p>
<%: Html.LabelFor(Model => Model.GameData.Genre) %>
<%: Html.DropDownList("Genre", new SelectList(Model.AllGenres, "GenreID", "Name", Model.GameData.GenreID)) %>
</p>
<p>
<%: Html.Label("Platforms") %><br />
<% for (int i = 0; i < Model.AllPlatforms.Count(); ++i) { %>
<%: Model.AllPlatforms[i].Platform.Name %> <%: Html.CheckBoxFor(plat => plat.AllPlatforms[i].IsSelected)%><br />
<% } %>
</p>
<p>
<%: Html.Label("Review Title") %>
<%: Html.TextBoxFor(model => model.GameData.Content.Title) %>
</p>
<p>
<%: Html.Label("Review") %>
<%: Html.TextAreaFor(model => model.GameData.Content.Text) %>
</p>
<p>
<%: Html.Label("Review Score") %>
<%: Html.DropDownList("Score", new SelectList(new int[] {1, 2, 3, 4, 5}, "ReviewScore")) %>
</p>
<p>
<%: Html.LabelFor(model => model.GameData.Pros) %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %>
</p>
The line in question is the one that attempts to create the first DropDownList, specifically when I write Model.AllGeneres. That invocation of Model is what's throwing the error. It's confusing since none of the other attempts to access Model trigger an error.
The first few html helpers in your partial are using the capital 'Model' instead of lowercase 'model' for the lambda parameter. You have
<%: Html.TextBoxFor(Model => Model.GameData.GameTitle) %>
But it should be
<%: Html.TextBoxFor(model => model.GameData.GameTitle) %>
I've got a model which contains a List of QuestionEditModel for which I want to use an EditorFor.
Normally, I would just call EditorFor on the collection and MVC will do the rest. However, I need the individual QuestionEditModel to use different EditorTemplates depending on the value of a field within the object.
I would've thought that the method for doing this would be something like
<%: Html.EditorFor(model=>model.Questions), [fieldname from individual question] %>
but I cannot figure out how to tell it to look at the Question which is currently selected and use the EntryType field from the question to determine which EditorTemplate to use.
So I tried this
<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions)
{
Html.EditorFor(q=>qem, qem.EntryType, null);
} %>
but this doesn't render anything on to the page. The odd thing is that if I set a breakpoint and run over the code, this does call the correct EditorTemplate, the correct model data is passed in and there are no exceptions, but it just doesn't render anything.
Is there some additional work I need to do in this scenario to get the rendered EditorTemplate back in to my page?
EDIT:
Full code of the Edit View.
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<%: Html.HiddenFor(model=>model.AcadPeriod) %>
<%: Html.HiddenFor(model=>model.ReviewID) %>
<%: Html.HiddenFor(model=>model.ReviewName) %>
<%: Html.HiddenFor(model=>model.CategoryID) %>
<%: Html.HiddenFor(model=>model.CategoryName) %>
<%-- Categories not getting returned in model for some reason. Use EditorFor or DisplayFor instead of loop? --%>
<%: Html.HiddenFor(model=>model.Categories) %>
<%: Html.HiddenFor(model=>model.ClassificationID) %>
<%: Html.HiddenFor(model=>model.ClassificationName) %>
<div style="width:100%">
<div style="float:left">
<ul style="list-style-type:none">
<% for (int i = 0; i < Model.Categories.Count(); i++)
{ %>
<li style="background-color:Gray; border: 1px solid black; padding: 3px 3px 3px 3px; margin-bottom: 2px">
<%: Html.ActionLink(Model.Categories[i].name, "Edit", new { AcadPeriod = Model.AcadPeriod, ClassificationID=Model.ClassificationID, ReviewID=Model.ReviewID, CategoryID=Model.Categories[i].category_id })%>
</li>
<% }%>
</ul>
</div>
</div>
<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %>
<%: Html.EditorFor(q=>qem, qem.EntryType,null); %>
<% } %>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
EDIT 2:
Complete View, Controller, and Template code as requested.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Reviewer.Models.ReviewEditModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h1><%: Model.AcadPeriod %> > <%: Model.ClassificationName %> > <%: Model.ReviewName %></h1>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<%: Html.HiddenFor(model=>model.AcadPeriod) %>
<%: Html.HiddenFor(model=>model.ReviewID) %>
<%: Html.HiddenFor(model=>model.ReviewName) %>
<%: Html.HiddenFor(model=>model.CategoryID) %>
<%: Html.HiddenFor(model=>model.CategoryName) %>
<%-- Categories not getting returned in model for some reason. Use EditorFor or DisplayFor instead of loop? --%>
<%: Html.HiddenFor(model=>model.Categories) %>
<%: Html.HiddenFor(model=>model.Questions) %>
<%: Html.HiddenFor(model=>model.ClassificationID) %>
<%: Html.HiddenFor(model=>model.ClassificationName) %>
<div style="width:100%">
<div style="float:left;width: 15%">
<ul style="list-style-type:none">
<% for (int i = 0; i < Model.Categories.Count(); i++)
{ %>
<li style="background-color:Gray; border: 1px solid black; padding: 3px 3px 3px 3px; margin-bottom: 2px">
<%: Html.ActionLink(Model.Categories[i].name, "Edit", new { AcadPeriod = Model.AcadPeriod, ClassificationID=Model.ClassificationID, ReviewID=Model.ReviewID, CategoryID=Model.Categories[i].category_id })%>
</li>
<% }%>
</ul>
</div>
<div style="float:left; width: 80%; margin-left: 5px">
<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %>
<%: Html.EditorFor(q=>qem, qem.EntryType,null) %>
<% } %>
</div>
</div>
<div style="clear:both" />
<p>
<input type="submit" value="Save" />
</p>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
Editor Template:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Reviewer.Models.QuestionEditModel>" %>
<div style="width:100%; border: 1px solid black">
<div style="width: 100%; border: 1px solid black"><h2><%: Model.QuestionName %></h2></div>
<div style="width:25%; display:inline; border: 1px solid black; float:left">
<%: Model.QuestionText %>
</div>
<div style="width:70%; border: 1px solid black; float:left">
<%: Html.TextAreaFor(model=>model.Answer) %>
<%:Html.ValidationMessageFor(model=>model.Answer) %>
</div>
<div style="clear:both" />
</div>
<fieldset>
<legend>TEXT</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.QuestionID) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.QuestionID) %>
<%: Html.ValidationMessageFor(model => model.QuestionID) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.QuestionName) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.QuestionName) %>
<%: Html.ValidationMessageFor(model => model.QuestionName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.QuestionText) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.QuestionText) %>
<%: Html.ValidationMessageFor(model => model.QuestionText) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.DefaultText) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.DefaultText) %>
<%: Html.ValidationMessageFor(model => model.DefaultText) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.EntryType) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.EntryType) %>
<%: Html.ValidationMessageFor(model => model.EntryType) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.HelpText) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.HelpText) %>
<%: Html.ValidationMessageFor(model => model.HelpText) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Answer) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Answer) %>
<%: Html.ValidationMessageFor(model => model.Answer) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.OptionValue) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.OptionValue) %>
<%: Html.ValidationMessageFor(model => model.OptionValue) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.completedBy) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.completedBy) %>
<%: Html.ValidationMessageFor(model => model.completedBy) %>
</div>
Option Required: <%:Html.TextBoxFor(model=>model.OptionRequired) %>
Answer Required: <%: Html.TextBoxFor(model=>Model.AnswerRequired) %>
</fieldset>
Edit(GET) Action:
public ActionResult Edit(string AcadPeriod, string ClassificationID, string ReviewID, int CategoryID)
{
Reviewer.Models.ReviewEditModel dset1 = rr.GetReviewEditModel(AcadPeriod, ReviewID, CategoryID.ToString(), ClassificationID);
return View(dset1);
}
Edit(POST) Action:
[HttpPost]
public ActionResult Edit(Reviewer.Models.ReviewEditModel model)
{
try
{
foreach (Reviewer.Models.QuestionEditModel qem in model.Questions)
{
if (qem.Answer == null || qem.OptionValue == null) { qem.completedBy = this.HttpContext.User.Identity.Name; }
}
if (ModelState.IsValid)
{
rr.SaveReviewEditModel(model);
return RedirectToAction("Index");
}
else { return View(model); }
}
catch
{
return View(model);
}
}
You have to tell it what to actually render (<%: %>):
<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %>
<%: Html.EditorFor(q=>qem, qem.EntryType, null) %>
<% } %>
I got one problem with showing error message to element.
Is there any option to turn on messages on place where is Html.ValidationMessageFor(model => model.ConfirmPassword). Becsoue for me it isn’t show up. I would like to have summary and near field information too not only red border. Any one know how to do it?
using (Ajax.BeginForm("CreateValidForm", "Test", new AjaxOptions { HttpMethod = "Post" })) {%> <div id="validationSummary1">
<%= Html.ValidationSummary(true)%> </div> <fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.Name)%>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Name)%>
<%= Html.ValidationMessageFor(model => model.Name)%>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Email)%>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Email)%>
<%= Html.ValidationMessageFor(model => model.Email)%>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Password)%>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Password)%>
<%= Html.ValidationMessageFor(model => model.Password)%>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.ConfirmPassword)%>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.ConfirmPassword)%>
<%= Html.ValidationMessageFor(model => model.ConfirmPassword)%>
</div>
<p>
<input type="submit" value="Create" />
</p> </fieldset> <% } %> <%= Html.ClientSideValidation<ValidModel>()
.UseValidationSummary("validationSummary1", "Please fix the following problems:") %>
Here is link for sample project http://www.sendspace.com/file/m9gl54 .
Table Product
Product Id
Product Name
Table Supplier
SupplierId
ProductId
SupplierName
When I create a New Product, I want to have a textbox to enter a supplier as well on the same view. Is this a good practice? Since Product can have many Suppliers, I want to be able to add more Supplier records from the same view. How do I do that?
I am trying to figure out what do I put in the aspx page?
If I put something like <%= Html.TextBoxFor(model => model.Supplier) %> I see a textbox with System.Data.Objects.DataClasses.EntityCollection`1[MyProject.Mvc.Models.Supplier] in it.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MyProject.Mvc.Models.ProductFormViewModel>" %>
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.ProductId) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.ProductId) %>
<%= Html.ValidationMessageFor(model => model.Product.ProductId) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.ProductName) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.ProductName) %>
<%= Html.ValidationMessageFor(model => model.Product.ProductName) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Product.Description) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Product.Description) %>
<%= Html.ValidationMessageFor(model => model.Product.Description) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
ProductViewModel
public class ProductFormViewModel
{
public Product Product{ get; private set; }
public IEnumerable<Supplier> Supplier { get; private set; }
public ProductFormViewModel()
{
Product = new Product();
}
public ProductFormViewModel(Product product)
{
Product = product;
Supplier = product.Supplier;
}
}
I think you will find Steven Sanderson's blogpost about editing variable length lists in ASP.NET MVC 2 really useful. He also has another blogpost about validating such a list.