Last day, i saw that in my razor view
#Html.DropDownListFor(x => x.FoodId,null, htmlAttributes: new { #class = "form-control" })
// and (just another alternative)
#Html.DropDownList("FoodId", null, htmlAttributes: new { #class = "form-control" })
And i'm wondering what's going on with the data in the list, where and when data-filling occurs? and what is the difference between the two lines? and how the dropdown got filled with data (because there is data in the execution of the code)
sorry for my bad english
Update #1
Model:
Food.cs and User.cs
public partial class Food
{
public Food()
{
this.User = new HashSet<User>();
}
public System.Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> User { get; set; }
}
//
public partial class User
{
public System.Guid Id { get; set; }
public string Name { get; set; }
public Nullable<System.Guid> FoodId { get; set; }
public virtual Food Food { get; set; }
}
Controller (only action)
public ActionResult Create()
{
ViewBag.FoodId = new SelectList(db.FoodSet, "Id", "Name");
return View();
}
Omg thanks i'm now stupid :)
Answer: Got filled with ViewBag.FoodId
When passing a null value to the second argument, it it will automatically, even without javascript and with a cleared cache look in the ViewBag for a key with the same name as the dropdown, otherwise launch exception.
In my case, null was passed and it checked the ViewBag and found a key
Related
My input model consists of NewForm in which many fields
public class NewForm
{
[Key]
public int Id { get; set; }
public string HeadForm { get; set; }
public List<Field> Fields { get; set; }
}
public class Field
{
public int Id { get; set; }
public bool Check { get; set; }
public string HeadField { get; set; }
}
I want to take values from the base and edit them, but Model.Fields.Count throw exception. Although the string "HeadForm" is displayed. Lists are not displayed.
EditPage:
#model EditFormApplication.Models.NewForm
#using (Html.BeginForm("Edit", "Home", FormMethod.Post))
{
#Html.TextBoxFor(model => model.HeadForm)
<h5>Fields:</h5><br>
#for ( var i = 0; i< Model.Fields.Count; i++) {
#Html.TextBoxFor(model => model.Fields[i].HeadField)
#Html.CheckBoxFor(model => model.Fields[i].Check)
}
<input type="button" value="Add Field" onclick="addField(this);">
<input type="submit"value="Save">
}
For example, I am typing data by ID = 3.
Controller:
public ActionResult CreateForm(NewForm model)
{
using (NewFormContext db = new NewFormContext())
{
db.NewForms.Add(model);
db.SaveChanges();
return RedirectToAction("Edit");
}
}
public ActionResult Edit()
{
using (NewFormContext db = new NewFormContext()) {
var model = db.NewForms.Find(3);
return this.View(model);
}
}
used Code First and one to many
Sounds like Model.Fields property still contain null when db.NewForms.Find() is executed to assign the model you want to return into view, indicating that EF doesn't create dependent collection yet. As far as I know you should add collection instance definition inside parameterless constructor of entity class:
public class NewForm
{
public NewForm()
{
// instantiate list here
Fields = new List<Field>();
}
[Key]
public int Id { get; set; }
public string HeadForm { get; set; }
public List<Field> Fields { get; set; }
}
Or if you're using lazy loading, mark the property as virtual to let EF instantiate the collection while necessary:
public virtual List<Field> Fields { get; set; }
Related issue:
EF codefirst : Should I initialize navigation properties?
I'm using mvc4. How can I Bind CuntryName and its values in DropdownList
Country?
public class Country
{
public int Cnt_Id { get; set; }
public string Cnt_Name { get; set; }
}
This is my private class
public class HybridEmployee
{
public IEnumerable<Country> GetCount { get; set; }
}
Controller
public ActionResult GetCountry()
{
var x = ObjRepo.GetCountry();
hybrid.GetCount = x;
return View(hybrid);
}
Index.cshtml
#model Mvc_Application.Models.HybridEmployee
#using Mvc_Application.Models
#using (Html.BeginForm("SaveEmp", "Home", FormMethod.Post))
{
#Html.DropDownListFor(x=>x.GetCount.FirstOrDefault().Cnt_Id),new SelectList(Model.GetCount,"","");
}
We can have two approaches as shown below:
Using a ViewBag containing the data for dropdown list.
Model file:
public class State
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int CountryID { get; set; }
}
In .cs file:
ViewBag.Countries = countryService.All().Select(x => new SelectListItem() { Text = x.Name, Value = x.Id.ToString() }).ToList();
In .cshtml file:
#Html.DropDownListFor(x => x.CountryID, ViewBag.Countries as IEnumerable<SelectListItem>, "Select Country", new { #class = "form-control" })
Using a Model's property containing the data for dropdown list.
Model file:
public class State
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int CountryID { get; set; }
public List<SelectListItem> Countries { get; set; }
}
In .cs file:
model.Countries = countryService.All().Select(x => new SelectListItem() { Text = x.Name, Value = x.Id.ToString() }).ToList();
In .cshtml file:
#Html.DropDownListFor(x => x.CountryID, Model.Countries, "Select Country", new { #class = "form-control" })
This expression totally doesn't makes sense:
#Html.DropDownListFor(x=>x.GetCount.FirstOrDefault().Cnt_Id),new SelectList(Model.GetCount,"","");
The first argument of DropDownListFor helper (Expression<Func<TModel, TProperty>> expression) doesn't use LINQ expression, it is model binding expression - you must use a property to hold selected value instead. The drop down list binding should be used like this:
Model
public class Country
{
public int Cnt_Id { get; set; }
public string Cnt_Name { get; set; }
public int SelectedCountry { get; set; } // additional property to get selected value
}
View
#Html.DropDownListFor(x => x.SelectedCountry, new SelectList(Model.GetCount, "Cnt_Id", "Cnt_Value"), null)
I've read every article that stack overflow recommended to me and have not yet solved my problem. This is my first post and I apologize if it is an easy fix, but no matter what I save first (AfterCooler, F1046, or BasicInfo, I get the exception for explicitly inserting AfterCooler's identity. BasicInfo saves fine on it's own, but when adding F1046, saving it, or adding AfterCooler and saving it, I get this exception. AfterCooler and F1046 should have a 1 to 1, and F1046 and BasicInfo should have a one to many relationship.
Entities:
[MetadataType(typeof(F1046MetaDataSource))]
public partial class F1046
{
public int F1046Id { get; set; }
public virtual AfterCooler AfterCooler { get; set; }
public int BasicInfoId { get; set; }
public virtual BasicInfo BasicInfo { get; set; }
}
class F1046MetaDataSource
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int F1046Id { get; set; }
[ForeignKey("BasicInfo")]
public int BasicInfoId { get; set; }
}
[MetadataType(typeof(AfterCoolerMetaDataSource))]
public partial class AfterCooler : IComparer<AfterCooler>
{
public string AfCoolReasonChange { get; set; }
public string VendorAF { get; set; }
public int F1046Id { get; set; }
public virtual F1046 F1046 { get; set; }
}
class AfterCoolerMetaDataSource
{
[Key,ForeignKey("F1046")]
public int F1046Id { get; set; }
}
[MetadataType(typeof(BasicInfoMetaDataSource))]
public partial class BasicInfo
{
public int BasicInfoId { get; set; }
public DateTime? DateBasicInfo { get; set; }
...
public virtual ICollection<F1046> F1046 { get; set; }
public BasicInfo()
{
F1046 = new List<F1046>();
}
}
class BasicInfoMetaDataSource
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int BasicInfoId { get; set; }
}
Repository methods:
public void SaveAfterCooler(AfterCooler afterCooler)
{
if (afterCooler.F1046Id == 0)
{
context.AfterCooler_.Add(afterCooler);
}
else
{
context.Entry(afterCooler).State = EntityState.Modified;
}
context.SaveChanges();
}
(this looks the same for essentially every entity, just swapping the contexts/id's..)
I have a view which has elements of the BasicInfo (but not the id's) and of the F1046 (but not the id's), the members of the F1046 (AfterCooler, its properties, etc..) like this:
<div class="form-group">
#Html.Label("After Cooler Reason")
#Html.EditorFor(x => Model.F1046.AfterCooler.AfCoolReasonChange, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => Model.F1046.AfterCooler.AfCoolReasonChange, "", new { #class = "text-danger" })
</div>
and it gets submitted to a controller method which I shortened to something like this..
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateF1046(F1046_CreateViewModel fm)
{
if (ModelState.IsValid)
{
BasicInfo bi = fm.BasicInfo;
F1046 f1 = fm.F1046;
_f1046Repository.SaveF10461(f1);
bi.F1046.Add(f1);
return RedirectToAction("Summary", bi);
}
I've tried everything in every order or at least it feels that way.. I'm sorry if this doesn't make much sense, the program takes a lot of fields in and I tried to leave out the irrelevant ones. The ViewModel mentioned above for the controller method contains a BasicInfo object and an F1046 object for relevance.
Thank you.
I'm having hard time trying to figure out which way to go.
Before i start, here some of the classes :
public class Car
{
[Key]
[Required]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
[MaxLength(255)]
public string Title { get; set; }
[Required]
public DateTime Date{ get; set; }
public virtual Category Category { get; set; }
}
public class Category {
[Key]
[Required]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ID {get;set;}
public Category Parent{get;set;}
[Required]
[MaxLength(255)]
public string Title {get;set;}
}
So, to create a new "Car", I simply need a page with a dropdown for all of the categories. To do that, I wrote a new class and passed it to "ActionResult Create"...
Here it is :
public class CarCreate
{
public Car Car { get; set; }
public List<Category> Categories
{
get
{
List<Category> list = new List<Category>();
SystemContext sc = new SystemContext();
list = sc.Categories.ToList();
list.Insert(0, null);
sc.Dispose();
return list;
}
}
}
And from the controller I passed it like this:
public ActionResult Create()
{
return View(new CarCreate());
}
And within the view, I created a dropdown for List in CarCreate class:
<div class="col-md-4">
#Html.LabelFor(t => t.Car.Title)
#Html.TextBoxFor(model => model.Car.Title, new { #class = "form-control" })
</div>
<div class="col-md-4">
#Html.LabelFor(t => t.Car.Category)
#Html.DropDownListFor(model => model.Car.Category, new SelectList(Model.Categories, "ID", "Title","Select"), new { #class = "form-control" })
</div>
And when I check the Car.Category within the ActionResult that handles postback like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CarCreate emc)
{
Response.Write(emc.Car.Title);
Response.Write(emc.Car.Category== null ? "null" : "notnull");
return View(new CarCreate());
}
I can get title. But category is always null.
What would I have to do to get category from postback?
DropDownListFor is mapped with a value wich is defined by the option selected in the select.
You try to set this value in a complex object.
I think you should have a things like
public class Car
{
[Key]
[Required]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
[MaxLength(255)]
public string Title { get; set; }
[Required]
public DateTime Date{ get; set; }
public virtual int CategoryID { get ; set;}
public virtual Category Category { get; set; }
}
And
<div class="col-md-4">
#Html.LabelFor(t => t.Car.Category)
#Html.DropDownListFor(model => model.Car.CategoryID, new SelectList(Model.Categories, "ID", "Title","Select"), new { #class = "form-control" })
</div>
I believe it's because your Category is not instanciate. Try to add this in the Car constructor :
public class Car
{
public Car()
{
this.Category = new Category();
}
}
Hope it helps !
I would keep my viewmodels as lite as i can. Just keep the properties you really need in your view. Also i prefer to keep those as simple POCO's(not with data loading logic in that) so that i can use that in many places.
public class CreateCarVM
{
[Required]
public string Title { set;get;}
public List<SelectListItem> Categories { set;get;}
[Required]
public int SelectedCategory { set;get;}
public CreateCarVM()
{
Categories =new List<SelectListItem>();
}
}
and in my create action method,
public ActionResult Create()
{
var vm=new CreateCarVM();
vm.Categories=GetCategories();
return View(vm);
}
private List<SelectListItem> GetCategories()
{
var list=new List<SelectListItem>();
//2 items hard coded for demo. You may load it from db
list.Add(new SelectListItem { Value="1", Text="Sedan"});
list.Add(new SelectListItem { Value="2", Text="SUV"});
return list;
}
and in your View which is strongly typed to the CreateCarVM
#model CreateCarVM
#using(Html.BeginForm())
{
#Html.TextBoxFor(s=>s.Title)
#Html.DropDownListFor(s=>s.SelectedCategory,Model.Categories,"Select")
<input type="submit" />
}
Now when the form is posted, You can check the SelectedCategory property of the viewmodel
[HttpPost]
public ActionResult Create(CreateCarVM model)
{
if(ModelState.IsValid)
{
//check for model.SelectedCategory now
// to do :Save and Redirect (PRG pattern)
}
model.Categories=GetCategories();
return View(model);
}
My Model:
public class EntryModel
{
[Required]
public string Date { get; set; }
public string Car { get; set; }
public string Engine { get; set; }
public string User { get; set; }
public int CarCod { get; set; }
public int EngineCod { get; set; }
}
My View:
<%=Html.Label("Car")%>
<%=Html.Text("Car", car,new { #class = js_car")%>
<%=Html.ValidationMessageFor(x=>x.Car) %>
<%=Html.TextBox("CarCod", carCod, new { #class = "js_car", #style = "display:none;",#id="_car_cod" })%>
My Problem:
When posting the data, "CarCod" always fires an error at the ModelState, thus rendering both ModelState.IsValid and Html.ValidationSummary useless.
I already have workarounds for this (i.e not using them), but it would be very nice to know why.
To go off of what Garret said, make CarCod and EngineCod nullable.
It looks like you're hiding the CarCod textbox so it will be submitted with an empty string. The Model expects it to be an int so it's having problems converting that to an integer. What happens if you set the value to "0"?