Dropdownlists not populating with data from 3 separate reference tables - c#

Currently I am working with ASP.Net MVC 6 using EF7. I am using the default controller generator. For some reason my drop downs are not populating with data on the create or edit page even though data is present.
Just to clarify the 3 select lists are being populated by 3 different tables that are all connected to the main table I am adding to.
Here's what I got.
Controller code
private readonly SchoolContext _context;
public SchoolsController(SchoolContext context)
{
_context = context;
}
public IActionResult Create()
{
ViewData["DistrictId"] = new SelectList(_context.Districts, "DistrictId", "District");
ViewData["LocationId"] = new SelectList(_context.Locations, "LocationId", "Location");
ViewData["TierId"] = new SelectList(_context.Tiers, "TierId", "Tier");
return View();
}
View code
#model School
is included at the top and here is what one of the select element looks like
<div class="form-group">
<label asp-for="DistrictId" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="DistrictId" class ="form-control"></select>
</div>
</div>
The select lists are completely blank with no errors there is data.
This is all generated automatically so I am totally clueless on what went wrong. Any suggestions?

You need both a property to bind to (the selected value) and a property for the options and they need to have different names. Ideally you should be using a view model which would have (say)
public class SchoolVM
{
public int DistrictId { get; set; }
public IEnumerable<SelectListItem> DistrictList { get; set; }
....
and in the GET method
public IActionResult Create()
{
SchoolVM model = new SchoolVM
{
DistrictList = new SelectList(_context.Districts, "DistrictId", "District"),
.....
};
return View(model);
}
and in the view
#model SchoolVM
....
<select asp-for="DistrictId" asp-items="Model.DistrictList"></select>
alternatively, you could use ViewBag or ViewData and use
<select asp-for="DistrictId" asp-items="ViewBag.DistrictList"></select>

Assuming your view name is School (the convention for ViewModel is name of the view + "ViewModel")
class SchoolViewModel
{
IEnumerable<SelectListItem> Districts;
IEnumerable<SelectListItem> Locations;
IEnumerable<SelectListItem> Tiers;
}
Then in your view,
#model SchoolViewModel
...
#Html.DropDownList("Districts", m=>m.Districts, "-- Select--")
#Html.DropDownList("Locations", m=>m.Locations, "-- Select--")
#Html.DropDownList("Tiers", m=>m.Tiers, "-- Select--")
In your controller
public IActionResult Create()
{
var vm = new SchoolViewModel();
vm.Districts = _context.Districts.Select(d => new
{
Text = d.District,
Value = d.DistrictId.ToString()
};
//repeat for others...
return View(vm);
}

Related

Setting an existing value for dropdown in MVC C# with Linq

I have a dropdown list rendered from a database, just need to be able to set an existing value (if it exists). _jobService.GetTenancyForJob gets a value if one already exists and the other service just returns an id and value for each item. I need to be able to set the selected list item here in the controller but just struggling with the syntax (yeah it's using viewbag just for testing will be using ViewModel).
I've done this before in a wide variety of ways just wondering how it would be done in this scenario... Any pointers appreciated.
var jobTenancies = _jobService.GetTenancyForJob(id);
var getTenancies = _jobService.GetAllJobTenancies();
var tenancyList = getTenancies.Select( t => new SelectListItem()
{
Text = t.JobTenancyName,
Value = t.Id.ToString()
}).ToList();
tenancyList.Insert(0, new SelectListItem() { Text="", Value = "" } );
Viewbag.TenancyList = tenancyList;
Edit: in the view
<div class="control-group">
#Html.BootstrapLabelFor(model => model.TenancyName)
<div class="controls">
#Html.DropDownListFor(x=>x.TenancyId, (List<SelectListItem>)ViewBag.TenancyList)
#Html.BootstrapValidationMessageFor(model => model.TenancyId)
</div>
</div>
You need to set the value of property TenancyId in the controller before you return the View. If the value matches the value of one of your options then that option will be selected when the view is displayed. Note also you should not be adding a 'empty' option by inserting an additional SelectListItem (which adds <option value="">), but rather use the overload of DropDownListFor() that accepts optionLabel which correctly adds an option with a null value (<option value>). As you indicated you intend to use a view model, it might include
public class TenancyVM
{
[Required(ErroMessage = "Please select tenancy")]
[Display(Name = "Tenancy")]
public int? TenancyID { get; set; }
....
public SelectList TenancyList { get; set; }
}
Controller
public ActionResult Edit(int id)
{
TenancyVM model = new TenancyVM();
model.TenancyID = jobService.GetTenancyForJob(id);
ConfigureEditModel(model);
return View(model);
}
// Gets called in the GET and in POST method if the view is returned
private void ConfigureEditModel(TenancyVM model)
{
var tenancies = _jobService.GetAllJobTenancies();
model.TenancyList = new SelectList(tenancies , "Id", "JobTenancyName");
}
View
<div class="control-group">
#Html.BootstrapLabelFor(m => m.TenancyID)
<div class="controls">
#Html.DropDownListFor(m => m.TenancyID, Model.TenancyList, "-Please select-")
#Html.BootstrapValidationMessageFor(m => m.TenancyID)
</div>
</div>
You need to cast your ViewBag data to SelectList as follow:
var data = (SelectList)Viewbag.TenancyList;
You need to do this because ViewBag carry object data type.
After casting you can get your tenacyList from data.Items.

Template ViewModel's SelectList property magically selected when rendered in view

I have a master-detail view that allow users to dynamically add child records through jQuery DOM manipulation0, and then posting the whole master-detail form back to my HttpPost Edit method. My master view model is like this:
public class FooViewModel
{
// Other properties skipped for brevity
public ICollection<BarViewModel> Bars { get; set; }
}
My child view model:
public class BarViewModel
{
public int BazId { get; set; }
public IEnumerable<SelectListItem> BazSelectList { get; set; }
}
In my Edit action, I populate my view model through Entity Framework and Automapper:
public class FooController : Controller
{
public ActionResult Edit(int id)
{
// Fetch from db through Entity Framework,
// project to view model through AutoMapper
var viewModel = FooRepository.GetById(id)
.Project()
.To<FooViewModel>()
.Single();
// Populate ViewBag with an empty template BarViewModel to be manipulated
// through jQuery
ViewBag.BarTemplateViewModel = new BarViewModel
{
BazSelectList = FooRepository.GetBazSelectList()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Edit(FooViewModel viewModel)
{
// Skipped for brevity
}
}
From the debugger, I made sure all SelectListItem in BazSelectList had the Selected property value of false when a GET request is triggered to my Edit action method. Then my view is rendered:
#model FooViewModel
#using (Html.BeginForm())
{
#*Other properties skipped for brevity*#
#*Model binding magic here, editor template rendered for each BarViewModel*#
#Html.EditorFor(m => m.Bars)
<button type="button" class="btn btn-default">Add Bar</button>
}
#* BarViewModel template here *#
#Html.Partial("EditorTemplates/BarViewModel",
(BarViewModel)ViewBag.BarTemplateViewModel)
My BarViewModel editor template:
#model BarViewModel
<div class="form-group">
#Html.LabelFor(m => m.BazId, new { #class = "col-md-5 control-label" })
<div class="col-sm-6">
#Html.DropDownListFor(m => m.BazId,
Model.BazSelectList,
string.Empty,
new { #class = "form-control" })
</div>
</div>
When the view renders, ViewBag.BarTemplateViewModel.BazSelectList has one of the SelectListItem selected when it shouldn't, since I am passing an empty BarViewModel instance to the ViewBag. This is confirmed since I can see BazSelectList being pre-selected when I clicked the "Add Bar" button. The expected behaviour is to have a non-selected dropdown list. Can anyone help?
Eventually I found a solution. Wrapping the IEnumerable<SelectListItem> to a call to the SelectList constructor solved my problem, i.e. changing this:
#Html.DropDownListFor(m => m.BazId,
Model.BazSelectList,
string.Empty,
new { #class = "form-control" })
to
#Html.DropDownListFor(m => m.BazId,
new SelectList(Model.BazSelectList, "Value", "Text"),
string.Empty,
new { #class = "form-control" })

how model use for display two tables in a view

I want to display elements of two tables in a view but I don't know how.
In my view i Have #model IEnumerable which point to 'Tmembre' class of the model and corresponding of the table 'Tmembre' in database.
I can display elements of this table in my view, OK.
but I also want to display elements of another table in the this view and I can't put other #model déclaration in the view.
I try to create a class in the model for two table and put the sql in the model but i think it s not in the model i have to request DB.
public class myviewmodel
{
public Tmembre tmembre { get; set; }
public List<Tmembre> GetlstMembre { // SQL }
public TAssociation tassociation { get; set; }
public List<TAssociation> GetlstAssociation { // SQL }
}
In your controller you can create a new instance of the above ViewModel and fill the members with data from your database.
Once done you should return this ViewModel to your View;
public ActionResult Index()
{
MyViewModel myViewModel = new MyViewModel();
myViewModel.lstmembre = ....;
myViewModel.1stassociation = ...;
return View(myViewModel);
}
In your view you can now specify the #model as your view model
#model myproject.web.models.MyViewModel
Now all members of this model should be available for you to access from your view
Model.1stmembre
Model.1stassociation
Model.tmembre
etc..
OK
ViewBag.Message = "Liste des membres";
//Chercher les informations du membre connecté
//Tmembre Membre = db.TmembresansEDMdb.Find(10);
//TAssociation association = db.dbTassociation.Find(Membre.Idassociation);
//ViewData.Model = (from a in db.TmembresansEDMdb
// where a.Idassociation == Membre.Idassociation
// select a );
myviewmodel mymodel = new myviewmodel();
Tmembre Membre = db.TmembresansEDMdb.Find(1);
mymodel.lstassociation = db.dbTassociation.ToList();
ViewData["Idassociation"] = Membre.Idassociation;
mymodel.lstmembre= (from a in db.TmembresansEDMdb
where a.Idassociation == Membre.Idassociation
select a ).ToList();
return View(mymodel);
In View
#foreach (var item in Model.lstassociation)
{
if (item.Nomassociation == #ViewData["Idassociation"])
{
<option selected>#item.Nomassociation</option>
} else {
<option>#item.Nomassociation</option>
}
}
#foreach (var item in Model.lstmembre) {
<div class="divmembre">
<div class="dphoto"><img src="~/Content/#item.SRCImage"/></div>
<div class="containerdetail">
<div class="ddetail">
<div class="ddetaild nom">#item.Nommembre</div>
<div class="ddetaild prenom">#item.Prenommembre</div>
<div class="ddetaild mail">#item.Mailmembre</div>
</div>
</div>
</div>
}
All elements of lstmembre are displayed but I want to select in a list the element of table Association corresponding with Idassociation in the view data. I have message : no entry point in
if (item.Nomassociation == ViewData["Idassociation"])
but if I use #ViewData["Idassociation"] in HTML Tag and not in a loop it s ok, the value is displayed. I think it s just a syntax error. tks

Update a Model and a Collection of Models on a Single View (MVC4)

I've been working on an MVC 4 Application and have run into a problem when attempting to update Models in a ViewModel.
My ViewModel (detailed below) contains one ComplexObjectOne and a List<ComplexObjectTwo>.
My GET ActionResult successfully populates the ViewModel from a database and everything displays correctly on my View.
The problem is encountered when attempting to pass the ComplexObjectOne and List<ComplexObjectTwo> to the POST ActionResult.
The ComplexObject is passed correctly but everything I've tried fails pass the List<ComplexObjectTwo> collection.
My ComplexModelOne Model
public class Test
{
public int Id {get;set;}
public string Result {get;set;}
public virtual ICollection<TestResult> TestResults {get;set;}
}
My ComplexModelTwo Model
public class TestResult
{
public int Id {get;set;}
public string Result {get;set;}
public string Comment {get;set;}
public virtual Test Test{get;set;}
}
My ViewModel
public class TestingViewModel
{
public TestingViewModel()
{
if(TestResults == null)
{
TestResults = new List<TestResult>();
}
}
public Test Test {get;set;}
public IEnumerable<TestResult> TestResults {get;set;}
}
My Edit() GET ActionResult
public ActionResult Edit(int id = 0)
{
var viewModel = new TestingViewModel();
Test test = testRepo.GetTestById(id);
var results = test.TestResults;
viewModel.Test = test;
viewModel.TestResults = results;
return View(viewModel);
}
My Edit() POST ActionResult
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(TestingViewModel model)
{
// do update - left out for brevity
}
My Edit.cshtml View
#model Namespace.Models.ViewModels.TestingViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(model => model.Test, "TestHeader")
<table>
<tr>
<th>Test</th>
<th>Result</th>
<th>Comment</th>
</tr>
#Html.EditorFor(model => model.TestResults, "TestResults")
</table>
<input type="submit" value="Update"/>
}
Within my View I do use a couple of EditorTemplates to display the property fields.
Any assistance, comments, or suggestions will be much appreciated. I'd like to be able to accomplish updating these entities on a single page instead of multiple pages which I resorted to in the Create() steps.
Thank you,
Patrick H. (stpatrck)
Replace:
#Html.EditorFor(model => model.TestResults, "TestResults")
with:
#Html.EditorFor(model => model.TestResults)
and then rename your EditorTemplates/TestResults.cshtml editor template to EditorTemplates/TestResult.cshtml (notice the missing s) and inside replace the model declaration from:
#model IEnumerable<TestResult>
to:
#model TestResult
Now obviously this will lead to getting rid of any for or foreach loops you might have written in this editor template because now ASP.NET MVC will automatically invoke the template for each element of the collection.
So for example:
#foreach (var item in Model)
{
#Html.EditorFor(x => item.SomeProperty)
}
will simply become:
#Html.EditorFor(x => x.SomeProperty)
Now look at the generated markup and notice the difference in the names of your input fields. Before you had:
<input type="text" name="item.SomeProperty" value="foo" />
and now you have:
<input type="text" name="TestResults[0].SomeProperty" value="foo" />
Now when you submit the form to the POST action the default model binder will be able to successfully bind the collection because now the naming convention is respected. You can read more about this convention in the following blog post.
Also you have circular references in your object graph which cannot be successfully serialized and model bound. You should use view models in order to break this circular dependency.

How to add values to dropdown in MVC3?

I want to add a dropdownlist in my form, with 2 values userid and username in my dropdownlist, and also I want to get the value selected by the user when I click the button. I'm new to MVC and so far, I have not worked on dropdownlist, tried few samples but nothing seems to be working the way I want.
I'll jump lots of MVC3 concepts. If you're really new to ASP.NET MVC, you should take a look at some tutorials.
This code should help you:
VIEW
#using (Html.BeginForm("ACTION NAME", "CONTROLLER NAME"))
{
<select name="select">
<option value="username" selected>User name</option>
<option value="userid">User id</option>
</select>
<input type="submit" />
}
ACTION
[HttpPost]
public ActionResult ACTIONNAME(string select)
{
//...
}
Please, note:
ACTION NAME and CONTROLLER NAME at the BeginForm helper. You will have to modify this at your code
The select name ("select") and the name of the argument at the action ("select"). This is not a coincidence, it's a convention. MVC uses the name attr to bind data
The selected attribute at the option will make it the default option
Regards
See one of the ways you can do it is send the list in a model property as the binding and for the value you can bind it to another property like :
public class YourModel
{
public List<UserList> OptionList { get; set; }
public String YourValue{get;set;}
}
public class UserList
{
public String UserName{get;set;}
public String UserId{get;set;}
}
#Html.DropDownListFor(model => model.YourValue, Model.OptionList, "")
In the helper there are overided options which are used to specify the value and text.
And Remember :
This is StackOverflow.
Even the Not working example which you have tried are important for the ones who try to help you since they are spending their precious bandwidths for u.
You don't need create a new model class for each view, just put this on controller:
ViewBag.FieldName = new SelectList(new List<SelectListItem>() {
new SelectListItem { Value = "userid", Text = "User ID" },
new SelectListItem { Value = "username", Text = "User name" }
});
And this on view:
#Html.DropDownList("FieldName")
You need to create a collection of SelectListItem like:
IEnumerable<SelectListItem> selectList =
from c in areaListResponse.Item
select new SelectListItem
{
Text = c.AreaName,
Value = c.Id.ToString()
};
Pass this selectList to your view:
return View(selectList);
In your cshtml:
#model IEnumerable<SelectListItem>
#Html.DropDownListFor(m => m.RequestAreaName, Model)
If you need complecated object, you may need a wrapper class like:
public class RaiseRequestModelWrapper
{
public IEnumerable<SelectListItem> GetModel { get; set; }
public RaiseRequestModel PostModel { get; set; }
}

Categories

Resources