Passing Data View-to-Controller - c#

I've tried several various was to move data from a view to the controller in order to sort a new view, but I am unable to get the data to pass. Here is what I have:
View 1
#model TabCheckout.checkout
#{
ViewBag.Title = "Select the Letter of Your Last Name";
}
<h3>Select the Letter of Your Last Name</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-10">
#{int i = 0;
foreach (string letter in ViewBag.Letters)
{
i++;
if (i == 9)
{
i = 0;
#Html.Raw("<br />")
}
else
{
<input type='submit' id='#letter' name='selectletter' value='#letter' formaction='Names' />
}
}
}
</div>
</div>
</div>
}
Controller
public ActionResult Letters(string selectletter)
{
List<string> letters = new List<string>();
for (int y = 0; y < 26; y++)
{
char filter = Convert.ToChar(65 + y);
string letter = filter.ToString();
letters.Add(letter);
}
ViewBag.Letters = letters;
GlobalVariable.selectletter = Convert.ToString(selectletter);
return View(GlobalVariable.selectletter);
}
public ActionResult Names()
{
// var namesrt = from s in db.users
// select s;
// namesrt = namesrt.Where(s => s.LastName.StartsWith(GlobalVariable.letter));
// ViewBag.UserID = new SelectList(namesrt, "UserID", "FullName", null);
ViewBag.UserID = new SelectList(db.users, "UserID", "FullName", null);
return View();
}
View 2
#model TabCheckout.checkout
#{
ViewBag.Title = "Select Your Name";
}
<h3>Select Your Name - #GlobalVariable.selectletter</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-10">
#{int i = 0;
foreach (var item in ViewBag.UserID as SelectList)
{
i++;
if (i == 9)
{
i = 0;
#Html.Raw("<br />")
}
else
{
<input type="submit" name="#item.Text" value="#item.Text" formaction="Vehicles">
}
}
}
</div>
</div>
</div>
}
I feel like the majority of the problem has to do with my Controller verbiage. I've tried using request name to string, FormCollection, and the current mess.
Thank you for your help and your understanding of my limited skill level.
Here is the model for full disclosure:
Model
namespace TabCheckout
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("NewsData_Tab.checkout")]
public partial class checkout
{
public int CheckoutID { get; set; }
[Required]
public int User { get; set; }
[ForeignKey("User")]
public virtual user users { get; set; }
[Required]
public int Vehicle { get; set; }
[ForeignKey("Vehicle")]
public virtual vehicle vehicles { get; set; }
[Required]
public int Equipment { get; set; }
public DateTime TimeOut { get; set; }
public DateTime TimeIn { get; set; }
public checkout()
{
TimeOut = DateTime.Now;
}
}
public static class GlobalVariable
{
public static string selectletter { get; set; }
}
}

public ActionResult Names(FormCollection form)
{
var letter = form["selectletter"];
ViewBag.UserID = new SelectList(db.users, "UserID", "FullName", null);
return View();
}
It works for me!

Related

Why does my DropDownList repeat same value?

I am getting values from a ViewModel into a view for form fields. In one of my DropDownList the values are correct but in another the value repeats itself instead of changing. What am I doing wrong?
ViewModel:
namespace FulfillmentPortal.ViewModels
{
public class ViewModel
{
[Required(ErrorMessage = "Please select a carrier")]
public List<Carrier> CarrierList { get; set; }
[Required(ErrorMessage = "Please select a service")]
public List<CarrierService> ServiceList { get; set; }
}
}
Controller:
public class FulfillmentController : Controller
{
private CarrierModel db = new CarrierModel();
// GET: Fulfillment
public ActionResult Index()
{
ViewModel vm = new ViewModel
{
CarrierList = db.Carriers.ToList(),
ServiceList = db.CarrierServices.ToList()
};
return View(vm);
}
}
View:
#model FulfillmentPortal.ViewModels.ViewModel
#{
ViewBag.Title = "index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
<div class="panel-heading">REPORT OPTIONS</div>
<div class="panel-body" style="padding-left:35px;">
<form id="processForm" class="form-horizontal" action="~/Fulfillment/Report" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="sel1">Carrier:</label>
#Html.DropDownListFor(model => model.CarrierList, new SelectList(Model.CarrierList, "CarrierId", "CarrierName"), "Select a Carrier",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
<label for="sel2">Carrier Services:</label>
#Html.DropDownListFor(model => model.ServiceList, new SelectList(Model.ServiceList, "Code", "WebName"), "Select a Service",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
</div>
</form>
</div>
</div>
Model:
public partial class CarrierModel : DbContext
{
public CarrierModel()
: base("name=CarrierModel")
{
}
public virtual DbSet<Carrier> Carriers { get; set; }
public virtual DbSet<CarrierService> CarrierServices { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
[HttpPost]
public ActionResult Index(ViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.CarrierList.ToList();
viewModel.ServiceList.ToList();
}
return View(viewModel);
}
This my controller now. Now my view is just erroring out. I think I am missing something or misunderstanding something.
DropDownListFor(model => model.ServiceList
This is not how this method is supposed to work, and I suspect this is the answer to your problem.
This lambda is supposed to provide a field that will hold a value that this drop down list outputs. For your case you should have two fields in the model:
public class ViewModel
...
public int CarrierId { get; set; }
public string CarrierServiceCode { get; set; }
These will hold currently selected value, on none if nothing is selected (yet). And they are supposed to be used in that lambda:
DropDownListFor(model => model.CarrierServiceCode
Alternatively you could use DropDownList() method, which does not require a field in the model, and give it a custom name that will be posted with selected value.
Your ViewModel should be as follows:
public class ViewModel
{
[Required(ErrorMessage = "Please select a carrier")]
public int CarrierId {get; set;}
[Required(ErrorMessage = "Please select a service")]
public int ServiceCode {get; set;}
public List<Carrier> CarrierList { get; set; }
public List<CarrierService> ServiceList { get; set; }
}
Then in the view:
<label for="sel1">Carrier:</label>
#Html.DropDownListFor(model => model.CarrierId, new SelectList(Model.CarrierList, "CarrierId", "CarrierName"), "Select a Carrier",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
<label for="sel2">Carrier Services:</label>
#Html.DropDownListFor(model => model.ServiceCode, new SelectList(Model.ServiceList, "Code", "WebName"), "Select a Service",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
Then your Index Post method should be as follows:
[HttpPost]
public ActionResult Index(ViewModel viewModel)
{
if(ModelState.IsValid)
{
// do whatever you want with `viewModel.CarrierId` and `viewModel.ServiceCode` here
}
viewModel.CarrierList = db.Carriers.ToList();
viewModel.ServiceList = db.CarrierServices.ToList();
return View(viewModel);
}

c# ASP.NET MVC cannot pass model's collection field to controller [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 7 years ago.
I have a class from EF.
public partial class Customer
{
public Customer()
{
this.Customer_CustomerSpecialConcern = new HashSet<Customer_CustomerSpecialConcern>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public virtual ICollection<Customer_CustomerSpecialConcern> Customer_CustomerSpecialConcern { get; set; }
}
When I pass the model from controller to view everything works fine (can access Customer_CustomerSpecialConcern values).
The problem is when I post back model to a controller to save the changes the property Customer_CustomerSpecialConcern is null.
Here is how I use it in view.
#foreach (var ccsc in Model.Customer_CustomerSpecialConcern)
{
<div class="form-group fields-container col-md-3">
<label class="field-label control-label col-md-10" for="">#ccsc.CustomerSpecialConcern.Title</label>
<div class="col-md-1 field-input">
#Html.EditorFor(model => ccsc.Value)
#Html.HiddenFor(model => ccsc.Value)
</div>
</div>
}
Please, I need help to get the values of this collection property to controller. Thank you.
Update - Customer_CustomerSpecialConcern class details
public partial class Customer_CustomerSpecialConcern
{
public int Id { get; set; }
public int Customer_Id { get; set; }
public int CustomerSpecialConcern_Id { get; set; }
public bool Value { get; set; }
public virtual Customer Customer { get; set; }
public virtual CustomerSpecialConcern CustomerSpecialConcern { get; set; }
}
Please try this,
#for (int i = 0; i < Model.Customer_CustomerSpecialConcern.Count(); i++)
{
<div class="form-group fields-container col-md-3">
<label class="field-label control-label col-md-10" for="">#Model.CustomerSpecialConcern[i].Title</label>
<div class="col-md-1 field-input">
#Html.EditorFor(model => model.Customer_CustomerSpecialConcern[i].Value)
#Html.HiddenFor(model => model.Customer_CustomerSpecialConcern[i].Value)
</div>
</div>
}
Check this article.
I tried your example, and this is how it looks
public ActionResult Index()
{
var customer = new Customer
{
Name = "Name",
Surname = "Surname",
Email = "email#email.com",
Mobile = "mobile...",
Customer_CustomerSpecialConcern = new List<Customer_CustomerSpecialConcern>
{
new Customer_CustomerSpecialConcern
{
Value = true
},
new Customer_CustomerSpecialConcern
{
Value = true
}
}
};
return View(customer);
}
View:
#model WebApplication1.Models.Customer
#{
ViewBag.Title = "Customer";
var customer_CustomerSpecialConcern = Model.Customer_CustomerSpecialConcern.ToList();
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
for (int i = 0; i < Model.Customer_CustomerSpecialConcern.Count(); i++)
{
<div class="form-group fields-container col-md-3">
<label class="field-label control-label col-md-10" for=""></label>
<div class="col-md-1 field-input">
#Html.CheckBoxFor(model => customer_CustomerSpecialConcern[i].Value)
</div>
</div>
}
<input type="submit" value="Save"/>
}

Writing a list to database

For a school assignment I need to make a poll with ASP.NET
The problem I get when trying to write the answers in the database is that only one question and one answer gets written into it.
This is the View
#model CinemaJamV2.WebUIV2.Models.EnqueteModel
#{
ViewBag.Title = "Enquete";
}
<h2>Enquete</h2>
#Html.ValidationSummary(true)
#using (Html.BeginForm("Enquete", "Enquete", new { vraag = "vraag", antwoord = "antwoord", naam = "naam", cijfer = "cijfer" }))
{
<div class="col-md-12">
#for(var i=0;i< Model.enquetevragen.Count();i++)
{
<div class="thumbnail">
#Html.LabelFor(model => model.enquetevragen[i].vraag, new { htmlAttributes = new { #class = "form-control" } })
#Html.EditorFor(model => model.enquete.antwoord, new { htmlAttributes = new { #class = "form-control" } })
#Html.EditorFor(model => model.enquete.cijfer, new { htmlAttributes = new { #class = "form-control" } })
</div>
}
</div>
<div class="col-md-12">
<p>Naam <input type="text" name="naam" /> </p>
<input type="submit" name="submit" value="Verzend" />
</div>
}
This is the Controller:
namespace CinemaJamV2.WebUIV2.Controllers
{
public class EnqueteController : Controller
{
private IRepository<Enquete> repository;
private IRepository<EnqueteVraag> a_repository;
private CineJamContext db = new CineJamContext();
public EnqueteController(IRepository<Enquete> a_model, IRepository<EnqueteVraag> vraag_model)
{
repository = a_model;
a_repository = vraag_model;
}
[HttpGet]
public ActionResult Enquete()
{
EnqueteModel enquetevragen = new EnqueteModel
{
enquetevragen = a_repository.List
};
return View(enquetevragen);
}
[HttpPost]
public ActionResult Enquete(Enquete enquete)
{
if (ModelState.IsValid)
{
db.Enquetes.Add(enquete);
db.SaveChanges();
return RedirectToAction("Enquete");
}
return View(enquete);
}
}
}
The ModelView:
namespace CinemaJamV2.WebUIV2.Models
{
public class EnqueteModel
{
public List<Enquete> enquetes {get; set;}
public Enquete enquete { get; set; }
public List<EnqueteVraag> enquetevragen { get; set; }
}
}
And this is the Model Enquete which should contain all the given answers:
namespace CinemaJamV2.Domain.Entities
{
[Table("Enquete")]
public partial class Enquete : IEntity
{
public int Id { get; set; }
[StringLength(1000)]
public string vraag { get; set; }
[StringLength(1000)]
//[Required]
public string antwoord { get; set; }
public int? cijfer {get; set;}
[StringLength(50)]
//[Required]
public string naam { get; set; }
}
}
This Model contains all the Questions
namespace CinemaJamV2.Domain.Entities
{
[Table("EnqueteVraag")]
public partial class EnqueteVraag : IEntity
{
public int Id { get; set; }
[StringLength(1000)]
public string vraag { get; set; }
}
}
The action for POST has only one instance of the Model as its parameter. You need to read this: Model binding to a list
YOu need to use view model that will have list of Enquete and then in post method again you need to do for loop and save it to database.
See following links for samples.
http://www.binaryintellect.net/articles/b1e0b153-47f4-4b29-8583-958aa22d9284.aspx
http://www.c-sharpcorner.com/UploadFile/pmfawas/Asp-Net-mvc-how-to-post-a-collection/
http://www.codeproject.com/Tips/855577/List-of-Model-Object-Post-to-Controller-in-ASP-NET

MVC 5 not validating StringLength attribute properly

I'm trying to validate the sortCode field in my PersonPaymentDetails model but my view is failing to validate the StringLength(6). If I submit the form with a value of length 1 it incorrectly validates successfully.
Am I doing something fundamentally wrong here?
/* [CONTROLLER] */
public class PersonController : Controller
{
[HttpGet]
[Route("person/paymentDetails/create/{personId?}")]
public ActionResult PaymentDetailsCreate(int? personId)
{
if (personId == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Person person = db.People.Find(personId);
if (person == null)
{
return HttpNotFound();
}
PersonPaymentDetailsViewModel personPaymentDetailsVM = new PersonPaymentDetailsViewModel();
personPaymentDetailsVM.SetPerson(person);
return View(personPaymentDetailsVM);
}
[HttpPost]
[Route("person/paymentDetails/create")]
public ActionResult PaymentDetailsCreate(PersonPaymentDetailsViewModel personPaymentDetailsVM)
{
if (ModelState.IsValid)
{
/* should not be entering here with sortCode = 123, as not 6 characters in length */
return Content("No errors: |" + personPaymentDetailsVM.SinglePaymentDetails.sortCode + "|");
}
}
}
/* [VIEW] */
#model X.ViewModels.PersonPaymentDetailsViewModel
#Html.ValidationSummary()
#using (Html.BeginForm("PaymentDetailsCreate", "Person", FormMethod.Post, new { #class = " form-horizontal" }))
{
#Html.HiddenFor(m => m.Person.id, "default")
<div class="form-group">
<label for="bankSortCode" class="col-md-3 control-label">Sort Code</label>
<div class="col-md-9">
#Html.EditorFor(m => m.SinglePaymentDetails.sortCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<label for="save" class="col-md-3 control-label"> </label>
<div class="col-md-9">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
}
/* [MODEL] */
public partial class PersonPaymentDetails
{
public int id { get; set; }
[Required, StringLength(6)]
public string sortCode { get; set; }
}
/* [ViewModel] */
public class PersonPaymentDetailsViewModel
{
public Person Person { get; set; }
public PersonPaymentDetails SinglePaymentDetails { get; set; }
public void SetPerson(Person person)
{
this.Person = person;
this.SinglePaymentDetails = new PersonPaymentDetails();
}
}
You want
[Required, StringLength(6, MinimumLength = 6)]
Constructor of StringLength takes in the maximum length only, so as you currently have it it checks that string is not longer than 6 characters, and therefore string of length 1 passes validation successfully.

Model (complex type) won't submit to action

I have some problem posting a form with 'complex type' model:
I have a Model:
public class CircleEditViewModel
{
[Key]
public int CircleId { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
public bool IsSystem { get; set; }
public class UserInCircle
{
public UserInCircle(User user)
{
this.UserId = user.UserId;
FullName = user.FullName;
}
public int UserId { get; set; }
public byte[] Picture { get; set; }
public string FullName { get; set; }
public bool isInCircle { get; set; }
}
public List<UserInCircle> Users { get; set; }
}
My first problem was that at post event, my Users where null.. so i followed a few posts on here (like MVC- Model Binding on a Complex Type) to use a for instead of a foreach,but since i did so, my form won't post anymore:
View:
#model Wims.Website.ViewModels.CircleEditViewModel
<script type="text/javascript">
$(document).ready(function () {
$.validator.unobtrusive.parse('form');
});
</script>
#using (Ajax.BeginForm(Html.ViewContext.RouteData.Values["Action"].ToString(), null, new AjaxOptions { HttpMethod = "POST", OnSuccess = "SaveDone(data)" }, new { id = "editform" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Circle</legend>
#Html.Label(DateTime.Now.ToString());
<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>
</fieldset>
if (Model.Users != null)
{
for (int i = 0; i < Model.Users.Count; i++)
{
<div class="userDetail">
<div>
<div>
#Html.DisplayFor(model => Model.Users[i].isInCircle);
</div>
<div class="iconDiv">
#Html.Image("~/Content/Images/defaultUser.jpg", Model.Users[i].FullName, null);
</div>
<div>
#Html.TextBoxFor(model => Model.Users[i].FullName)
#Html.HiddenFor(model => Model.Users[i].UserId)
</div>
</div>
</div>
<div style="clear: both"></div>
}
}
#Html.GenerateSecureDataControls(model => model.CircleId)
<input type="submit" value="Save" />
}
My view is rendered as a partial loaded thru ajax (not sure it makes any difference here).
Any idea why it won't post? If i remove all the '[]' like 'Users[0].FullName' to Users0.FullName i will post, but of course it won't be bound.
Thanks for your help
Edit just in case needed: Action:
[HttpPost]
public ActionResult Edit(CircleEditViewModel circleData, FormCollection collection)
{
if (ModelState.IsValid)
{
using (var logic = new CircleLogic())
{
Circle circle = logic.GetCircleById(circleData.CircleId, WebMatrix.WebData.WebSecurity.CurrentUserId);
if (circle == null)
{
return HttpNotFound();
}
else
{
circle.Name = circleData.Name;
logic.UpdateCircle(circle, GetSelectedUser(collection));
}
return PartialView("_CircleAndUsers", GetData(logic, circle.CircleId));
}
}
return this.Json(new { success = false, viewdata = RenderRazorViewToString("_CircleAndUsers", circleData) });
}
Pablo Romeo was right, i added a default ctor and it worked.

Categories

Resources