MVC4 Pass custom view Model back to Controller Action - asp.net-mvc

I have a custom class
public class BloggerViewModel
{
public Person Blogger;
public List<BloggerWebsite> BloggerWebsites;
}
That I pass into a view
[HttpGet]
public ActionResult Edit(int id)
{
blogger = GetById(id);
var WebSites = GetBloggersWebsites(Id);
var BloggerViewModel = new BloggerViewModel();
BloggerViewModel.Blogger = blogger;
BloggerViewModel.BloggerWebsites = WebSites;
return View(BloggerViewModel);
}
Then when I post back to the edit action
[HttpPost]
public ActionResult Edit(BloggerViewModel entity)
{
return View(entity);
}
entity is null.
My view is something like this ( I took out allot of the code that you didn't need to see. Such as most of the text box bindings)
#model Bloginect.Model.Models.BloggerViewModel
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
#Html.HiddenFor(model => model.Blogger.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.FirstName)
#Html.ValidationMessageFor(model => model.Blogger.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.LastName)
#Html.ValidationMessageFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[0].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website1")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[1].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website2")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[2].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website3")
}
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Is there something I am doing wrong? I have checked out some of the other replies to similar questions on this and they did not answer my question.

You must use editors to handle the bindings to your nested model properties, a good example on how to do it can be found here.

Related

How to retain formcollection values on postback in MVC

Here I am using simple application and on clicking send button I will execute Index httppost action. But for some reason if my captcha is not correct then i am trying to load the same view. I am passing form collection so my firstname and lastname are not wiped out. Please suggest how can i persist my values.
[HttpPost]
public ActionResult Index(FormCollection dataColl)
{
ColComments datgrp = new ColComments();
datgrp.fname = dataColl[0].ToString();
datgrp.lname = dataColl[1].ToString();
if (!this.IsCaptchaValid(""))
{
ViewBag.Classname = "alert alert-warning";
ViewBag.ErrorMessage = "Incorrect captcha answer.";
}
else
{
ViewBag.ErrorMessage = "OKAY";
return RedirectToAction("Landing", "Account");
}
return View(dataColl);
}
Index view.
#using CaptchaMvc.HtmlHelpers
#model CaptchaTestApp.Models.ColComments
#{
ViewBag.Title = "Home Page";
}
<div class="jumbotron">
<h1>ASP.NET</h1>
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
<p>Learn more ยป</p>
</div>
<div>
#using (Html.BeginForm())
{
<div> #Html.ValidationSummary(true)</div>
<fieldset>
<legend>ColComments</legend>
<div class="editor-label">
#Html.LabelFor(model => model.fname)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.fname)
#Html.ValidationMessageFor(model => model.fname)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.lname)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.lname)
#Html.ValidationMessageFor(model => model.lname)
</div>
</fieldset>
<table>
<tr>
<td colspan="3">
#Html.Captcha(8, "_captchaCnt")
</td>
</tr>
</table>
<p>
<input type="submit" value="Send" />
</p>
}
</div>
You need to return the same view which you are sending in HttpGet method with updated values. You are sending form collection object to view.
[HttpPost]
public ActionResult Index(FormCollection dataColl)
{
ColComments datgrp = new ColComments();
datgrp.fname = dataColl[0].ToString();
datgrp.lname = dataColl[1].ToString();
if (!this.IsCaptchaValid(""))
{
ViewBag.Classname = "alert alert-warning";
ViewBag.ErrorMessage = "Incorrect captcha answer.";
}
else
{
ViewBag.ErrorMessage = "OKAY";
return RedirectToAction("Index", "Home");
}
return View(datgrp);
}

ASP.NET MVC: Values are null when they reach the Controller

So I have the following Controller:
[HttpPost]
public ActionResult CreateSupport(CreateSupport model)
{
if (ModelState.IsValid && (model.Description != null))
{
model.CreatedById = UserId;
model.ModifiedById = UserId;
}
return View(model);
}
I have the following view:
#using (Html.BeginForm("CreateSupport", "Support", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend></legend>
<div class="editor-label">
#Html.LabelFor(model => model.Subject, new Dictionary<string, object>() { { "class", "req" } })
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Subject)
#Html.ValidationMessageFor(model => model.Subject)
</div>
<div class="support-form-left">
<div class="editor-label">
#Html.LabelFor(model => model.BrowserInfo, new Dictionary<string, object>() { { "class", "req" } })
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.BrowserInfo)
#Html.ValidationMessageFor(model => model.BrowserInfo)
</div>
</div>
<div class="support-form-right">
<div class="editor-label">
#Html.LabelFor(model => model.DatabaseVersion, new Dictionary<string, object>() { { "class", "req" } })
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.DatabaseVersion)
#Html.ValidationMessageFor(model => model.DatabaseVersion)
</div>
</div>
<div class="clearFloat"></div>
<div class="editor-label">
#Html.LabelFor(model => model.Description, new Dictionary<string, object>() { { "class", "req" } })
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="actionButtons">
<button id="btnCancel" class="myButtonCancel">Cancel</button>
<input type="submit" value="Submit" class="myButton" />
</div>
#if (ViewBag.SuccessMessage != null)
{
<div>
<label style="color: red;">#ViewBag.SuccessMessage</label>
</div>
}
</fieldset>
}
Here's the Model:
public class CreateSupport : SupportTicket
{
public CreateSupport()
{
ProductList = new List<Product>();
ProductVersionsList = new List<ProductVersion>();
EnviromentList = new List<InstallationEnvironment>();
content = new Content();
}
[Required]
[UIHint("tinymce_jquery_full"), AllowHtml]
public string Description { get; set; }
[Required]
[DisplayName("Browser version Info.")]
public string BrowserInfo { get; set; }
[Required]
[DisplayName("Database Version")]
public string DatabaseVersion { get; set; }
public Content content { get; set; }
}
The problem is that the values that reach the Controller are NULL even if you enter some value in them.
You should check your browser's developer tools to see if the form is properly posting its values. If it isn't, you should do two things:
A) Disabled javascript to see if there is a script that is interfering with the POST (typically either by disabling or clearing fields)
B) Ensuring your markup is valid using the W3C markup validation service
For input fields use
#Html.EditorFor(x => x.Subject)
For display fields use
#Html.DisplayFor(x => x.Subject)

MVC file saving and uploading with same button

I have a Upload and Save forms that works but I would like to pass uploaded image and save other data for movies in one button (to merge Save and Upload)
Here is my cshtml Create view:
#model MvcMovie.Models.Movie
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ReleaseDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ReleaseDate)
#Html.ValidationMessageFor(model => model.ReleaseDate)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Genre)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Genre)
#Html.ValidationMessageFor(model => model.Genre)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Rating)
#Html.ValidationMessageFor(model => model.Rating)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ImageUrl)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ImageUrl)
#Html.ValidationMessageFor(model => model.ImageUrl)
</div>
<input type="submit" value="Create" />
</fieldset>
<img src="~/Content/Images/Full/image1.JPG" alt="Sample Image" width="300px" height="200px" />
}
#using (Html.BeginForm("Upload", "Movies", FormMethod.Post, new { enctype="multipart/form-data" }))
{
<input name="ImageUploaded" type="file">
<input type="submit" value="Upload"/>
}
#Html.ActionLink("Back to List", "Index")
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here's my Controller:
public ActionResult Create()
{
return View();
}
//
// POST: /Movies/Create
[HttpPost]
public ActionResult Create(Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index", "Movies");
}
return View(movie);
}
public ActionResult Edit(int id = 0)
{
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
[HttpPost]
public ActionResult Upload(ImageModel model)
{
if (ModelState.IsValid)
{
string fileName = model.ImageUploaded.FileName;
string serverPath = Server.MapPath("~");
string imagesPath = serverPath + "Content\\Images\\";
String fullPath = #"" + "C:/Users/FAZI-7/Desktop/Full/";
String thumbPath = #"" + "C:/Users/FAZI-7/Desktop/Thumb/";
ImageModel.ResizeAndSave(thumbPath, fileName, model.ImageUploaded.InputStream, 80, false);
ImageModel.ResizeAndSave(fullPath, fileName, model.ImageUploaded.InputStream, 600, false);
}
return RedirectToAction("Index", "Movies");
}
I can't make one button for both functions, I have read that I might need to have the same controller action having two parameters, or put all the controls in one form, but how would I do this?
Here's a working example. I think one of the critical pieces you're missing is the enctype parameter on your HTML form element.
Create.shtml
#model ARES.Models.EmployeeViewModel
#{
ViewBag.Title = "Create New Employee";
}
#using (Html.BeginForm("Create", "Employees", FormMethod.Post, new { enctype = "multipart/form-data" })) {
<fieldset class="containedAndCentered">
<div class="editor-label">
Department
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.SelectedDepartmentId, new SelectList(Model.Departments, "department_id", "department_name", Model.SelectedDepartmentId))
#Html.ValidationMessageFor(model => model.Departments)
</div>
<div class="editor-label">
Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.EmployeeName)
#Html.ValidationMessageFor(model => model.EmployeeName)
</div>
<div class="editor-label">
Photo
</div>
<div class="editor-field">
<input type="file" id="EmployeePhoto" name="EmployeePhoto" />
</div>
<div class="editor-field">
#Html.HiddenFor(model => model.EmployeeId)
</div>
<hr />
<div class="controls left">
#Html.ActionLink("Back to List", "Index")
</div>
<div class="controls right">
<input type="submit" value="Create" />
</div>
</fieldset>
}
EmployeesController.cs
namespace ARES.Controllers {
public class EmployeesController : Controller {
private employee_picsEntities db = new employee_picsEntities();
[HttpPost]
public ActionResult Create(EmployeeViewModel evm) {
if (ModelState.IsValid) {
// Find the selected department object.
var department = (from d in db.departments
where d.department_id == evm.SelectedDepartmentId
select d).FirstOrDefault();
employee_master employee_master = new employee_master() {
department = department,
employee_name = evm.EmployeeName,
file_location = evm.EmployeePictureUrl,
status = 1
};
// Add the employee to the collection before we set the file_location field so that we have the neccessary employee_id value.
db.employee_master.Add(employee_master);
db.SaveChanges();
// Save a photo if we were provided with one.
if (evm.EmployeePhoto != null) {
employee_master.file_location = SaveEmployeePhoto(employee_master.employee_id, evm.EmployeePhoto);
}
//db.employee_master.Add(employee_master);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(evm);
}
public string SaveEmployeePhoto(int employeeId, HttpPostedFileBase employeePhoto) {
var basePath = "~/Content/images/photos";
var filename = "";
var path = Server.MapPath(basePath);
var savedFileName = "";
HttpPostedFileBase file = Request.Files[0];
if (file.ContentLength > 0) {
filename = employeeId + Path.GetExtension(file.FileName);
savedFileName = Path.Combine(path, filename);
file.SaveAs(savedFileName);
}
//filename = (basePath + "/" + fileName).ToAbsoluteUrl()
return string.Format("{0}/{1}", basePath, filename).ToAbsoluteUrl();
}
}
}

Hidden ViewModel Property defaulting to 0 when null - should stay null

Get Controller Method:
public ActionResult Create(int? parentId)
{
var model = new CreatePersonViewModel();
// pull set from db
var parent = _db.Persons.FirstOrDefault(s => s.PersonId == parentId);
if (parent != null)
{
model.ParentId = parent.PersonId;
}
return View("Create", model);
}
POST:
public ActionResult Create(CreatePersonViewModel viewModel) // viewModel.ParentId is 0 when it's passed to this method from the view, even though I didn't set it, and it's null coming from GET.
{
//bla bla
}
My View:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>CreatePersonViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
#Html.HiddenFor(model => model.ParentId) // tried with second parameter of "null" as well
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Any idea why the view is sending back a value of 0 in that property for cases when it should be null? I don't have any details to add here but the form validation is asking for more text so here it is.

How do I call submit in mvc app?

I have mvc3 web app.
inside that I have one Enquiry form once I submit that form it should save all data into database for that I have used Entity Framework.
EnquiryController.cs
public class EnquiryController : Controller
{
aspnetdbEntities dbEntities = new aspnetdbEntities();
//
// GET: /Enquiry/
public ActionResult Index()
{
return View();
}
//
// GET: /Enquiry/
public ActionResult Enquiry()
{
return View();
}
//
//POST: /Enquiry/
[HttpPost]
public ActionResult Enquiry(Enquiry enquiry)
{
if (ModelState.IsValid)
{
dbEntities.Enquiries.AddObject(enquiry);
dbEntities.SaveChanges();
return RedirectToAction("Index");
}
return View(enquiry);
}
}
Enquiry.cshtml
#model MyWeb.Models.Enquiry
#{
ViewBag.Title = "Enquiry";
}
<h2>Enquiry</h2>
<div>
<fieldset>
<legend>Enquiry Form</legend>
<div class="editor-label">
#Html.LabelFor(m => m.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.LastName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.LastName)
#Html.ValidationMessageFor(m => m.LastName)
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</div>
But when I clicked on Submit button it is not working no round rip no refresh
please help me where i go wrong i'm newbie.
ashuthinks,
just add the htmlHelper (for forms) to your view:
#using(Html.BeginForm()){
// exisiting fieldset stuff
<fieldset>... bla</fieldset>
}
around your fieldset and you're good to go

Resources