I am super new to MVC3 and C#, so excuse my noob questions. I have been struggling with this for almost a full day and hope someone can shed some light (I have scoured this site for clues, hints, answers as well).
I have a single table in my database which will hold all the data. It is for a profile editor which will store values that the user can populate their timekeeping entry form automatically upon select. I am on step one though, trying to populate the first dropdownlist with the profile name. I am using LINQ, MVC3/ Razer, and C#.
Here is my dbml:
Cant post image cause I am new
http://imageshack.us/photo/my-images/560/timem.png/
Here is my model:
namespace Timekeeping.Models
{
public class Profile
{
public int Profile_ID { get; set; }
public string profilename { get; set; }
public string networkuserid { get; set; }
public int projectnumber { get; set; }
public int costcode { get; set; }
public int paycode { get; set; }
public int jobtype { get; set; }
public int workorder { get; set; }
public int activity { get; set; }
public string taxarea { get; set; }
public IEnumerable<Profile> profiles { get; set; }
}
public class ProfileViewModel
{
public int Profile_ID { get; set; }
public IEnumerable<SelectListItem> profiles { get; set; }
}
}
Here is my Controller:
namespace Timekeeping.Controllers
public class TimeProfileController : Controller
{
private static String strConnString = ConfigurationManager.ConnectionStrings["timekeepingConnectionString"].ConnectionString;
[HttpGet]
public ActionResult ProfileSelect()
{
profileConnectionDataContext dataContext = new profileConnectionDataContext(strConnString);
var model = new ProfileViewModel();
var rsProfile = from fbs in dataContext.TimeProfiles select fbs;
ViewData["ProfileList"] = new SelectList(rsProfile, "Profile_ID", "profilename");
return View(model);
}
}
And here are all the different html helpers I have tried for my View(none work):
#Html.DropDownList("rsProfile", (SelectList)ViewData["ProfileList"]))
#Html.DropDownListFor(
x => x.Profile_ID,
new SelectList(Model.profiles, "Values", "Text"),
"-- Select--"
)
#Html.DropDownListFor(model => model.Profile_ID, Model.profilename)
I know this is a mess to look at, but I am hoping someone can help so I can get on with the hard parts. Thanks in advance for any help I get from the community
Hope it will work surely...
Inside Controller :
var lt = from result in db.Employees select new { result.EmpId, result.EmpName };
ViewData[ "courses" ] = new SelectList( lt, "EmpId", "EmpName" );
Inside View :
<%: Html.DropDownList("courses") %>
Try this:
public class TimeProfileController : Controller
{
private static String strConnString = ConfigurationManager.ConnectionStrings["timekeepingConnectionString"].ConnectionString;
[HttpGet]
public ActionResult ProfileSelect()
{
var dataContext = new profileConnectionDataContext(strConnString);
var profiles = dataContext.TimeProfiles.ToArray().Select(x => new SelectListItem
{
Value = x.Profile_ID,
Text = x.profilename
});
var model = new ProfileViewModel
{
profiles = profiles
};
return View(model);
}
}
and in the view:
#model ProfileViewModel
#Html.DropDownListFor(
x => x.Profile_ID,
new SelectList(Model.profiles, "Values", "Text"),
"-- Select--"
)
If you are using a model class just try this:
<%: Html.DropDownList("EmpId", new SelectList(Model, "EmpId", "EmpName")) %>
If you want to add click event for drop down list try this:
<%: Html.DropDownList("courses", ViewData["courses"] as SelectList, new { onchange = "redirect(this.value)" }) %>
In the above one redirect(this.value) is a JavaScript function
Related
I was trying nested Editor Templates but couldnt get it working. The structure of my model is
public class CompanyModel
{
public EmployeeModel Emp { get; set; }
}
public class EmployeeModel
{
public EmpType EmployeeType { get; set; }
public string Name { get; set; }
public DateTime StartDate { get; set; }
public string EmailAddress { get; set; }
}
public enum EmpType
{
Manager = 1,
Assistant = 2,
TeamLeader = 3
}
Each EmpType will have different EditorTemplates
The Index view is
#model CompanyModel
<h3>Index</h3>
#Html.EditorFor(m => m.Emp,"Employee")
Then i have create EditorTemplates(Employee.cshtml)
#model EmployeeModel
<h2>Employee</h2>
#Html.EditorForModel("EmpType_"+ Model.EmployeeType.ToString())
EditorTemplate(EmpType_Manager.cshtml)
#model EmployeeModel
<h2>EmpType_Manager</h2>
I am Manager
For testing i am populating the model with dummy data in the controller
public ActionResult Index(CompanyModel model)
{
EmployeeModel emp = new EmployeeModel
{
EmployeeType = EmpType.Manager,
Name = "xxxx",
StartDate = DateTime.Now,
EmailAddress = "xxx#yyy.com"
};
model = new CompanyModel();
model.Emp = emp;
return View(model);
}
When i run this it does not call the EmpType_Manager template. Can some one help me on this. I have tried using partial view which works. But would like to use EditorTemplate instead of Partial view.
Well looks like this is not possible as it is by mvc design.
I am trying to update a compound page model which as one of its properties has a list of objects.
My Model looks like this:
public class PageViewModel
{
public ProgramListVM ProgramsDDL { get; set; }
public PageViewModel()
{
this.ProgramsDDL = new ProgramListVM();
}
}
The ProgramListVM class is:
public class ProgramListVM
{
public List<ProgramVM> Program_List { get; set; }
public int SelectedValue { get; set; }
public ProgramListVM()
{
this.Program_List = new List<ProgramVM>();
this.SelectedValue = 0;
}
}
and ProgramVM is:
public class ProgramVM
{
public int ProgramID { get; set; }
public string ProgramDesc { get; set; }
public ProgramVM(int id, string code)
{
this.ProgramID = id;
this.ProgramDesc = code;
}
}
I try to render this dropdownlist by the following two:
1-
<%: Html.DropDownList("ProgramsDDL", new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc", Model.Page6VM.ProgramsDDL.SelectedValue))%>
2-
<%: Html.DropDownListFor(m => m.Page6VM.ProgramsDDL.Program_List, new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc"), Model.Page6VM.ProgramsDDL.SelectedValue)%>
But when I try to update my model through a controller action
[HttpPost]
public ActionResult UpdateUser(PageViewModel model)
{
}
model.ProgramsDDL.count is zero.
What is the best way to render this dropdownlist and be able to set the selected index, and also be able to send the selected index back to the controller?
You mixed up the parameters for Html.DropDownListFor(). Code sample below should work.
<%: Html.DropDownListFor(m => m.SelectedValue,
new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc"),
null) %>
You also should have a SelectedValue in your model that's posted back.
public class PageViewModel
{
public ProgramListVM ProgramsDDL { get; set; }
public int SelectedValue { get; set; }
public PageViewModel()
{
this.ProgramsDDL = new ProgramListVM();
}
}
Also default model binder can't map complex collections to your model. You probably don't need them in your post action anyway.
I have an Inventory Class that contains not only its own fields but several reference IDs to other classes.
public class Inventory {
public int Id { get; set; }
public string RtNum { get; set; }
public string AcntNum { get; set; }
public string CardNum { get; set; }
public string Num { get; set; }
[Range(1,3)]
public int Type { get; set; }
public int CompanyId { get; set; }
public int BranchId { get; set; }
public int PersonId { get; set; } }
In my action I generate several IEnumerable lists of the relevant fields from the other classes. I also have several non-list values I want to pass to the View. I know how to create a ViewModel to pass everything to the webgrid but have no way of iterating through the lists. I also know how to AutoMap an index to one list, see How to display row number in MVC WebGrid.
How would you combine the two so that you could use the index to iterate through multiple lists?
Update #1 (more detail)
public class Company {
public int Id { get; set; }
public string Name { get; set; } }
public class Branch {
public int Id { get; set; }
public string Name { get; set; } }
public class Person {
public int Id { get; set; }
public string Name { get; set; } }
public class MyViewModel {
public int PageNumber { get; set; }
public int TotalRows { get; set; }
public int PageSize { get; set; }
public IEnumerable<Inventory> Inventories { get; set; }
public int Index { get; set; }
public IEnumerable<string> CmpNm { get; set; }
public IEnumerable<string> BrnNm { get; set; }
public IEnumerable<string> PrnNm { get; set; } }
Controller
public class InventoryController : Controller
{ // I have a paged gird who’s code is not relevant to this discussion but a pagenumber,
// pagesize and totalrows will be generated
private ProjectContext _db = new ProjectContext();
public ActionResult Index() {
IEnumerable<Inventory> inventories = _db.Inventories;
List<string> cmpNm = new List<string>; List<string> brnNm = new List<string>; List<string> prnNm = new List<string>;
foreach (var item in inventories) { string x1 = "";
Company cmps = _db. Company.SingleOrDefault(i => i.Id == item.CompanyId); if (cmps!= null)
{ x1 = cmps.Name; } cmpNm.Add(x1); x1 = "";
Branch brns = _db. Branch.SingleOrDefault(i => i.Id == item. Branch Id); if (brns!= null) { x1 = brns.Name; } brnNm.Add(x1); x1 = "";
Person pers = _db.Persons.SingleOrDefault(i => i.Id == item. PersonId);
if (pers!= null) { x1 = pers.Name; } prnNm.Add(x1);
// the MyViewModel now needs to populated with all its properties and generate an index
// something along the line of
new MyViewModel { PageNumber= pagenumber, PageSize= pagesize, TotalRows=Totalrows, Inventories = inventories; CmpNm=cmpNm, BrnNm=brnNm, PrnNm=prnNm}
View (How to create the Index is the problem)
#model.Project.ViewModels.MyViewModel
#{ var grid = new WebGrid(Model.Inventories, Model.TotalRows, rowsPerPage: Model.PageSize); }
#grid.GetHtml( columns: grid.Columns(
Grid.Column(“PrnNm”, header: "Person", format: #Model.PrnNm.ElementAt(Index))
Grid.Column(“BrnNm”, header: "Branch", format: #Model.BrnNm.ElementAt(Index))
Grid.Column(“CmpNm”, header: "Company", format: #Model.CmpNm.ElementAt(Index))
grid.Column("RtNum", header: "Route"),
grid.Column("AcntNum", header: "Account"),
grid.Column("CardNum", header: "Card")
… ) )
What the grid should look like is self-evident.
It's pretty unclear what is your goal. But no matter what it is I would recommend you to define a real view model reflecting the requirements of your view and containing only the information you are interested in seeing in this grid:
public class InventoryViewModel
{
public int Id { get; set; }
public string PersonName { get; set; }
public string BranchName { get; set; }
public string CompanyName { get; set; }
public string RouteNumber { get; set; }
public string AccountNumber { get; set; }
public string CardNumber { get; set; }
}
Now you could have the main view model:
public class MyViewModel
{
public int PageNumber { get; set; }
public int TotalRows { get; set; }
public IEnumerable<InventoryViewModel> Inventories { get; set; }
}
Alright, the view is now obvious:
#model MyViewModel
#{
var grid = new WebGrid(
Model.Inventories,
rowsPerPage: Model.PageSize
);
}
#grid.GetHtml(
columns: grid.Columns(
grid.Column("Id", header: "Inventory id"),
grid.Column("PersonName", header: "Person"),
grid.Column("BranchName", header: "Branch"),
grid.Column("CompanyName", header: "Company"),
grid.Column("RouteNumber", header: "Route"),
grid.Column("AccountNumber", header: "Account"),
grid.Column("CardNumber", header: "Card")
)
)
Now all that's left is build this view model in your controller. Since I don't know what you are trying to achieve here, whether you need an inner join or a left outer join on those columns, I will take as an example here a left outer join:
public ActionResult Index()
{
var inventories =
from inventory in _db.Inventories
join person in _db.Persons on inventory.PersonId equals person.Id into outerPerson
join company in _db.Companies on inventory.CompanyId equals company.Id into outerCompany
join branch in _db.Branch on inventory.BranchId equals branch.Id into outerBranch
from p in outerPerson.DefaultIfEmpty()
from c in outerCompany.DefaultIfEmpty()
from b in outerBranch.DefaultIfEmpty()
select new InventoryViewModel
{
PersonName = (p == null) ? string.Empty : p.Name,
CompanyName = (c == null) ? string.Empty : c.Name,
BranchName = (b == null) ? string.Empty : b.Name,
Id = inventory.Id,
AccountNumber = inventory.AcntNum,
CardNumber = inventory.CardNum,
RouteNumber = inventory.RtNum
};
var model = new MyViewModel
{
PageSize = 5,
// TODO: paging
Inventories = inventories.ToList()
};
return View(model);
}
And that's pretty much it. Of course in this example I am leaving the pagination of the Inventories collection for you. It should be pretty trivial now to .Skip() and .Take() the number of records you need.
As you can see ASP.NET MVC is extremely simple. You define a view model to reflect the exact requirements of what you need to show in the view and then populate this view model in the controller. Most people avoid view models because they fail to populate them, probably due to lack of knowledge of the underlying data access technology they are using. As you can see in this example the difficulty doesn't lie in ASP.NET MVC at all. It lies in the LINQ query. But LINQ has strictly nothing to do with MVC. It is something that should be learned apart from MVC. When you are doing MVC always think in terms of view models and what information you need to present to the user. Don't think in terms of what you have in your database or wherever this information should come from.
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
My model is
public class SiteConfig
{
public SiteConfig()
{
}
public int IdSiteConfig { get; set; }
public string Name { get; set; }
public byte[] SiteLogo { get; set; }
public string Brands { get; set; }
public string LinkColour { get; set; }
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
and
public class SiteBrand
{
public int Id { get; set; }
public int SiteId { get; set; }
public int BrandId { get; set; }
public Brand Brand { get; set; }
public SiteConfig SiteConfig { get; set; }
}
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
I am following Data Base first approach. Each SiteConfig record can contain one or more Brand. So Brand is saving to another table called SiteBrand.
SiteBrand contains the forign key reference to both SiteConfig(on IdSiteConfig) and Brand(BrandId).
When I am creating a SiteConfig I want to display all the available Brand as list box where user can select one or many record(may not select any brand).
But when I bind my view with the model how can I bind my list box to the list of brands and when view is posted how can I get the selected brands.
And I have to save the SiteConfig object to database with the selected Items. And this is my DB diagram.
This is my DAL which saves to db.
public SiteConfig Add(SiteConfig item)
{
var siteConfig = new Entities.SiteConfig
{
Name = item.Name,
LinkColour = item.LinkColour,
SiteBrands = (from config in item.SiteBrands
select new SiteBrand {BrandId = config.BrandId, SiteId = config.SiteId}).
ToList()
};
_dbContext.SiteConfigs.Add(siteConfig);
_dbContext.SaveChanges();
return item;
}
Can somebody advide how to bind the list box and get the selected items.
Thanks.
Add a new Property to your SiteConfig ViewModel of type string array. We will use this to get the Selected item from the Listbox when user posts this form.
public class SiteConfig
{
//Other properties here
public string[] SelectedBrands { get; set; } // new proeprty
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
In your GET action method, Get a list of SiteBrands and assign to the SiteBrands property of the SiteConfig ViewModel object
public ActionResult CreateSiteConfig()
{
var vm = new SiteConfig();
vm.SiteBrands = GetSiteBrands();
return View(vm);
}
For demo purposes, I just hard coded the method. When you implement this, you may get the Data From your Data Access layer.
public IList<SiteBrand> GetSiteBrands()
{
List<SiteBrand> brands = new List<SiteBrand>();
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 3, Name = "Nike" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 4, Name = "Reebok" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 5, Name = "Addidas" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 6, Name = "LG" } });
return brands;
}
Now in your View, which is strongly typed to SiteConfig ViewModel,
#model SiteConfig
<h2>Create Site Config</h2>
#using (Html.BeginForm())
{
#Html.ListBoxFor(s => s.SelectedBrands,
new SelectList(Model.SiteBrands, "Brand.BrandId", "Brand.Name"))
<input type="submit" value="Create" />
}
Now when user posts this form, you will get the Selected Items value in the SelectedBrands property of the ViewModel
[HttpPost]
public ActionResult CreateSiteConfig(SiteConfig model)
{
if (ModelState.IsValid)
{
string[] items = model.SelectedBrands;
//check items now
//do your further things and follow PRG pattern as needed
}
model.SiteBrands = GetBrands();
return View(model);
}
You can have a "ViewModel" that has both the site and brand model in it. Then you can bind your view to that model. This would allow you to bind any part of the view to any part of any of the underlying models.
public class siteViewModel{
public SiteConfig x;
public Brand b; //Fill this with all the available brands
}
Of course you can include any other information your view might need (reduces the need of ViewBag as well).