I encountered the next indexer syntax during binding my model with collection to view.
Here is what I have:
public class CustomerModel
{
public List<Customer> Customers { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ImportAction ImportAction { get; set; }
}
public enum ImportAction
{
Skip,
Add,
Merge
}
My view:
#using (Html.BeginForm("Edit", "Home"))
{
var index = 0;
foreach (var customer in Model.Customers)
{
<span>Name: #customer.Name</span>
#Html.DropDownListFor(x => x.Customers[index].ImportAction, customer.ImportAction.ToListItems())
index++;
}
<button type="submit">
Submit</button>
}
How to avoid this [index] usage? Any other correct syntax? Take to the look, that without it #Html.DropDownListFor would not work and update my model on post back.
you can use the loop variable 'customer' like the following:
#Html.DropDownListFor(x => customer.ImportAction)
Related
I am creating a filter view to find records. This example on SO helps, but does not mention how handle the (Filtered) View.
The err below is because, the actions returns a List<ProductViewModel>, and it Errors/complains that the View is using a SearchViewModel, I need to this POST the searchmodel/variables, butGET back the list/results model
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[ViewModels.ProductVM]', but this
dictionary requires a model item of type 'ViewModels.SearchModel'.
Issue/Question: Since there are two models, the SearchViewModel passed to the controller & the ProductViewModel returned as a result, which model should be strongly typed to the view? and How can I create the view to handle both SearchModel & ProductModel If I stronglyType ProductVM, then I loose the submitform from the SearchVM.
I create the SearchView as the mainview, & the _ResultsPartialView as a partialView, is this wrong?
public ActionResult Index(SearchModel searchModel)
{
var filteredProdVMList = _Repository.GetFilteredProducts(searchModel);
return View(filteredProdVMList);
}
public class ProductVM
{
public int Id { get; set; }
public int Price { get; set; }
public string Name { get; set; }
// implicit const... blah.. removed
}
public class SearchModel
{
public int? Id { get; set; }
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
public string Name { get; set; }
}
You need to modify your SearchModel to include a collection property for the products
public class SearchModel
{
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
....
public IEnumerable<ProductVM> Products { get; set; } // add
}
then you return just SearchModel to your view
public ActionResult Filter(SearchModel filter)
{
filter.Products = _repository.GetFilteredProducts(filter);
return View(filter);
}
and your view will be
#model SearchModel
....
#using (Html.BeginForm("Filter", "yourControllerName", FormMethod.Get))
{
#Html.LabelFor(m => m.PriceFrom)
#Html.EditorFor(m => m.PriceFrom)
#Html.ValidationMessageFor(m => m.PriceFrom)
... // other form controls for properties you want to filter the results on
<input type="submit" value="Filter" />
}
#Html.Partial("_ResultsPartialView", Model.Products)
I'm new to MVC, and stuck on what should be a pretty straight forward issue. I'm working through this tutorial and got everything pretty much working, except I now want to add a foreign key 'link' (not sure what it's called) but can't seem to get it to work. Here's what I have:
Tables:
Inventory:
Id | SerialNumber | ManufacturerId (foreignkey to Manufactueres->id)
Manufactureres
Id (primary key) | Name
Model (InventoryItem.cs):
public class InventoryItem {
public int Id {get; set; }
public int SerialNumber{ get; set; }
//this starts the trouble, I actually want to interact with the Manufactureres table -> Name column
public int ManufacturerId { get; set; }
}
View (Create.cshtml):
...
//What i really want is a dropdown of the values in the Manufactureres table
#Html.EditorFor(model=> model.ManufacturerId)
This must be a farely common issue when using a relational database there would be many foreign key relationships to be used/shown, but for some reason i can't find a tutorial or issue on stackoverflow that directly corresponds to something so simple. Any guidance, or direction is much appreciated!
Thanks,
I hope I understand your question correctly. Seems like when you want to add a new inventory item then you want a list of all the manufacturers in a dropdown list. I am going to work on this assumption, please let me know if I am off the track :)
Firstly go and create a view model. This view model you will bind to yout view. Never bind domain objects to your view.
public class InventoryItemViewModel
{
public int SerialNumber { get; set; }
public int ManufacturerId { get; set; }
public IEnumerable<Manufacturer> Manufacturers { get; set; }
}
Your domain objects:
public class InventoryItem
{
public int Id { get; set; }
public int SerialNumber{ get; set; }
public int ManufacturerId { get; set; }
}
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
Your controller might look like this:
public class InventoryItemController : Controller
{
private readonly IManufacturerRepository manufacturerRepository;
private readonly IInventoryItemRepository inventoryItemRepository;
public InventoryItem(IManufacturerRepository manufacturerRepository, IManufacturerRepository manufacturerRepository)
{
// Check that manufacturerRepository and inventoryItem are not null
this.manufacturerRepository = manufacturerRepository;
this.inventoryItemRepository = inventoryItemRepository;
}
public ActionResult Create()
{
InventoryItemViewModel viewModel = new InventoryItemViewModel
{
Manufacturers = manufacturerRepository.GetAll()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(InventoryItemViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
Manufacturers = manufacturerRepository.GetAll()
return View(viewModel);
}
// All validation is cool
// Use a mapping tool like AutoMapper
// to map between view model and domain model
InventoryItem inventoryItem = Mapper.Map<InventoryItem>(viewModel);
inventoryItemRepository.Insert(inventoryItem);
// Return to which ever view you need to display
return View("List");
}
}
And then in your view you might have the following:
#model MyProject.DomainModel.ViewModels.InventoryItems.InventoryItemViewModel
<table>
<tr>
<td class="edit-label">Serial Number <span class="required">**</span></td>
<td>#Html.TextBoxFor(x => x.SerialNumber, new { maxlength = "10" })
#Html.ValidationMessageFor(x => x.SerialNumber)
</td>
</tr>
<tr>
<td class="edit-label">Manufacturer <span class="required">**</span></td>
<td>
#Html.DropDownListFor(
x => x.ManufacturerId,
new SelectList(Model.Manufacturers, "Id", "Name", Model.ManufacturerId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.ManufacturerId)
</td>
</tr>
</table>
I hope this helps :)
Yes, this is common issue, you need select Manufactureres in action and then send them to view. You can use ViewBag or strontly typed view model.
Examples:
Problem populating dropdown boxes in an ASP.NET MVC 3
Application
Having difficulty using an ASP.NET MVC ViewBag and
DropDownListfor
MVC3 Razor #Html.DropDownListFor
This is what I would recommend you.
1) Create a Manufacturer model class
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
2) Create InventoryItem model class as follows
public class InventoryItem
{
public int Id { get; set; }
public int SerialNumber{ get; set; }
public int ManufacturerId { get; set; }
[ForeignKey("Id ")]
public Manufacturer Manufacturer{get; set;}
public IEnumerable<Manufacturer> Manufacturer {get;set;}
}
3) Make sure DbContext is also updated as follows
public DbSet<InventoryItem> InventoryItem {get;set;}
public DbSet<Manufacturer> Manufacturer{get;set;}
4) Controller
[HttpGet]
public ActionResult Create()
{
InventoryItem model = new InventoryItem();
using (ApplicationDbContext db = new ApplicationDbContext())
{
model.Manufacturer= new SelectList(db.Manufacturer.ToList(), "Id", "Name");
}
return View(model);
}
[HttpPost]
public ActionResult Create(InventoryItem model)
{
//Check the Model State
if(! ModelState.IsValid)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
model.Manufacturer= new SelectList(db.Manufacturer.ToList(), "Id", "Name");
return View(model);
}
}
using (ApplicationDbContext db = new ApplicationDbContext())
{
InventoryItem dto = new InventoryItem();
dto.SerialNumber= model.SerialNumber;
dto.Id= model.Id;
Manufacturer manudto = db.Manufacturer.FirstOrDefault(x => x.Id== model.Id);
dto.CatName = manudto.CatName;
db.Test.Add(dto);
db.SaveChanges();
}
TempData["SM"] = "Added";
return RedirectToAction("Index");
}
5) Make sure View has dropdownselect option in below format
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Id, Model.Manufacturer,"Select", new { #class = "form-control" } )
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "text-danger" })
</div>
</div>
Hope this works :D
I am developing an ASP.Net MVC 3 Web application and I am having difficulties retrieving the selected checkbox values within the HttpPost method in my Controller. Hopefully someone can help.
I have 2 ViewModels
public class ViewModelShiftSubSpecialties
{
public IEnumerable<ViewModelCheckBox> SpecialtyList { get; set; }
}
public class ViewModelCheckBox
{
public string Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
public string Specialty { get; set; }
}
And a partial View I use as an EditorTemplate
#model Locum.UI.ViewModels.ViewModelCheckBox
#Html.HiddenFor(x => x.Id)
#Html.CheckBoxFor(x => x.Checked)
#Html.LabelFor(x => x.Name, Model.Name)<br />
In my View I create the checkboxes under two headings, Medicine and Surgery
<h3>Medicine</h3>
foreach (var sub in Model.SpecialtyList)
{
if (sub.Specialty.Equals("Medicine"))
{
#Html.EditorFor(m => sub)
}
}
<h3>Surgery</h3>
foreach (var sub in Model.SpecialtyList)
{
if (sub.Specialty.Equals("Surgery"))
{
#Html.EditorFor(m => sub)
}
}
And then in my HttpPost Controller I try to get the values of the selected checkboxes, but mode.SpecialtyList is always Null
[HttpPost]
public ActionResult AssignSubSpecialties(ViewModelShiftSubSpecialties model)
{
foreach (var item in model.SpecialtyList)
{
if (item.Checked)
{
//do some logic
}
}
return View();
}
Does anyone know why model.SpecialtyList is always Null?
Any help is much appreciated.
Thanks.
give checkboxes same names like:
<input type="checkbox" name="ViewModelShiftSubSpecialties.SpecialtyList" .../>
and it will post an array
I am trying to use dropdownList with two foreign keys which are modelId, and categoryId.
And I am using ViewBag with selectList.
public ActionResult Create()
{
ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name");
ViewBag.modelId = new SelectList(db.Model, "modelId", "name");
return View();
}
//
// POST: /Product/Create
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
db.Product.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name", product.categoryId);
ViewBag.modelId = new SelectList(db.Model, "modelId", "name", product.modelId);
return View(product);
}
And here is my Create.cshtml.
<div class="editor-label">
#Html.LabelFor(model => model.Category)
</div>
<div class="editor-field">
#Html.DropDownList("categoryId", "--Select--")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Model)
</div>
<div class="editor-field">
#Html.DropDownList("modelId", "--Select--")
</div>
When I press submit button, error come up,
'An item with the same key has already been added'
What is problem? Is it problem with in Model?
Here is my models.
--Prodruct.cs--
public class Product
{
[Key] public int productId { get; set; }
[Required(ErrorMessage = "Please select category")]
public int categoryId { get; set; }
[Required(ErrorMessage = "Please select model")]
public int modelId { get; set; }
[DisplayName("Model name")]
public String model { get; set; }
public virtual Category Category { get; set; }
public virtual Model Model { get; set; }
}
--Category.cs--
public class Category
{
[Key] public int categoryId { get; set; }
public String name { get; set; }
}
--Model.cs--
public class Model
{
[Key] public int modelId { get; set; }
public String name { get; set; }
}
--RentalDB.cs--
public class rentalDB : DbContext
{
public DbSet<Product> Product { get; set; }
public DbSet<Model> Model { get; set; }
public DbSet<Customer> Customer { get; set; }
public DbSet<Order> Order { get; set; }
public DbSet<Cart> Cart { get; set; }
public DbSet<Category> Category { get; set; }
public DbSet<OrderDetails> OrderDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Where it is wrong? Index page in Create can get category data and model data. However, when I submit it, it has error, 'An item with the same key has already been added'.
Could you help me where has got problem?
Thank you.
--added more coding--
I am using this LINQ. Probably here has problem.
How can I add 'Model' entity in here?
var product = from a in db.Product.Include(a => a.Category)
select a;
This is how I would have done it..
I would suggest that you don't send your domain models to the view, but rather create a view model for each view. Doing it this way you will only include what is needed on the screen.
Create a new view model for your Create view:
public class ProductCreateViewModel
{
// Include other properties if needed, these are just for demo purposes
public string Name { get; set; }
public string SKU { get; set; }
public string LongDescription { get; set; }
// This is the unique identifier of your category,
// i.e. foreign key in your product table
public int CategoryId { get; set; }
// This is a list of all your categories populated from your category table
public IEnumerable<Category> Categories { get; set; }
// This is the unique identifier of your model,
// i.e. foreign key in your product table
public int ModelId { get; set; }
// This is a list of all your models populated from your model table
public IEnumerable<Model> Models { get; set; }
}
Category class:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
Model class:
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
In your Create view you would have the following:
#model MyProject.ViewModels.ProductCreateViewModel
#using (Html.BeginForm())
{
<table>
<tr>
<td><b>Category:</b></td>
<td>
#Html.DropDownListFor(x => x.CategoryId,
new SelectList(Model.Categories, "Id", "Name", Model.CategoryId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.CategoryId)
</td>
</tr>
<tr>
<td><b>Model:</b></td>
<td>
#Html.DropDownListFor(x => x.ModelId,
new SelectList(Model.Models, "Id", "Name", Model.ModelId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.ModelId)
</td>
</tr>
</table>
<!-- Add other HTML controls if required and your submit button -->
}
Your Create action methods:
public ActionResult Create()
{
ProductCreateViewModel viewModel = new ProductCreateViewModel
{
// Here you do database calls to populate your dropdowns
Categories = categoryService.GetAllCategories(),
Models = modelService.GetAllModels()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(ProductCreateViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
viewModel.Categories = categoryService.GetAllCategories();
viewModel.Models = modelService.GetAllModels();
return View(viewModel);
}
// Mapping
Product product = ... // Do your mapping here
// Insert product in database
productService.Insert(product);
// Return the view where you need to be
}
I would also recommend that you use AutoMapper to do the mappings for you between your domain model and view model. I would also recommend that you look at Fluent Validation to take care of your view model validations.
I hope this helps.
UPDATED ANSWER
The service that was used to get all the categories could look like this:
public class CategoryService : ICategoryService
{
private readonly ICategoryRepository categoryRepository;
public CategoryService(ICategoryRepository categoryRepository)
{
// Check if category repository is not null, throw exception if it is
this.categoryRepository = categoryRepository;
}
public IEnumerable<Category> GetAllCategories()
{
return categoryRepository.GetAllCategories();
}
}
categoryRepository is injected by Autofac.
Category service interface:
public interface ICategoryService
{
IEnumerable<Category> GetAllCategories();
}
I currently still use Entity Framework 4.1 code first.
My category repository:
public class CategoryRepository : ICategoryRepository
{
MyContext db = new MyContext();
public IEnumerable<Category> GetAllCategories()
{
return db.Categories
.OrderBy(x => x.Name);
}
}
My category repository interface:
public interface ICategoryRepository
{
IEnumerable<Category> GetAllCategories()
}
public class Test
{
rentalDB db = new rentalDB();
public Product LoadProductById(int pId)
{
return db.Products.Include(p => p.Model).Include(p => p.Category).Where(p => p.productId == pId).SingleOrDefault();
} // To get specific product.
public IEnumerable<Product> LoadAllProducts()
{
return db.Products.Include(p => p.Model).Include(p => p.Category).ToList();
} // To get all products.
}
I have changed your DbSet to Products make it more clear. This is how you load all the references for one product or all products, in order to iterate over them.
i have a model :
public class person
{
public int id{get;set;}
public string name{get;set;}
}
how can i make a drop down list, from list of person in mvc3 razor by this syntax : #Html.DropDownListFor(...) ?
what type must be my persons list?
sorry I'm new in mvc3
thanks all
public class PersonModel
{
public int SelectedPersonId { get; set; }
public IEnumerable<Person> persons{ get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
then in the controller
public ActionResult Index()
{
var model = new PersonModel{
persons= Enumerable.Range(1,10).Select(x=>new Person{
Id=(x+1),
Name="Person"+(x+1)
}).ToList() <--- here is the edit
};
return View(model);//make a strongly typed view
}
your view should look like this
#model Namespace.Models.PersonModel
<div>
#Html.DropDownListFor(x=>x.SelectedPersonId,new SelectList(Model.persons,"Id","Name","--Select--"))
</div>
You should translate that to a List<SelectListItem> if you want to use the build in MVC HtmlHelpers.
#Html.DropDownFor(x => x.SelectedPerson, Model.PersonList)
Alternatively, you can simply make your own in the template:
<select id="select" name="select">
#foreach(var item in Model.PersonList)
{
<option value="#item.id">#item.name</option>
}
</select>