How to pass IEnumerable object or data from view to controller? - asp.net-mvc-3

I have created a strongly type view. I want to pass IEnumerable Object or data from View to Controller. Following are my Model, Controller ,view
My Model:
public class UserDetailsClass
{
public static FeedbackDatabaseDataContext context = new FeedbackDatabaseDataContext();
public class Tablefields
{
[Key]
public int ID { get; set; }
[Required(ErrorMessage = "Email is required")]
public string EmailID { get; set; }
[Required(ErrorMessage="Password is required")]
public string Password { get; set; }
[Required(ErrorMessage = "First Name is required")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required")]
public string LastName { get; set; }
}
public static List<UserDetails> getalluser()
{
var lst = (from r in context.UserDetails select r);
return lst.ToList();
}
}
My Controller
public ActionResult Test()
{
IList<UserDetailsClass.Tablefields> viewmodel = new List<UserDetailsClass.Tablefields>();
var q = UserDetailsClass.getalluser().ToList();
foreach (SQLOperation.Models.UserDetails item in q)
{
UserDetailsClass.Tablefields viewItem = new UserDetailsClass.Tablefields();
viewItem.EmailID = item.Email;
viewItem.FirstName = item.FirstName;
viewItem.LastName = item.LastName;
viewItem.Password = item.Password;
viewmodel.Add(viewItem);
}
return View(viewmodel);
}
[HttpPost]
public ActionResult Test(IEnumerable<UserDetailsClass.Tablefields> items)
{
return View();
}
My View:
#model IEnumerable<SQLOperation.Models.UserDetailsClass.Tablefields>
#{
ViewBag.Title = "Test";
}
<h2>Test</h2>
#using (Html.BeginForm())
{
<table>
<tr>
<th>
EmailID
</th>
<th>
Password
</th>
<th>
FirstName
</th>
<th>
LastName
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.EmailID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Password)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
</tr>
}
</table>
<input type="submit" value="submit" />
}
I didn't get any value in items.When I set breakpoint on it it show NULL in items
I am totally Confused about how to pass values to controller.
Thank you,
Amol

Instead of #Html.DisplayFor use #Html.EditorFor, that way databinding will happen in your form.
Also since you are using collection you need to iterate your fields (simplified example):
#for (int row = 0; row < Model.Count; row++)
{
#Html.EditorFor(x => x[row].FirstName )
}

#for (int i = 0; i < Model.length; i ++)
{
<tr>
<td>
#Html.DisplayFor(model => Model[i].EmailID)
</td>
<td>
#Html.DisplayFor(model => Model[i].Password)
</td>
<td>
#Html.DisplayFor(model => Model[i].FirstName)
</td>
<td>
#Html.DisplayFor(model => Model[i].LastName)
</td>
</tr>
}
</table>
<input type="submit" value="submit" />
}

Related

Error when joining two tables using linq in mvc4

This is my controller, in select new what should I use? If I use any class name the it is showing error like name don't find in this model?
Here the controller code:
public class HomeController : Controller
{
Database1Entities db = new Database1Entities();
public ActionResult Index()
{
return View();
}
public ActionResult details()
{
var myParts = (from p in db.emps
join d in db.depts on p.Eid equals d.Eid
select new
{
name =p.name,
address = p.address,
number=d.number,
sub=d.sub
}).ToList();
return View(myParts);
}
}
}
My index page what should I give in model if I give the class name or table name if I give class name then I have two class the which class i give in above model
here this Index page code:
#model IEnumerable<two2.Models.mass>
#{
ViewBag.Title = " Deaprtment name ";
}
<h2>Index</h2>
#{
ViewBag.Title = "Department";
}
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.name)
</th>
<th>
#Html.DisplayNameFor (model => model.address)
</th>
<th>
#Html.DisplayNameFor (model => model.sub)
</th>
<th>
#Html.DisplayNameFor (model => model.mark)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.address)
</td>
<td>
#Html.DisplayFor(modelItem => item.sub)
</td>
<td>
#Html.DisplayFor(modelItem => item.mark)
</td>
</tr>
}
</table>
and my view page
in index page it is showing object not found
and in foreach statement it is showing error
#model two2.Models.mass
#{
ViewBag.Title = "deatils";
}
#using (#Html.BeginForm())
{
#Html.LabelFor(model => model.name)
#Html.TextBoxFor(model => model.name)
<br /><br />
#Html.LabelFor(model => model.address)
#Html.PasswordFor(model => model.address)
<br /><br />
<br /><br />
#Html.LabelFor(model => model.sub)
#Html.PasswordFor(model => model.sub)
<br /><br />
<br /><br />
#Html.LabelFor(model => model.mark)
#Html.PasswordFor(model => model.mark)
<br /><br />
<button>Login</button>
}
I don't know what should I use such that my be class name or table name and how to display on view
You should use same class name in Action also which is used in View like:
public ActionResult details()
{
var myParts = (from p in db.emps
join d in db.depts on p.Eid equals d.Eid
select two2.Models.mass
{
Eid = p.Eid,
name = p.name,
address = p.address,
number = d.number,
mark = d.mark, // <- you need to pass mark as it is used in View
sub = d.sub
}).ToList();
return View(myParts);
}
If you are using in View:
#model IEnumerable<two2.Models.mass>
Class two2.Models.mass is one type of ViewModel and it should contain only those fields which are needed in View:
namespace two2.Models
{
public class mass
{
public int Eid { get; set; }
public string name { get; set; }
public string address { get; set; }
public int number { get; set; }
public string sub { get; set; }
public int mark { get; set; }
}
}

Posted ViewModel return null properties

I am having issues with a view model that constantly return null properties after a post. Below is my code (it could be a syntax issue or two calling a class or property the same name as i saw in other posts but i could not see any such issue in code):
VIEW MODEL:
public class ProductItem
{
public int ProductID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string LongDescription { get; set; }
public int SupplierID { get; set; }
public string Dimensions { get; set; }
public double Price { get; set; }
public bool On_Sale { get; set; }
public double DiscountedPrice { get; set; }
public string Thumbnail { get; set; }
public string LargeImage { get; set; }
public string LargeImage2 { get; set; }
public string LargeImage3 { get; set; }
public string CrossRef { get; set; }
public byte Available { get; set; }
public double Weight { get; set; }
public byte Important { get; set; }
public virtual ICollection<ProductCategory> ProductCategories { get; set; }
// this is required on the page to allow products to be marked for deletion
public bool IsForDelete { get; set; }
}
public class ProductListViewModel
{
public IEnumerable<ProductItem> ProductItems { get; set; }
public IEnumerable<Category> CategoryItems { get; set; }
}
CONTROLLER:
public ActionResult ProductList()
{
var productList = new ProductListViewModel();
productList.ProductItems = productRepository.GetProductsWithDeleteOption().ToList();
productList.CategoryItems = categoryRepository.GetCategories().ToList();
return View(productList);
}
[HttpPost]
public ActionResult ProductList(ProductListViewModel productViewModel, FormCollection formCollection, string submit)
{
if (ModelState.IsValid)
{
// Check for submit action
if (submit == "Change Sort")
{
if (formCollection["Sortby"] == "ProductID")
{
OrderBy(productViewModel, formCollection, "m.ProductID");
}
else if (formCollection["Sortby"] == "Code")
{
OrderBy(productViewModel, formCollection, "m.Code");
}
else if (formCollection["Sortby"] == "Name")
{
OrderBy(productViewModel, formCollection, "m.Name");
}
else if (formCollection["Sortby"] == "Price")
{
OrderBy(productViewModel, formCollection, "m.Price");
}
}
else if (submit == "Delete all selected")
{
}
else if (submit == "Update All")
{
}
else if (submit == "Restrict Display")
{
}
}
return View(productViewModel);
}
VIEW:
#model Admin.Models.ViewModels.ProductListViewModel
#{
ViewBag.Title = "View Products";
}
#using (Html.BeginForm())
{
<h2>Product List as at #DateTime.Now.ToString("dd/MM/yyyy")</h2>
<table>
<tr>
<td>Sort by:</td>
<td>
<select name="Sortby">
<option value="ProductID">ProductID</option>
<option value="Code">Code</option>
<option value="Name">Name</option>
<option value="Price">Price</option>
</select>
</td>
<td>
<input type="radio" name="sortDirection" checked="checked" value="Asc" /> Ascending
<input type="radio" name="sortDirection" value="Desc" /> Descending
</td>
<td>
<input type="submit" name="submit" value="Change Sort" />
</td>
</tr>
<tr>
<td>Display only : (category)</td>
<td>#Html.DropDownList("CategoryID", new SelectList(Model.CategoryItems, "CategoryID", "Name"), "All Categories")</td>
<td colspan="2"><input type="submit" name="submit" value="Restrict Display" /></td>
</tr>
<tr>
<td colspan="4"><br />Total Number of products: #Model.ProductItems.Count()</td>
</tr>
</table>
<table>
<tr>
<th>
Edit
</th>
<th>
Code
</th>
<th>
Name
</th>
<th>
Price
</th>
<th>
On_Sale
</th>
<th>
DiscountedPrice
</th>
<th>
Weight
</th>
<th>
Delete
</th>
<th></th>
</tr>
#for (var i = 0; i < Model.ProductItems.ToList().Count; i++)
{
<tr>
<td>
#Html.HiddenFor(m => m.ProductItems.ToList()[i].ProductID)
#Html.ActionLink(Model.ProductItems.ToList()[i].ProductID.ToString(), "ProductEdit", new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.DisplayFor(m => m.ProductItems.ToList()[i].Code)
</td>
<td>
#Html.DisplayFor(m => m.ProductItems.ToList()[i].Name)
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].Price)
</td>
<td>
#Html.CheckBoxFor(m => m.ProductItems.ToList()[i].On_Sale, new { id = "On_Sale_" + Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].DiscountedPrice)
</td>
<td>
#Html.EditorFor(m => m.ProductItems.ToList()[i].Weight)
</td>
<td>
#Html.CheckBoxFor(m => m.ProductItems.ToList()[i].IsForDelete, new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
<td>
#Html.ActionLink("Edit", "ProductEdit", new { id = Model.ProductItems.ToList()[i].ProductID }) |
#Html.ActionLink("Details", "Details", new { id = Model.ProductItems.ToList()[i].ProductID }) |
#Html.ActionLink("Delete", "Delete", new { id = Model.ProductItems.ToList()[i].ProductID })
</td>
</tr>
}
</table>
<p>
<input name="submit" type="submit" value="Delete all selected" />
</p>
<p>
<input name="submit" type="submit" value="Update All" />
</p>
<p>
#Html.ActionLink("Add a new product", "ProductAdd")
</p>
}
In the post action, the productViewModel argument has the ProductItems and CategoryItems properties as null.
Ok, so there are two problems.
I don't understand why you want to post list of the CategoryItems You should only expect the selected category and not the list
The problem with ProductItems is the name generated for <input> tags. Currently, the name being generated is name="[0].Price" whereas it should have been name="ProductItems[0].Price"
I changed the following code
#Html.EditorFor(m => m.ProductItems.ToList()[i].Price)
to
#Html.EditorFor(m => m.ProductItems[i].Price)
and it worked.
Note: I changed IEnumerable<ProductItem> ProductItems to List<ProductItem> ProductItems in ProductListViewModel
Yes it will be null on post back. I have a similar table in one of my projects and this is what I would have done given my situation.
You could change your view model to look like this then you don't have to do so many converting to lists in your view:
public class ProductListViewModel
{
public List<ProductItem> ProductItems { get; set; }
public List<Category> CategoryItems { get; set; }
}
Now in you view it could look something like this (this is just part of it, then rest you can just go and add):
#for (int i = 0; i < Model.ProductItems.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(m => m.ProductItems[i].Name)
#Html.HiddenFor(m => m.ProductItems[i].Name)
</td>
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.ProductItems[i].IsForDelete)
</td>
</tr>
}
Add the code and do some debugging to see how the values are returned on submit
I hope this helps.

I lost my data on submit MVC 3

I have a MVC 3 application with entity framework.
In my page I use a custom Model that contains all objects I use. The page is rendered perfectly, but when I press the submit button my object loses the data.
This is my custom model:
public class ControleAcessoModel
{
private List<Controle> controles = new List<Controle>();
public GRUPO_ACESSO_TB grupo_acesso_tb { get; set; }
public List<Controle> Controles
{
get
{
return controles;
}
}
public void AddTela(byte id, string nome)
{
Controle ctrl = new Controle();
ctrl.ID_TELA = id;
ctrl.NM_TELA = nome;
controles.Add(ctrl);
}
public class Controle
{
public bool Selecionado { get; set; }
public byte ID_TELA { get; set; }
public string NM_TELA { get; set; }
public bool FL_SALVAR { get; set; }
public bool FL_ALTERAR { get; set; }
public bool FL_EXCLUIR { get; set; }
}
}
this is my Razor Html code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<table>
<tr>
<th>Salvar</th>
<th>Editar</th>
<th>Excluir</th>
<th>Tela</th>
</tr>
#foreach (var item in Model.Controles)
{
<tr>
<td style="text-align: center">
#Html.EditorFor(modelItem => item.FL_SALVAR)
</td>
<td style="text-align: center">
#Html.EditorFor(modelItem => item.FL_ALTERAR)
</td>
<td style="text-align: center">
#Html.EditorFor(modelItem => item.FL_EXCLUIR)
</td>
<td>
#Html.DisplayFor(modelItem => item.NM_TELA)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Salvar" />
</p>
}
This is my create code, where I put the data on database.
Is in this part, that my object controleacessomodel is empty.
[HttpPost]
public ActionResult Create(ControleAcessoModel controleacessomodel, byte id)
{
if (ModelState.IsValid)
{
for (int i = 0; i < controleacessomodel.Controles.Count; i++)
{
if (ValidaSelecao(controleacessomodel.Controles[i]))
{
PERMISSAO_GRUPO_ACESSO_TELA_TB permissao = new PERMISSAO_GRUPO_ACESSO_TELA_TB();
permissao.ID_GRUPO_ACESSO = controleacessomodel.grupo_acesso_tb.ID_GRUPO_ACESSO;
permissao.ID_TELA = controleacessomodel.Controles[i].ID_TELA;
permissao.FL_SALVAR = controleacessomodel.Controles[i].FL_SALVAR;
permissao.FL_ALTERAR = controleacessomodel.Controles[i].FL_ALTERAR;
permissao.FL_EXCLUIR = controleacessomodel.Controles[i].FL_EXCLUIR;
db.PERMISSAO_GRUPO_ACESSO_TELA_TB.AddObject(permissao);
}
}
db.SaveChanges();
return RedirectToAction("Edit", "GrupoAcesso", new { id = id });
}
return View(controleacessomodel);
}
Why my object is empty after submit?
It's not possible to use the Foreach loop construct as the generated ids will be not be correct, therefore MVC is not able to map the values back to the model. You need to use a for loop instead:
#for (int i = 0 ; i < Model.Controles.Count; i++)
{
<tr>
<td style="text-align: center">
#Html.EditorFor(m => m.Controles[i].FL_SALVAR)
</td>
<td style="text-align: center">
#Html.EditorFor(m => m.Controles[i].FL_ALTERAR)
</td>
<td style="text-align: center">
#Html.EditorFor(m => m.Controles[i].FL_EXCLUIR)
</td>
<td>
#Html.DisplayFor(m => m.Controles[i].NM_TELA)
</td>
</tr>
}
Phil Haack write a good blog post about this. Also Scott Hanselman wrote a nice post too.

Error on page: The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies

I get this error on my Details view page:
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.cpd_certificates_65AF30842281867E2F4F6A1026590271109C12A85C8175394F14EF6DE429CBC7', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[cpd.Models.cpd_certificates]'.
This is my controller :
public class Default8Controller : Controller
{
//
// GET: /Default8/
private cpdDbContext db = new cpdDbContext();
public ActionResult Index()
{
return View(db.CPD.ToList());
}
//
// GET: /Default8/Details/5
public ActionResult Details(int id)
{
cpd_certificates cpd_ = db.Cert.Find(id);
return View(cpd_);
}
Below is my Details view:
#model IEnumerable<cpd.Models.cpd_certificates>
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CertificateNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mark)
</td>
</tr>
}
</table>
Below is the cpd_certificates model:
public class cpd_certificates
{
[Key]
public int CertificateNo { get; set; }
public int QuizNo { get; set; }
public DateTime? DateReceived { get; set; }
public DateTime? DatePaid { get; set; }
public string Mark { get; set; }
public int? AccreditationNo { get; set; }
public int? ID { get; set; }
public virtual cpd_recipients Recipients { get; set; }
}
I have two models and I can view the list on my Index. I intended that when I click the details link it takes me to details of certificates earned and exams which are in another model/table. So in short two models which have a PK ID for CPD and FK ID on Cert. Index page show just personal information and this page is fine.
When Details is clicked it then shows the other model/table data that is the many certificates of that person.
You should pass the model into the view as the List of IEnumerable entries instead of passing it as a single entry.
In your Controller you want to show one entry details, but in the view, want to show details of all entries.First you should decide what to show.
For showing one entry details, use this:
controller:
public ActionResult Details(int id)
{
cpd_certificates cpd_ = db.Cert.Find(id);
return View(cpd_);
}
view:
#model cpd.Models.cpd_certificates
#{
ViewBag.Title = "Details";}
<h2>Details</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
<tr>
<td>
#Html.DisplayFor(model => model.CertificateNo)
</td>
<td>
#Html.DisplayFor(model => model.Mark)
</td>
</tr>
}
</table>
And when you want to list all of entries, use this:
controller:
public ActionResult List()
{
cpd_certificates cpd_ = db.Cert.ToList();
return View(cpd_);
}
view:
#model IEnumerable<cpd.Models.cpd_certificates>
#{
ViewBag.Title = "List";
}
<h2>List</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CertificateNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mark)
</td>
</tr>
}
</table>

Posting to a list<modeltype> MVC3

I am trying to get my view to post a List back to the action however it keeps coming in as null.
So my Model has a List of WeightEntry objects.
Exercise Model
public class Exercise
{
public List<WeightEntry> Entries { get; set; }
public int ExerciseID { get; set; }
public int ExerciseName { get; set; }
}
WeightEntry Model
public class WeightEntry
{
public int ID { get; set; }
public int Weight { get; set; }
public int Repetition { get; set; }
}
My View contains the ExerciseName and a forloop of WeightEntry objects
#model Mymvc.ViewModels.Exercise
...
<span>#Model.ExerciseName</span>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<table class="left weight-record">
<tr>
<th>Reps</th>
<th>Weight</th>
</tr>
#foreach (var item in Model.Entries)
{
<tr>
<td>
#Html.EditorFor(x => item.Repetition)
</td>
<td>
#Html.EditorFor(x => item.Weight)
</td>
</tr>
}
</table>
<input type="submit" value="Save" />
}
The Controller Action (Post) Does nothing at the moment. I am just trying to get the binding working before I add the save code.
[HttpPost]
public ActionResult WeightEntry(Exercise exercise)
{
try
{
//Add code here to save and check isvalid
return View(exercise);
}
catch
{
return View(exercise);
}
}
I have seen a few little tricks with adding a numerator to the form elements' names used in MVC2 but I was wondering if MVC3 was any different? I was hoping it would all bind nicely with ID's being 0 or null but instead the whole List is null when I inspect it after the form posts. Any help is appreciated.
Thanks.
Replace the following loop:
#foreach (var item in Model.Entries)
{
<tr>
<td>
#Html.EditorFor(x => item.Repetition)
</td>
<td>
#Html.EditorFor(x => item.Weight)
</td>
</tr>
}
with:
#for (var i = 0; i < Model.Entries.Count; i++)
{
<tr>
<td>
#Html.EditorFor(x => x.Entries[i].Repetition)
</td>
<td>
#Html.EditorFor(x => x.Entries[i].Weight)
</td>
</tr>
}
or even better, use editor templates and replace the loop with:
#Html.EditorFor(x => x.Entries)
and then define a custom editor template that will automatically be rendered for each element of the Entries collection (~/Views/Shared/EditorTemplates/WeightEntry.cshtml):
#model WeightEntry
<tr>
<td>
#Html.EditorFor(x => x.Repetition)
</td>
<td>
#Html.EditorFor(x => x.Weight)
</td>
</tr>
The the generated input elements will have correct names and you will be able to successfully fetch them back in your POST action.

Resources