My CreateController.cs:
using System.Web.Mvc;
using ClientDAL;
using Services;
using ShardingMvcDemo.Raven;
using ShardingMvcDemo.ViewModels;
namespace ShardingMvcDemo.Controllers
{
public class CreateController : Controller
{
//
// GET: /Create/
public ActionResult Index()
{
return View();
}
//
// POST: /Create/
[HttpPost]
public ActionResult Create(ClientViewModel client)
{
try
{
var ravenDbConnection = new RavenDbConnection(new RavenDbConnectionManager());
var service = new ClientService(ravenDbConnection);
service.AddClient(client.FirstName, client.LastName, client.Country);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
}
My Create/Index.cshtml view:
#model ShardingMvcDemo.ViewModels.ClientViewModel
#{
ViewBag.Title = "Create a client";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Client</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Country)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Country)
#Html.ValidationMessageFor(model => model.Country)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
When I click the submitting button in the form, the [HttpPost] method is not even triggered (checked in debug mode). What am I doing wrong?
It doesn't match your view name. Change it to:
public ActionResult Index(ClientViewModel client)
Perhaps you should try to explicitely define the controller and action in your form's initialization, like so:
#using (Html.BeginForm("Create", "Create")) {
...
In your current setup you're trying to POST to /create/index, instead of /create/create.
Related
I'm trying to pass a ViewModel consisting of the 'List' entity and an array of 'Book' objects to the 'Create' Post method in my controller. The post will return the list but not any books. I'm not sure if I'm setting this up correctly or if I'm using the wrong model for the partial view.
ListWithBooksViewModel:
public class ListWithBooksViewModel
{
public BookList List { get; set; }
public Book[] Books { get; set; }
}
'Create' View:
#model LitList.Models.ListWithBooksViewModel
#using (Html.BeginForm("Create", "List", FormMethod.Post))
{
<div>List Name: #Html.EditorFor(l => l.List.ListName)</div>
<div>Subject of List: #Html.EditorFor(l => l.List.Subject)</div>
Html.RenderPartial("AddBookPartial");
Html.RenderPartial("AddBookPartial");
Html.RenderPartial("AddBookPartial");
<p align="center">
<input type="submit" value="Create List" />
</p>
}
'AddBookPartial' Partial View:
#model LitList.Domain.Entities.Book
#Html.BeginForm()
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.BookName)
<div class="col-md-10">
#Html.EditorFor(model => model.BookName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Author)
<div class="col-md-10">
#Html.EditorFor(model => model.Author)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PublicationYear)
<div class="col-md-10">
#Html.EditorFor(model => model.PublicationYear)
</div>
</div>
</div>
'Create' ActionMethod:
[HttpPost]
public ActionResult Create(ListWithBooksViewModel newList)
{
BookList list = newList.List;
if (ModelState.IsValid)
{
foreach (var b in newList.Books)
{
b.ListRefId = list.ListId;
}
list.Books = newList.Books;
listRepo.SaveList(list);
TempData["message"] = string.Format("{0} has been saved", list.ListName);
return View("Index");
}
else
{
return View("Fail");
}
Sorry but you cannot have "nested forms" or BeginForm inside a BeginForm.
You are nesting the BeginForm inside a PartialView with another BeginForm.
You can refer to this link as additional reference: Html.BeginForm inside of Html.BeginForm MVC3
Plese add the loop and just add on RenderPartial pass your object.
#using (Html.BeginForm("Create", "List", FormMethod.Post))
{
<div>List Name: #Html.EditorFor(l => l.List.ListName)</div>
<div>Subject of List: #Html.EditorFor(l => l.List.Subject)</div>
foreach (var book in Books)
{
Html.RenderPartial("AddBookPartial", book);
}
<p align="center">
<input type="submit" value="Create List" />
</p>
}
I get this problem whenever I save the changes I made when changing the roles of a user:
An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code. Additional
information: The ViewData item that has the key 'URole' is of type
'System.Int32' but must be of type 'IEnumerable
These are the codes of my GET and POST Edit
// GET: /AccountAdmin/Edit/5
public ActionResult Edit(int id)
{
Account account = db.Accounts.Find(id);
if (account == null)
{
return HttpNotFound();
}
RoleDropDownList(account.URole);
return View(account);
}
//
// POST: /AccountAdmin/Edit/5
[HttpPost]
public ActionResult Edit(Account account)
{
try
{
if (ModelState.IsValid)
{
db.Entry(account).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
RoleDropDownList(account.URole);
return View(account);
}
catch (Exception ex)
{
return View(account);
}
}
private void RoleDropDownList(object selectedRole = null)
{
var q = from a in db.Roles
orderby a.RoleID
select a;
ViewBag.URole = new SelectList(q, "RoleID", "UserRole", selectedRole);
}
And this is the Edit View
#model MvcApplication3.Models.Account
#ViewBag.Title = "Edit";
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Account</legend>
<div class="editor-label">
#Html.LabelFor(model => model.AccID)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.AccID)
#Html.ValidationMessageFor(model => model.AccID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.UName)
#Html.ValidationMessageFor(model => model.UName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Pword)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.Pword)
#Html.ValidationMessageFor(model => model.Pword)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.FName)
#Html.ValidationMessageFor(model => model.FName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.LName)
#Html.ValidationMessageFor(model => model.LName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.URole, "Role")
</div>
<div class="editor-field">
#Html.DropDownList("URole", String.Empty)
#Html.ValidationMessageFor(model => model.URole)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts{
<script src="#System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bundles/jqueryval")"></script>
}
What could be the problem? Thanks in advance!
The problem is here.
<div class="editor-field">
#Html.DropDownList("URole", String.Empty)
#Html.ValidationMessageFor(model => model.URole)
</div>
This snippet getting URole from model property. Which may be an integer. So giving expection while enumerating through int. Here is an alternate approach to handle this.
public ActionResult Edit(int id)
{
Account account = db.Accounts.Find(id);
if (account == null)
{
return HttpNotFound();
}
RoleDropDownList(account.URole); // Assuming RoleDropDownList returns a SelectList
return View(account);
}
And then in view.
#Html.DropDownList("URole",ViewBag.Roles as SelectList,string.Empty,
new { #name= "URole" });
I am trying to create a edit page for a viewmodel. The view only shows a control for the string in the view model. How do I get the form to display controls for the other objects? If I manually add controls for the Resource model in the viewmodel the form post the resource as null.
The viewmodel
public class ViewModelResourceReturn
{
public string Teststring { get; set; }
public Resource Resource { get; set; }
public ViewModelResult Result { get; set; }
public List<SelectListItem> RoleCheckboxes { get; set; }
}
The controller
[HttpGet]
public ActionResult AddEditRecord(int? id)
{
ResourceRestApi api = new ResourceRestApi(this);
if (id != null)
{
ViewBag.IsUpdate = true;
ViewModelResourceReturn resource = api.GetResource(id ?? 0);
return PartialView(resource);
}
ViewBag.IsUpdate = false;
return PartialView();
}
The view that is generated
#model Project.ViewModels.ResourceViewModels.ViewModelResourceReturn
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ViewModelResourceReturn</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Teststring)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Teststring)
#Html.ValidationMessageFor(model => model.Teststring)
</div>
#Html.EditorFor(m => m.Resource)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Editor Template:
#model Project.Models.Resource
#{
Layout = null;
}
#Html.HiddenFor(model => model.ResourceId)
<div class="editor-label">
#Html.LabelFor(model => model.EmailAddress)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.EmailAddress)
#Html.ValidationMessageFor(model => model.EmailAddress)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FullName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FullName)
#Html.ValidationMessageFor(model => model.FullName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TimeManagerResourceId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TimeManagerResourceId)
#Html.ValidationMessageFor(model => model.TimeManagerResourceId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TravelManagerResourceId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TravelManagerResourceId)
#Html.ValidationMessageFor(model => model.TravelManagerResourceId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OvertimeManagerResourceId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OvertimeManagerResourceId)
#Html.ValidationMessageFor(model => model.OvertimeManagerResourceId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AbsenceManagerResourceId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AbsenceManagerResourceId)
#Html.ValidationMessageFor(model => model.AbsenceManagerResourceId)
</div>
Edit:
[HttpPost]
public ActionResult AddEditRecord(ViewModelResourceReturn resource)
{
return PartialView(resource);
}
You have to create the editors for the other properties. It cannot guess how to render the complex ones.
You can use #Html.EditorFor(m => m.Resource) and create an editor template for the Resource type
EDIT: In the POST action, try renaming the parameter to something other than resource. It may cause the model binder to panic a little.
I have a form with a submit button on a registration page that will not work when pressed, have been at it for a while now? I put a break point on the creat method and it doesn't get called
This is the Creat Metod in the controller
public ActionResult Create()
{
return View();
}
//
// POST: /RegsterDetails/Create
[HttpPost]
public ActionResult Create(User user )
{
if(ModelState.IsValid)
try
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("RegisterStats", "RegisterStats");
}
catch(Exception)
{
return View();
}
return View(user);
This is The View
#model Fitness_Friend.Web.Models.User
#{
ViewBag.Title = "RegisterDetails";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>RegisterDetails</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DOB)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DOB)
#Html.ValidationMessageFor(model => model.DOB)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address)
#Html.ValidationMessageFor(model => model.Address)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Gender)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Gender)
#Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<p>
<input type="Submit" name="Create" value="Register Details" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index","Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
For some reason, your form is not hooking up to your action properly. In order to eliminate some of the possibilities for what is going on, I suggest that you actually specify what Action and Controller the form will use to post to.
#Html.BeginForm("CreateUser", "ControllerWithCreateUserMethod")
{
//insert your HTML here.
//submit button here
<input type="submit" value="Submit"/>
}
In a HTML form, you need a submit button to post the data, like this
<input type="submit" value="Submit"/>
or
<button type="submit">Submit</button>
If you don't like those, you can choose something like this
<a onclick="$('#formId').submit();">Submit</a>
and of course you can optionally specify in form tag where the data is to be posted
#Html.BeginForm("Action", "Controller")
{
...
}
I've duplicated this code as below:
Controller + Model (bad design don't do this):
public class HomeController : Controller
{
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(MyUser user)
{
// break point next line works
if (ModelState.IsValid)
try
{
//db.Users.Add(user);
//db.SaveChanges();
return RedirectToAction("RegisterStats", "RegisterStats");
}
catch (Exception)
{
return View();
}
return View(user);
}
public class MyUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
With this view:
#model MvcApplication3.Controllers.HomeController.MyUser
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<p>
<input type="Submit" name="Create" value="Register Details" />
</p>
</fieldset>
}
And it works without issue.
I'm very late to this but I think I know why this Controller Method doesn't get called.
If a form is passing the data for a Model back to the controller, then the Model class needs to have a constructor which takes no parameters. I'm willing to bet that in the above example
the class User does not have such a constructor.
Here is my Controller:
public class MatchManagerController : Controller
{
//
// GET: /MatchManager/
public ActionResult Index()
{
return View();
}
public ActionResult CreateMatch()
{
return View();
}
}
Here is my View:
#model MatchGaming.Models.MatchModel
#{
ViewBag.Title = "CreateMatch";
}
CreateMatch
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
MatchModel
<div class="editor-label">
#Html.LabelFor(model => model.MatchName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MatchName)
#Html.ValidationMessageFor(model => model.MatchName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MatchDescription)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MatchDescription)
#Html.ValidationMessageFor(model => model.MatchDescription)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Wager)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Wager)
#Html.ValidationMessageFor(model => model.Wager)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MatchTypeId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MatchTypeId)
#Html.ValidationMessageFor(model => model.MatchTypeId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I want my MatchTypeId to be a drop down that populates from my table MatchTypes.
I'm assuming that you have a MatchTypes table in your database that has Id filed and Description field. You want to display a drop down that will show different MatchType descriptions.
Include a field in you model that returns collection of MatchTypes records from the MatchTypes table. Then instead of LabelFor do this:
#Html.DropDownListFor(m => m.Description, Model.MatchTypes)