Get string from DropDownList - c#

I have XML file which contains my data and I want from dropdownlist save choose string to this xml.
In my view I have this:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>MatchXML</legend>
...
<div class="editor-label">
#Html.LabelFor(model => model.Team)
</div>
<div class="editor-field">
#Html.DropDownList("Team", (SelectList)ViewBag.Team, String.Empty)
#Html.ValidationMessageFor(model => model.Team)
</div>
...
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
In controller:
public ActionResult Pridat()
{
ViewBag.Team = new SelectList(repo.GetTeams(), "Name", "Name");
return View();
}
[HttpPost]
public ActionResult Pridat(MatchXML match, string Team)
{
if (ModelState.IsValid)
{
try
{
ViewBag.Team = new SelectList(repo.GetTeams(), "Name", "Name");
match.Team = repo.GetTeamByName(Team);
repo.AddMatch(match);
return RedirectToAction("Index");
}
catch (Exception ex)
{
//error msg for failed insert in XML file
ModelState.AddModelError("", "Error creating record. " + ex.Message);
}
}
return View(match);
}
Models looks:
public class MatchXML
{
public int MatchXMLID { get; set; }
public string Opponent { get; set; }
public DateTime MatchDate { get; set; }
public string Result { get; set; }
public Team Team { get; set; }
public int Round { get; set; }
}
public class Team
{
public int TeamID { get; set; }
public string Name { get; set; }
public virtual User Coach { get; set; }
public virtual ICollection<Player> Players { get; set; }
}
I was trying do some modification to do this but it is not working. I can do it with TeamID and saving ID but I want in xml save string (name of team). Thanks for help
Edit:
I updated show code of controller and view method.

You are binding the dropdown to the Team complex property (first argument of the DropDownList helper). This doesn't make sense. You can bind only to scalar values. I would also recommend you using the strongly typed version of the helper:
#Html.DropDownListFor(x => x.Team.TeamID, (SelectList)ViewBag.Team, String.Empty)
This way you will populate the TeamID property in the POST action with the selected value from the dropdown.
Also replace:
#Html.ValidationMessageFor(model => model.Team)
with:
#Html.ValidationMessageFor(model => model.Team.TeamID)

Related

ASP.NET MVC, C#, Entity Framework

I am trying to update supplier in database when users on webform insert data into textboxes.
First users in textbox for supplierID insert value, and on screen shows particular supplier from database. Then user can change supplier and when he is done he have to click on submit button.
I use EntityState.Modifier, but supplier doesn't change in database, and also I have no errors in the view. I think that's not working because my Supplier have foreign key from Adress table.
Does somebody know how to update using Entity state modified if a have a foreign key to another table?
I appreciate any help!
public partial class Supplier
{
public int SupplierID{ get; set; }
public string Name{ get; set; }
public string Phone{ get; set; }
public string Email { get; set; }
public Nullable<int> TownID{ get; set; }
public Nullable<int> StreetID{ get; set; }
public Nullable<int> AdressNumber{ get; set; }
public virtual Adress Adress { get; set; }
}
public partial class Town
{
public int TownID{ get; set; }
public string Name{ get; set; }
}
public partial class Street
{
public int TownID{ get; set; }
public int StreetID{ get; set; }
public string Name{ get; set; }
}
public partial class Adress
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Adress()
{
this.Supplier= new HashSet<Supplier>();
}
public int TownID{ get; set; }
public int StreetID{ get; set; }
public int AdressNumber{ get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Supplier> Suppliercs{ get; set; }
}
This is my View:
#model FpisNada.Models.Supplier
#{
ViewBag.Title = "Index";
Layout = null;
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.TextBoxFor(model => model.SupplierID, new { #placeholder = "pib dobavljaca", style = " float:left" })
<div class="col-md-9">
#if (ViewBag.ListTown!= null)
{
#Html.DropDownListFor(m => m.TownID, ViewBag.ListTown as SelectList, "--select town--", new { #class = "form-control", style = " float:left" })
}
#Html.DropDownListFor(m => m.StreetID, new SelectList(""), "--select street--", new { #class = "form-control", style = " float:left" })
<div class="container">
#Html.TextBoxFor(model => model.AdressNumber, new { #class = "form-control"})
#Html.TextBoxFor(model => model.Email, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Name, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Phone, new { #class = "form-control"})
</div>
</div>
<input type="submit" value="Edit" />
}
My controller method:
[HttpGet]
public ActionResult Edit(int id)
{
Supplier supplier= db.Supplier.Find(id);
return View(supplier);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit( Supplier supplier)
{
try
{
if (ModelState.IsValid)
{
db.Entry(supplier).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("ChangeSupplier");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
return View(supplier);
}

Cannot combine two models into a ViewModel

I have been trying to get two models to appear in a single view using ViewModels but am failing.
I have simple view with 3 fields right now (Comment, Name, Department) and and a model to match it. I have a controller that returns an empty view and when you submit the form, the empty model is filled in and passed back to the controller. I now want to turn the department field into a drop down and have deduced (maybe incorrectly?) that I should create another model with the static values in it and then pass the ViewModel to the view via the controller but when I attempt to do this, it fails:
View:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="fieldset">
<fieldset>
<legend>CommentDb</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Comment)
</div>
<div>
#Html.TextAreaFor(model => model.Comment, new {style = "width: 900px; height:200px;", autocomplete = "off" })
#Html.ValidationMessageFor(model => model.Comment)
</div>
<div class="editor-label">
#Html.Label("Your Name")
#*#Html.LabelFor(model => model.CommentByName)*#
#Html.TextBoxFor(model => model.CommentByName, new { autocomplete = "off", placeholder = "Optional" } )
#Html.ValidationMessageFor(model => model.CommentByName)
</div>
<div class="editor-label">
#Html.Label("Your Department", new { #class = "display-label" })
#*#Html.LabelFor(model => model.Department)*#
#Html.TextBoxFor(model => model.Department, new { autocomplete = "off", placeholder = "Optional" })
#Html.ValidationMessageFor(model => model.Department)
</div>
</fieldset>
<br />
<br />
</div>
<div>
<input type="submit" value="Create" id="submit"/>
</div>
}
Department drop down model:
namespace SuggestionBox.Models
{
public class DropDownModel
{
public String Departments { get; set; }
public String SetDropDownList()
{
Departments = "Engineering";
return Departments;
}
}
}
Database model:
namespace SuggestionBox.Models
{
public class CommentModel
{
[Key]
public int CommentiD { get; set; }
public string CommentByName { get; set; }
public string Department { get; set; }
[Required]
public string Comment { get; set; }
public DateTime InsertDate { get; set; }
}
}
namespace SuggestionBox.Models
{
public class CommentDbContext : DbContext
{
public CommentDbContext() : base()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<CommentDbContext, SuggestionBox.Migrations.Configuration>());
}
public DbSet<CommentModel> Comments { get; set; }
}
}
My attempted ViewModel:
namespace SuggestionBox.ViewModels
{
public class SuggestionBoxViewModel
{
public CommentModel Comments { get; set; }
public DropDownModel Departments { get; set; }
public SuggestionBoxViewModel()
{
Departments = new DropDownModel();
Departments.SetDropDownList();
Comments = new CommentModel();
}
}
}
The Controller:
public ViewResult Index()
{
SuggestionBoxViewModel vm = new SuggestionBoxViewModel();
return View(vm);
}
In return View(vm);, the IDE says: Arguement type 'SuggestionBox.ViewModels.SuggestionBoxViewModel' is not assignable to the model type 'SuggestionBox.Models.CommentModel'
Any idea what I am doing wrong here?
Cheers.
You are making a simple task into something overly complex. Your view model should contain only the properties used in the view, and should not contain methods. Populating your view model properties is the responsibility of the controller.
View model
public class CommentModelVM
{
[Required]
public string Comment { get; set; }
public string CommentByName { get; set; }
[Display(Name="Your Department")] // add attributes associated with the view
public string Department { get; set; }
public SelectList DepartmentList { get; set } // to populate the dropdown options
}
Controller
public ActionResult Create()
{
CommentModelVM model = new CommentModelVM();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(CommentModelVM model)
{
if (!ModelState.IsValid())
{
// Repopulate options and return view
ConfigureViewModel(model);
return View(model);
}
// Save and redirect
}
private void ConfigureViewModel(CommentModelVM model)
{
List<string> departments = // create your list of departments here (from database or static list)
model.DepartmentList = new SelectList(departments);
}
View
....
#Html.LabelFor(m => m.Department)
#Html.DropDownListFor(m => m.Department, Model.DepartmentList)
....
I just want to start by saying that generally it is a bad idea to name properties or classes for our ViewModels out the view controls that they are bound to. For example: DropDownModel. Doing this creates confusion since Models and ViewModels don't represent a UI component they represent entities and data that the view uses to render its UI controls.
With that being said to answer you question I don't see the need for a ViewModel class to represent the static list of departments for your dropdown. I think you should just add a new list of departments to your SuggestionBoxViewModel class like this:
namespace SuggestionBox.ViewModels
{
public class SuggestionBoxViewModel
{
public CommentModel Comments { get; set; }
public IEnumerable<string> Departments { get; set; }
public string SelectedDepartment { get; set; }
public SuggestionBoxViewModel()
{
Departments = new [] {"Engineering","Sales"};
Comments = new CommentModel();
}
public int CommentiD
{
get { return Comments.CommentiD; }
}
public string CommentByName
{
get { return Comments.CommentByName; }
}
}
}
Then in your view all you have to do is bind the dropdown to the list of departments. Like this:
At the top of your view:
#model SuggestionBox.ViewModels.SuggestionBoxViewModel
Then where you want the dropdown to display:
#Html.DropDownListFor(m => m.SelectedDepartment, new SelectList(Model.Departments))
And that's it! I hope this helps.
Your View seems to expect a Comment Model.
If you wanted to bind to a ViewModel, then you would have to implement all the properties that Comment exposes.
So your ViewModel might look like this:
namespace SuggestionBox.ViewModels
{
public class SuggestionBoxViewModel
{
public CommentModel Comments { get; set; }
public DropDownModel Departments { get; set; }
public SuggestionBoxViewModel()
{
Departments = new DropDownModel();
Departments.SetDropDownList();
Comments = new CommentModel();
}
public int CommentiD
{
get { return Comments.CommentiD; }
}
public string CommentByName
{
get { return Comments.CommentByName; }
}
...etc.
}
}

MVC client-side validation for multiple models

I have three models: VehicleType, VehicleModel, and VehicleManufacturer.
Both VehicleType and VehicleManufacturer point to VehicleModel in the model, like so:
public class VehicleModel
{
[Key]
public int ModelId { get; set; }
[Required(ErrorMessage = "Field is Required")]
public int TypeId { get; set; }
[Required(ErrorMessage = "Field is Required")]
public int ManufacturerId { get; set; }
public string ModelName { get; set; }
public VehicleType VehicleType { get; set; }
public VehicleManufacturer Manufacturer { get; set; }
}
From there, VehicleModel points to the InventoryModel:
public class Inventory
{
[Key]
public int InventoryId { get; set; }
public int Price { get; set; }
public int Mileage { get; set; }
public int Year { get; set; }
public int ModelId { get; set; }
public VehicleModel VehicleModel { get; set; }
}
My problem is when I try to get client-side validation working on all three dropdownlists (VehicleType, VehicleManufacturer, VehicleModel), it only works with VehicleModel.
What needs to be done to validate these two dropdownlists using these models?
Here is my controller (fyi):
// GET: /Inventory/Create
public ActionResult Create()
{
ViewBag.TypeId = new SelectList(db.Types, "TypeId", "TypeName"); //(Object List, Value Field (usually Id), Column)
ViewBag.ModelId = new SelectList(db.Models, "ModelId", "ModelName"); //(Object List, Value Field (usually Id), Column)
ViewBag.ManufacturerId = new SelectList(db.Manufacturers, "ManufacturerId", "ManufacturerName"); //(Object List, Value Field (usually Id), Column)
return View();
}
// POST: /Inventory/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Inventory inventory, VehicleManufacturer VehicleManufacturer, VehicleType VehicleType)
{
if (ModelState.IsValid)
{
db.Inventorys.Add(inventory);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TypeId = new SelectList(db.Types, "TypeId", "TypeName");
ViewBag.ModelId = new SelectList(db.Models, "ModelId", "ModelName");
ViewBag.ManufacturerId = new SelectList(db.Manufacturers, "ManufacturerId", "ManufacturerName");
return View(inventory);
}
View:
<div class="editor-label">
#Html.LabelFor(model => model.VehicleModel.TypeId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("TypeId", String.Empty)
#Html.ValidationMessageFor(model => model.VehicleModel.TypeId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ModelId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("ModelId", String.Empty)
#Html.ValidationMessageFor(model => model.ModelId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VehicleModel.ManufacturerId, "Some name for column")
</div>
<div class="editor-field">
#Html.DropDownList("ManufacturerId", String.Empty)
#Html.ValidationMessageFor(model => model.VehicleModel.ManufacturerId)
</div>
Please someone help. I've been on this for many, many hours!
There are actually two problems That I see above
1) That you're not mapping the DropDownList and the ValidationMessageFor to the same model attribute.
#Html.ValidationMessageFor(model => model.VehicleModel.ManufacturerId)
The above is binding it to VehicleModel_ManufacturerId where as:
#Html.DropDownList("ManufacturerId", String.Empty)
the above is mapping the DropDown to just ManufacturerId
You need to change one or the other to match each other.
2) In the above code, I don't see any Validation Attributes. did you forgot them when you copied the code over here?
Hope this helps, Let me know if you needed more details.

Null Reference Exception when i use navigation property in model class

I try to add new entity in database in controller action.
This is my model class
public class Product
{
public int ProductID { get; set; }
[Required(ErrorMessage = "Please enter product name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter product model")]
public string Model { get; set; }
[Required(ErrorMessage = "Please enter product serial")]
public string Serial { get; set; }
[Required(ErrorMessage = "Please choose dealer")]
public int DealerID { get; set; }
[Required]
public Guid ClientID { get; set; }
[Required(ErrorMessage = "Please choose employee")]
public Guid EmployeeID { get; set; }
public virtual Dealer Dealer { get; set; }
public virtual Client Client { get; set; }
public virtual Employee Employee { get; set; }
[DisplayName("Commercial use")]
public bool UseType { get; set; }
}
This is actions for creating new product in database
public ViewResult Create()
{
PopulateDropDownLists();
var model = new Product();
return View(model);
}
[HttpPost]
public ActionResult Create(Product model)
{
try
{
if (ModelState.IsValid)
{
_repo.GetRepository<Product>().Add(model);
_repo.Save();
TempData["message"] = "Product was successfully created";
return RedirectToAction("List");
}
}
catch (DataException)
{
TempData["error"] =
"Unable to save changes. Try again, and if the problem persists, see your system administrator.";
return View("Error");
}
PopulateDropDownLists();
return View("Create");
}
CreateView has appropriate model type (Product type in this case). Code below
#using System.Web.Mvc.Html
#model STIHL.WebUI.Models.Product
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Model)
#Html.EditorFor(m => m.Serial)
<div class="form-group">
#Html.LabelFor(m => m.DealerID, "Dealer")
#Html.DropDownListFor(m => m.DealerID, new SelectList((IEnumerable)TempData["Dealers"],"DealerID", "DealerNumber"), string.Empty, new {#class = "form-control"})
#Html.ValidationMessageFor(m => m.DealerID, null, new {#class = "help-block"})
</div>
<div class="form-group">
#Html.LabelFor(m => m.EmployeeID, "Employee",new {#class = "control-label"})
#Html.DropDownListFor(m => m.EmployeeID, new SelectList((IEnumerable)TempData["Employees"],"EmployeeID", "FullName"),string.Empty, new {#class="form-control"})
#Html.ValidationMessageFor(m => m.EmployeeID, null, new {#class = "help-block"})
</div>
<div class ="ok-cancel-group">
<input class="btn btn-primary" type="submit" value="Create" />
#Html.ActionLink("Cancel", "List","Product",new {#class = "btn btn-primary"})
</div>
}
i always get null reference instead model in [HttpPost] action, but if i use ViewModel instead Model everything is ok (ViewModel code below)
public class ProductViewModel
{
public Product Product { get; set; }
}
I think it cause model class has virtual properties, but anyway i don't understand why it's ok when i use ViewModel.
Can anyone answer me?
Thx in advance.
The virtual properties won't change the outcome. The issue is that the view is written to bind to the view model, therefore accepting the model isn't going to work. If you want to use the model; then bind the view to the model.

MVC model binding keeps values NULL

I'm trying to get custom model binding to work, but for some reason the values aren't set. The code seems ligit when comparing it to working code, but still it doesnt bind. I guess it some trivial thing i'm missing.
Custom model:
//Cluster is from Entity Framework
//BaseViewModelAdmin defines:
public List<KeyValuePair<string, string>> MenuItems;
public IPrincipal CurrentUser = null;
public Foundation Foundation; //also from Entity Framework
public class AdminClusterCreateModel : BaseViewModelAdmin
{
public Cluster Item;
public AdminClusterCreateModel()
{
Item = new Cluster();
}
}
The view form looks like:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Cluster</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Active)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Active)
#Html.ValidationMessageFor(model => model.Item.Active)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Name)
#Html.ValidationMessageFor(model => model.Item.Name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
And the controller:
[HttpPost]
public ActionResult Create(AdminClusterCreateModel model, FormCollection form)
{
if(ModelState.IsValid) //true
{
var test = form["Item.Name"]; //Value is correct from form (EG: Test)
UpdateModel(model); //no error
}
//At this point model.Item.Name = null <--- WHY?
return View(model);
}
Cluster on request
public partial class Cluster
{
public Cluster()
{
this.Team = new HashSet<Team>();
}
public long Id { get; set; }
public System.DateTime Created { get; set; }
public System.DateTime Modified { get; set; }
public bool Active { get; set; }
public long FoundationId { get; set; }
public string Name { get; set; }
public virtual Foundation Foundation { get; set; }
public virtual ICollection<Team> Team { get; set; }
}
DefaultModelBinder works explicitly on 'Properties', not on 'Fields'
Changing public Cluster Item to public Cluster Item {get; set;} in AdminClusterCreateModel should do the trick.
public class AdminClusterCreateModel : BaseViewModelAdmin
{
public Cluster Item {get; set;}
public AdminClusterCreateModel()
{
Item = new Cluster();
}
}
Regards
This is a trivial and a corner case, yet if it might help someone:
If your model has a property, named model this to will cause the DefaultModelBinder to return a null.
public class VehicleModel
{
public string Model { get; set; }
}

Categories

Resources