ViewModel null on postback - c#

Hi I have been looking for a solution to this problem but I had no luck. Using my viewmodel POST can not get the data, no matter how you do always the object is null. I'll put the code so you can see to which I refer.
This is my ViewModel
public class ProyectosCompletos
{
public IEnumerable<Proyecto> Proyectos { get; set; }
public IEnumerable<Informacion> Informaciones { get; set; }
public IEnumerable<Diseno> Disenos { get; set; }
public IEnumerable<Procedimiento> Procedimientos { get; set; }
public IEnumerable<Programacion> Programaciones { get; set; }
public IEnumerable<Instalacion> Instalaciones { get; set; }
}
This is the model project, it would be the "main" model
public class Proyecto
{
public int ProyectoID { get; set; }
public string Titulo { get; set; }
public virtual ICollection<Elaboracion> Elaboraciones { get; set; }
public virtual Procedimiento Procedimiento { get; set; }
public virtual Informacion Informacion { get; set; }
public virtual Instalacion Instalacion { get; set; }
public virtual Diseno Diseno { get; set; }
public virtual Programacion Programacion { get; set; }
}
This is for example the Instalacion model, and the others are similar
public class Instalacion
{
[Key]
[ForeignKey("Proyecto")]
public int ProyectoID { get; set; }
public double HardwareNota { get; set; }
public double SoftwareNota { get; set; }
public virtual Proyecto Proyecto { get; set; }
public virtual ICollection<InstalacionEntrada> Entradas { get; set; }
public virtual ICollection<InstalacionAnotacion> Anotaciones { get; set; }
}
This is the Controller
public ActionResult Docente(int? ListaProyectos)
{
//This code is not relevant to the problem
var viewModel = new ProyectosCompletos();
string usuarioActualId = User.Identity.GetUserId();
ApplicationUser usuarioActual = db.Users.FirstOrDefault(x => x.Id == usuarioActualId);
var pro = db.Elaboraciones
.Where(e => e.ApplicationUserID == usuarioActual.Id)
.Select(e => new { e.ProyectoID, e.Proyecto.Titulo});
ViewBag.ListaProyectos = new SelectList(pro, "ProyectoID", "Titulo");
//THIS IS WHAT MATTERS
if (ListaProyectos != null)
{
ViewBag.ProyectoID = ListaProyectos.Value;
viewModel.Proyectos = db.Proyectos.Where(p => p.Archivar == false && p.ProyectoID == ListaProyectos.Value);
viewModel.Informaciones = db.Informaciones.Where(i => i.ProyectoID == ListaProyectos.Value);
viewModel.Procedimientos = db.Procedimientos.Where(i => i.ProyectoID == ListaProyectos.Value);
viewModel.Disenos = db.Disenos.Where(i => i.ProyectoID == ListaProyectos.Value);
viewModel.Programaciones = db.Programaciones.Where(i => i.ProyectoID == ListaProyectos.Value);
viewModel.Instalaciones = db.Instalaciones.Where(i => i.ProyectoID == ListaProyectos.Value);
}
return View(viewModel);
}
For GET no problem to get the data. I get them properly and see the view
public ActionResult Docente(int ListaProyectos, ProyectosCompletos viewModel)
{
if (ModelState.IsValid)
{
db.Entry(viewModel.Informaciones).State = EntityState.Modified;
db.Entry(viewModel.Disenos).State = EntityState.Modified;
db.Entry(viewModel.Procedimientos).State = EntityState.Modified;
db.Entry(viewModel.Programaciones).State = EntityState.Modified;
db.Entry(viewModel.Instalaciones).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Docente");
}
}
But to return to the POST form the object is completely empty.
Finally I put the view, I will reduce it a bit because it is already long enough question
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
foreach (var item in Model.Proyectos)
{
<h3>#item.Titulo</h3>
#if (Model.Instalaciones != null)
{
foreach (var instalacion in Model.Instalaciones)
{
Nota: #Html.EditorFor(m => instalacion.HardwareNota, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => instalacion.HardwareNota, "", new { #class = "text-danger" })
Nota: #Html.EditorFor(m => instalacion.SoftwareNota, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => instalacion.SoftwareNota, "", new { #class = "text-danger" })
}
}
}
<input type="submit" value="Guardar Cambios" class="btn btn-success" />
}
I hope you can help me out, thanks !!

Related

Table not incrementing after an insert in asp.net mvc

I'm working on an ASP.NET MVC project. I have created the various models and the viewmodels to use in my project. I have also seeded my database table with seed data but upon implementing the registration view, I tested the form but was getting 0 as the value inserted into the Id portion of the database table. I truncated the tables and did a fresh new insert I still had same error.
Below is the model for the user table
public class User
{
[Key]
public byte Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string RefIndicator { get; set; }
public Team TeamCategory { get; set; }
public byte TeamId { get; set; }
public bool IsRegistered { get; set; }
public DateTime DateRegistered { get; set; }
public DateTime? LastModified { get; set; }
public UserRoles UserRoles { get; set; }
public byte UserRolesId { get; set; }
}
and below is the viewModel I created for the Team Model property I needed to use in my view
public class RegisterFormViewModel
{
public User Users { get; set; }
public byte Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public IEnumerable<Team> Teams { get; set; }
public byte TeamId { get; set; }
public string RefIndicator { get; set; }
public bool IsRegistered { get; set; }
public DateTime DateRegistered { get; set; }
public byte UserRolesId { get; set; }
}
And here is the register action to the userController to initialize the values for the Register view
public ActionResult Register()
{
var AppUser = User.Identity.Name.Substring(5);
var AppUserEmail = AppUser + "#nlng.com";
int index = AppUser.IndexOf('.');
var FirstName = AppUser.Substring(0, index);
var LastName = AppUser.Substring(index + 1);
var IsRegistered = true;
var UserRolesId = 1;
var DateRegistered = HttpContext.Timestamp;
var teams = _context.Team.ToList();
var viewModel = new RegisterFormViewModel{
Email = AppUserEmail,
FirstName = FirstName,
LastName = LastName,
Teams = _context.Team.ToList(),
IsRegistered = IsRegistered,
UserRolesId = (byte)UserRolesId,
DateRegistered = DateRegistered
};
return View("Register", viewModel);
}
And finally here is the associated view for the registration page
#model eLeave.ViewModel.RegisterFormViewModel
#{
ViewBag.Title = "Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>User Registration</h2>
#using (Html.BeginForm("Save", "User"))
{
<div class="form-group">
#Html.LabelFor(r=>r.FirstName)
#Html.TextBoxFor(r => r.FirstName, new { #class = "form-control", #readonly = true })
</div>
<div class="form-group">
#Html.LabelFor(r => r.LastName)
#Html.TextBoxFor(r => r.LastName, new { #class = "form-control", #readonly = true })
</div>
<div class="form-group">
#Html.LabelFor(r => r.Email)
#Html.TextBoxFor(r => r.Email, new { #class = "form-control", #readonly = true })
</div>
<div class="form-group">
#Html.LabelFor(r => r.TeamId)
#Html.DropDownListFor(r => r.TeamId, new SelectList(Model.Teams, "Id", "TeamName"), "Select your Team", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(r => r.RefIndicator)
#Html.TextBoxFor(r => r.RefIndicator, new { #class = "form-control" })
</div>
#Html.HiddenFor(m => m.IsRegistered)
#Html.HiddenFor(m => m.DateRegistered)
#Html.HiddenFor(m => m.UserRolesId)
#Html.HiddenFor(m => m.Id)
#Html.AntiForgeryToken()
<button class="btn btn-primary">Register</button>
}
Finally here's the save action of the userController
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(User user)
{
if (!ModelState.IsValid)
{
var viewModel = new RegisterFormViewModel
{
Users = user,
Teams = _context.Team.ToList()
};
return View("Register", viewModel);
}
if (user.Id == 0)
{
_context.User.Add(user);
}
else
{
var usersInDb = _context.User.Single(m => m.Id == user.Id);
usersInDb.FirstName = user.FirstName;
usersInDb.LastName = user.LastName;
usersInDb.TeamCategory = user.TeamCategory;
usersInDb.RefIndicator = user.RefIndicator;
usersInDb.UserRoles = user.UserRoles;
usersInDb.IsRegistered = user.IsRegistered;
usersInDb.Email = user.Email;
usersInDb.DateRegistered = user.DateRegistered;
}
_context.SaveChanges();
return RedirectToAction("Index", "User");
}
The Save Action basically does two things...It saves a new form and it's also used for updating data.
Would appreciate if the bugs in my code can be fished out.
Form what I understand, you need to make ID as auto incremented value.
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string RefIndicator { get; set; }
public Team TeamCategory { get; set; }
public byte TeamId { get; set; }
public bool IsRegistered { get; set; }
public DateTime DateRegistered { get; set; }
public DateTime? LastModified { get; set; }
public UserRoles UserRoles { get; set; }
public byte UserRolesId { get; set; }
}
I don't think it will work with byte, but you can use int for sure.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Property(a => a.Id).HasKey(b => b.Id);
modelBuilder.Entity<User>().Property(a => a.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}

Saving selected multiSelectList items back to the model

I am working on a site where I have a MultiSelectList of categories. Each item can belong to multiple categories, and obviously each category can have many items. I have it selecting the correct items in the dropdownlist in my view. But once I save, I can't figure out how to save the selected items back into the model.
Here is my model:
public class WebItem
{
public string ImId { get; set; }
public string itemRef { get; set; }
public string name { get; set; }
public string Image { get; set; }
public string NUTS { get; set; }
public string description { get; set; }
public string ingredients { get; set; }
public string allergens { get; set; }
public string price { get; set; }
public string saleprice { get; set; }
public string quantity { get; set; }
private const string DEFAULT_USERNAME = "amyb";
private string _username = DEFAULT_USERNAME;
public string username {
get { return _username; }
set { _username = value; }
}
[Display(Name = "Active?")]
public bool active { get; set; }
[Display(Name = "Order online?")]
public bool orderonline { get; set; }
[Display(Name = "Food?")]
public bool isfood { get; set; }
[Display(Name = "Frozen?")]
public bool isfrozen { get; set; }
[Display(Name = "Overstock?")]
public bool isoverstock { get; set; }
public string activedate { get; set; }
//public int[] catIDs { get; set; }
public List<Category> Categories { get; set; }
public IEnumerable<SelectListItem> categories { get; set; }
private List<int> selectedCategories;
public List<int> SelectedCategories
{
get
{
if (selectedCategories == null)
{
selectedCategories = Categories.Select(m => int.Parse(m.catID)).ToList();
}
return selectedCategories;
}
set { selectedCategories = value; }
}
}
public class Category
{
public Category()
{
}
public Category(string catID, string name, string longname)
{
this.catID = catID;
this.name = name;
this.longname = longname;
}
public string catID { get; set; }
public string name { get; set; }
public string longname { get; set; }
}
Relevant controller code:
public ActionResult UpdateItem(string ImId)
{
WebItem item = new WebItem();
List<Category> categories = HomeModel.getAllCategories();
//var selectCategories = categories.Select(c => new
//{
// CategoryID = c.catID,
// CategoryName = c.longname
//}).ToList();
//item.categories = new MultiSelectList(selectCategories, "CategoryID", "CategoryName");
item.categories = categories.Select(c => new SelectListItem
{
Text = c.name,
Value = c.catID
});
if (ImId != null && !ImId.Equals(""))
{
string query = "SELECT 'Image', 'NUTS', ...";
MySqlConnection con;
//WebItem item = new WebItem();
try
{
con = new MySqlConnection();
con.ConnectionString = appConfig._...;
con.Open();
item = con.Query<WebItem>(query, new { imid = ImId }).FirstOrDefault();
string activedate = item.activedate;
if (activedate.Contains(' '))
{
string[] activedates = activedate.Split(' ');
item.activedate = activedates[0];
}
//List<Category> categories = HomeModel.getAllCategories();
//var selectCategories = categories.Select(c => new
//{
// CategoryID = c.catID,
// CategoryName = c.longname
//}).ToList();
query = "SELECT ...";
try
{
item.SelectedCategories = con.Query<int>(query, new { pid = ImId }).ToList();
}
catch (MySqlException ex)
{
}
//item.categories = new MultiSelectList(selectCategories, "CategoryID", "CategoryName", item.catIDs);
}
catch (MySqlException ex)
{
// show error somehow
//return View(ex.Message);
}
}
return View(item);
}
[HttpPost]
public ActionResult UpdateItem(WebItem item)
{
string result = HomeModel.insertUpdateItem(item);
TempData["Message"] = item.name + " has been inserted/updated.";
return RedirectToAction("WebItems");
}
And the relevant part of my view:
<div class="form-group">
#Html.LabelFor(model => model.categories, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.DropDownList("category", (MultiSelectList)Model.categories, new { multiple = "multiple", htmlAttributes = new { #class = "form-control" } })*#
#Html.ListBoxFor(m => m.SelectedCategories, Model.categories)
#Html.ValidationMessageFor(model => model.categories, "", new { #class = "text-danger" })
</div>
</div>
I don't currently have any code dealing with the categories in my [HttpPost] section of my action. But I'm sure I need something there. And I'm not sure if my model or view are right either.
You may add a new property of array type to your vie wmodel to store the selected options from the multi select box.When the form is posted, MVC Model binding will properly bind the selected values to an object of this view model as long as we have that in our HttpPost action method as a parameter.
public class CreateWebItem
{
public string Name{ get; set; }
public List<SelectListItem> Categories { set; get; }
public int[] SelectedCategories { set; get; }
//Add other properties NEEDED FOR THE VIEW
}
And in your GET action
public ActionResult Create()
{
var vm = new CreateWebItem();
//Hard coded for demo. you may replace with values from db
v.Categories = new List<SelectListItem>
{
new SelectListItem { Value="1", Text="Dinner" },
new SelectListItem { Value="2", Text="Lunch" },
new SelectListItem { Value="3", Text="Snacks" },
new SelectListItem { Value="4", Text="Drinks" }
};
return View(vm);
}
And in your razor view which is strongly typed to the CreateWebItem view model.
#model CreateWebItem
#using (Html.BeginForm())
{
<label>FirstName </label>#Html.TextBoxFor(d => d.Name)
<label>Categories</label>
#Html.ListBoxFor(s=>s.SelectedCategories,Model.Categories)
<input type="submit" value="Add" />
}
And when the form is posted, you can use the SelectedCategories property to get an array of Id's (of the selected options)
[HttpPost]
public ActionResult Index(CreateWebItem model)
{
//read model.SelectedCategories array
// to do : Save to somewhere and do a redirect (PRG pattern)
}

Set Required = false in virtual property, Entity Framework

I have an ASP.NET MVC app and I am using Entity framework.
I have a model named Propiedad and this have some virtual properties without Required attibute, in the view I have a dropdown for the virtual properties and when I do not select an option this tell me that I have to select an option.
I need that Grupo property does not need to select another option, that I can select the optionLabel without show me validator error message.
This is the model:
public class Propiedad
{
[Key]
public int Id { get; set; }
public virtual Entidad Entidad { get; set; }
public virtual PestanasPorEntidad Pestana { get; set; }
public virtual GrupoDePropiedades Grupo { get; set; }
public string Codigo { get; set; }
public string Nombre { get; set; }
public string TipoDeDatos { get; set; }
public bool Requerido { get; set; }
[Required]
public int Orden { get; set; }
public string Columna { get; set; }
}
This is part of the view (Create):
<div class="form-group">
#Html.LabelFor(model => model.Grupo, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.Grupo.Id, (SelectList)(ViewBag.PestanaList), "Ninguno", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Grupo)
</div>
</div>
This is part of the controller
private void SetGrupoListViewBag()
{
ViewBag.GrupoList = new SelectList(unitOfWork.GrupoDePropiedadesRepository.Get(), "id", "nombre");
}
// GET: /GlobalAdmin/Propiedades/Create
public ActionResult Create()
{
var propiedad = new Propiedad();
SetTipoDeDatosListViewBag();
SetEntidadListViewBag();
SetPestanaListViewBag();
SetColumnaListViewBag();
SetGrupoListViewBag();
var entidadId = Request["entidadId"] != null ? Convert.ToInt32(Request["entidadId"]) : -1;
if (entidadId != -1)
{
propiedad.Entidad = unitOfWork.EntidadRepository.GetById(entidadId);
return View(propiedad);
}
else
{
return View();
}
}

dropdownlistfor not assigning selected value

I have looked at similar questions and cannot find an answer that helps me. I am assigning the SelectListItem Selected property in my model method. I watch the model as it comes into the View and it has the selected value. But when it outputs in the view, I have just first value selected.
Model:
public class ProductModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Index("ItemNumber", 1, IsUnique = true)]
[Display(Name = "Item #")]
public int itemNumber { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Product")]
[MaxLength(50)]
public String product { get; set; }
[Display(Name = "Description")]
[MaxLength(500)]
public String description { get; set; }
[DefaultValue(true)]
[Display(Name = "Active?")]
public bool active { get; set; }
[Display(Name = "Image Name")]
public String imageName { get; set; }
[Display(Name = "PDF Name")]
public String PDFName { get; set; }
[ForeignKey("Category")]
public int CategoryID { get; set; }
public virtual CategoryModel Category { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
public static IEnumerable<SelectListItem> getCategories(int id = 0)
{
using (var db = new ProductContext())
{
List<SelectListItem> list = new List<SelectListItem>();
var x = db.Categories.ToList();
foreach (var y in x)
{
//SelectListItem sli = new SelectListItem { Value = y.ID.ToString(), Text = y.categoryName };
SelectListItem sli = new SelectListItem { Value = y.ID.ToString(), Text = y.categoryName };
if (id > 0 && y.ID == id)
{
sli.Selected = true;
}
list.Add(sli);
}
return list;
}
}
public ProductModel()
{
active = true;
}
}
Controller method assigning return value:
public ActionResult EditProduct(int? id)
{
ProductModel model = new ProductModel();
if (id != null)
{
using (var db = new ProductContext())
{
if (id != 0)
{
model = db.Products.Find(id);
}
if (Session["dropdownID"] != null && Session["dropdownID"].ToString().Trim() != "")
{
int dropdownID = Int32.Parse(Session["dropdownID"].ToString());
model.CategoryList = ProductModel.getCategories(dropdownID);
}
else
{
model.CategoryList = ProductModel.getCategories();
}
}
}
return PartialView(model);
}
View code:
<div class="form-group">
#Html.LabelFor(model => model.Category, new { #class = "control-label col-md-8" })
<div class="col-md-16">
#Html.DropDownListFor(model => model.CategoryID, Model.CategoryList, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
</div>
I believe the issue is that the list item is being selected by the value returned by model => model.CategoryID and not the Selected property of the item itself. So if CategoryID == 0 when the view is displayed, the first item in the list will be selected. It's been my experience that the HTML helper ignores the Selected property of the SelectListItem.

Getting Values to Dropdown from Model

I am trying to pull a list from my ViewModel to populate a drop-down. I can get the objects from the Model and pass them to the View, but the view just shows the name of the ViewModel as the value in the dropdown. Not sure how to get the actual values to the Dropdown or if am going in the wrong direction. No intellesence past the definition of the object "model.InitialFeesChart". Thanks in advance for looking.
Controller: Objects contain needed data
public ActionResult CreateFranchise()
{
var model = new FranchiseVM();
model.FranStates = new List<string> { "AZ", "NV", "CA" };
//Grap the Package Identificaton to determine Package selected by Franshise
model.InitialFeesChart = (from f in _db.InitalFeesCharts
select new InitalFeesChartVM {IFCPackage = f.IFCPackage}).ToList();
return View(model);
}
ViewModel:
namespace Compass.Models
{
public class FranchiseVM
{
[Key]
public int FranchiseID { get; set; }
public string FranPID { get; set; }
public string FranBusinessName { get; set; }
public string FranAddress { get; set; }
public string FranCity { get; set; }
public string FranState { get; set; }
public string FranPostalCode { get; set; }
public string FranPhonePrimary { get; set; }
public string FranPhonePrimaryCell { get; set; }
public string FranFAX { get; set; }
public string FranOwnerFirstName { get; set; }
public string FranOwnerLastName { get; set; }
public string FranAlternateFirstName { get; set; }
public string FranAlternateLastName { get; set; }
public string FranAlternatePhone { get; set; }
public string FranNotes { get; set; }
public string IFCPackageCurrent { get; set; }
public IList<string> FranStates { get; set; }
//public IList<InitalFeesChartVM> InitialFeesChart { get; set; }
//Added
public string IFCPackage { get; set; }
private readonly List<InitialFeesChart> _InitialFeesChart;
public IEnumerable<SelectListItem> IFCItems
{
get { return new SelectList(_InitialFeesChart, "InitialFeesID", "IFCPackage"); }
}
}
}
View:
<div class="form-group">
#Html.LabelFor(model => model.IFCPackageCurrent, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.IFCPackageCurrent, Model.IFCItems))
</div>
</div>
Final working code:
ViewModel
public IList<InitalFeesChartVM> InitialFeesChart { get; set; }
[Display(Name = "Franchise Package")]
public string IFCPackageCurrent { get; set; }
View:
<div class="form-group">
#Html.LabelFor(model => model.IFCPackageCurrent, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.IFCPackageCurrent, new SelectList(Model.InitialFeesChart, "InitialFeesID", "IFCPackage"))
</div>
</div>
Controller:
public ActionResult CreateFranchise()
{
var model = new FranchiseVM();
model.FranStates = new List<string> { "AZ", "NV", "CA" };
model.InitialFeesChart = (from f in _db.InitalFeesCharts select new InitalFeesChartVM { IFCPackage = f.IFCPackage, InitialFeesID = f.InitialFeesID }).ToList();
return View(model);
You need to specify what properties to use in the Select List. Specify the value field and the text field like this: SelectList(Items, "Id", "Title")
I've created a fiddle that uses your classes. You will have to change the string values in the part when the select list is created so that they match the properties you want to use from your InitalFeesChartVM http://dotnetfiddle.net/9052ZH

Categories

Resources