A better way than using ViewBag - c#

I obtain a list of data through docs which has a list of every single department and function the currently logged in user has access to. I need to populate a distinct list of Departments for a DropDownList and a distinct list of Functions for a DropDownList on the View page. I am currently not even using docs to do this but a different LINQ query to acheive this. Is there a way I can use the current model I am passing?
var docs = (Long LINQ query that joins in four different tables and returns a model)
ViewBag.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
ViewBag.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
Code on View: (Strongly Typed Model)
#model IEnumerable<DB.Models.MasterList>
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")

Define a model that will be used in your view.
public class MyViewModel
{
public string SelectedDepartment { get; set; }
public string SelectedFunction { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
public IEnumerable<SelectListItem> Functions { get; set; }
// Your old model
public IEnumerable<MasterList> Master { get; set;}
}
In your controller, populate these collections and return your model to view.
[HttpGet]
public ActionResult ActionMethodName()
{
var model = new MyViewModel();
model.Departments = db.Departments.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
model.Functions = db.Functions.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
return View(model);
}
Inside your view, use strongly typed html helpers.
#model MyViewModel
#Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments)
#Html.DropDownListFor(m => m.SelectedFunction, Model.Functions)
When you post back your form to server, SelectedDepartment and SelectedFunction should have the values selected in your view.

You could create a ViewModel and put all this data in this ViewModel:
ViewModel
public class MyViewModel{
public object DepartmentList{get; set;}
public object FunctionList{get; set;}
public IEnumerable<MasterList> Master {get; set;}
}
Controller
var docs = (Long LINQ query that joins in four different tables and returns a model)
MyViewModel vm = new MyViewModel();
vm.Master = docs; // I guess docs is a list of Masterlist
vm.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
vm.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
return View(vm);
View
#model MyViewModel
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")

You can always create a ViewModel class for your view and put all the necessary view information in it.
You can use a framework like AutoMapper (https://github.com/AutoMapper/AutoMapper) to help you with the mapping between your database model and your view model (I belive it's best that the view won't know the database model at all), and beside the model information you can also add those lists (That's what I do, I have a property for the entity, and properties for those kinds of lists).
If you need this information in many of your views you can always create a BaseViewModel and polpulate that information in a BaseController.

Related

Single Controller an View for multiple Models

I am new to MVC and EF, but i have a group of models that represent lookup tables that all have the same structure
public int ID {get; set;}
public string Value {get; set;}
public bool IsActive {get; set;}
Rather than writing one Controller and View for each is there a way to create one, that is defined by a previous selected value.
So if 2 of my lookups are Gender and Status and a dropdown with these values
can I then take the name of the selected option and then dynamically bind to the model
so rather than having Status status = new Status its Object object = new Object where object has been defined by the selection of Status in the previous dropdown
It is definitely possible. There are several ways you could achieve this. You could have an EditorTemplate with everything you need to display your dropdown. In ~/Views/Shared/EditorTemplates/DropDown.cshtml
#model string
#{
Layout = null;
List<SelectListItem> ListItems = (List<SelectListItem>)ViewBag.ListItems;
}
// not sure what the syntax for a dropdown is, I don't use them
#Html.SelectFor(m => Model, ListItems)
Then in your view
#Html.EditorFor(m => m.Status, "DropDown", new { ListItems = MyModel.StatusSelectListItems })
#Html.EditorFor(m => m.Gender, "DropDown", new { ListItems = MyModel.GenderSelectListItems })
Where in your model you would have the selection options:
public class MyModel
{
// other stuff
public static List<SelectListItem> GenderSelectListItems = new List<SelectListItem>
{
new SelectListItem{ Value = "Male", Text = "Male" },
new SelectListItem{ Value = "Female", Text = "Female" }
};
// etc
}

multiple select list c# mvc

I am trying to create a multiple select from a single select drop down menu.
my model originally had:
public int country_id { get; set; }
and my view had:
#Html.DropDownList("country_id", String.Empty)
to change it to multiple select i changed my model to:
public List<Country> country_id { get; set; }
and my view to:
#Html.ListBoxFor(model => model.country_id, ViewBag.ActionsList as MultiSelectList, new { #class = "multiselect", #style = "width: 450px;height:200px" })
the problem i am having is updating my databse using migration since the i am changing int to list, however, it keeps saying
"Cannot drop the index 'dbo.People.IX_country_id', because it does
not exist or you do not have permission."
I do have permission so I am not sure if I am missing something?
My list of countries is coming straight from the country database.
thanks for your inputs.
You need to populate a selectlist in the controller & pass it to the view, something like this:
var countries = from d in db.Countries
select new
{
Id = d.Id,
Name = d.Name
};
// I'd pass this in a model, but use ViewBag if that's what you're familiar with
ViewBag.ActionsList = new SelectList(countries , "Id", "Name");
And in the View:
#Html.DropDownListFor(model => model.country_id, ViewBag.ActionsList)
UPDATE:
You should use a ViewModel for this:
public class CountryList
{
// this may have to be a List<SelectListItems> to work with MultiSelectList - check.
public SelectList Countries{ get; set; }
public List<int> SelectedCountryIds { get; set; }
}
In the controller:
var model = new CountryList
{
SelectList = //assign the selectlist created earlier
}
return View(model);
In the View:
#Html.ListBoxFor(m => m.SelectedCountryIds, new MultiSelectList(#Model.Countries, "Id", "Name", #Model.SelectedCountryIds))

How to Specify SelectedValue for SelectList?

In my MVC Project, I have a Course model looks like this:
public class Course
{
[Key]
public int CourseId { get; set; }
[Required, MaxLength(50)]
public string Name { get; set; }
// bunch of other properties
}
I'm creating a SelectList for some Courses in my Action
var user = context.Users.Include("Courses")
.FirstOrDefault(x => x.Email == User.Identity.Name);
var courses = user.Courses.OrderBy(x => x.Name);
ViewBag.Courses = new SelectList(courses, "CourseId", "Name");`
I have a nullable courseId parameter in my Action like this:
public ActionResult Index(int? courseId)
If it's not null, I want to change the default selected value to that course.In order to do this I tried:
if (courseId != null)
{
var selectedCourse = courses
.FirstOrDefault(x => x.CourseId == courseId.Value);
if (selectedCourse != null)
{
ViewBag.Courses = new SelectList(courses, "CourseId", "Name", selectedCourse.CourseId);
}
}
But it doesn't work and selectedCourse is not null.Instead of specified Course I see the first course in my list selected every time.What am I missing ?
Edit: I'm creating DropdownList in my View like this:
#Html.Bootstrap().DropDownList("Courses", (SelectList)ViewBag.Courses)
You should send the selected value via your model, but, if you want to send it via viewbag, please try like so:
#Html.DropDownListFor(model => Model.CourseId,
new SelectList(ViewBag.Courses, "Value", "Text", #ViewBag.CourseId))
Please see my original answer to a similar question here for more info https://stackoverflow.com/a/16799915/1477388
If any answers solve your problem. Try it
put your selected value into a ViewBag.Seleted
$("#DropDownId option").each(function(){
if($(this).val() == "ViewBag.Selected"){
$(this).attr("selected","selected");
}
});

How to set two values in View()

How can set several objects in view?
public ActionResult Index()
{
var shops = this.context.shops.Select(q => new { q.id, q.name }).ToList();
var bikes = this.context.bikes.Select(q => new { q.id, q.name }).ToList();
return View(shops, bikes); // How to set two values in View()?
}
And parse in View()
#foreach (var r in Model.bikes)
{
<b>#r.name</b>
}
One way is to create a strong typed view model that contains both shops and bikes. Other option could be creating a Tuple and passing as a model to view. I would go first option.
Tuple
var tuple = new Tuple<shop, bike>(new shop(),new bike());
In you view
#Model Tuple<shop,bike>
You need create ViewModel
public class shopsAndbikes
{
public List<shop> shops {get;set;}
public List<bike> bikes {get;set;}
}
public ActionResult Index()
{
shopsAndbikes vm = new shopsAndbikes ()
{
var shops = this.context.shops.Select(q => new { q.id, q.name }).ToList();
var bikes = this.context.bikes.Select(q => new { q.id, q.name }).ToList();
}
return View(vm);
}
View:
#model shopsAndbikes
#foreach (var r in Model.bikes)
{
<b>#r.name</b>
}
#foreach (var r in Model.shops)
{
<b>#r.name</b>
}
Your Model-class should contain properties for both shops and bikes. That is if you use a strongly typed view, it looks that way. Otherwise you could add things to the ViewBag for use in the view.

Need help to complete the below code for a simple drop-down using <SelectListItem> in MVC

I would like to create a simple drop-down box that displays a list of countries. The data for it comes from the database and is accessed using the entity framework data context. The user should select a country before posting the data back.(simple validation check).
I've created the view model and have also written some code, but I'm not sure about my design and I also need help to complete the code. I've done some search, but I couldn't find a simple way of doing this. I'm still getting the data from context because I am still not sure about how to use repositories. At the moment, I just want the basic drop-down to work without getting too advanced. Please help. Thanks
Updated
View Model - Country.cs
public class Country
{ [Required]
public int Id { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
}
Controller
Public ActionResult CountriesDropDown()
{
Models.Country countryModel = new Models.Country();
using (ctx)
{
var model = (from q in ctx.Countries
select new SelectListItem
{
Text = q.CountryId,
Value = q.CountryName
}).ToList();
countryModel.Countries = model;
}
return View("Test",countryModel);
}
Countries View
#using (Html.BeginForm("DoSomething", "Test", FormMethod.Post))
{
#Html.DropDownListFor(model => model.Id, Model.Countries, "Please Select")
#Html.ValidationMessageFor(model => model.Id) //The validation part still Not Working. I want the user to select a country before submitting the form. Please help
<input type = submit value="submit" />
}
[HttpPost]
public ActionResult DoSomething(Models.Country Selectedcountry)
//country.Id holds the value of selected drop-down and it works fine
{
if (ModelState.IsValid)
//I need to do server-side validation and return back to client if Selectedcountry.Id is null (just in case, the client-side validation doesn't work)
{
return View();
}
else
{
return View("Test");
}
}
Thanks
Do this in your controller:
var model = new Country {
// assuming that the country with "id" exists
CountryId = ctx.Countries.Get(id).Id
};
model.Countries =
from q in ctx.Countries
select new SelectListItem {
Text = q.Id,
Value = q.Name
};
return view("countries", model);
Do this in your model
#model Models.Country
#Html.DropDownListFor(model => model.CountryId, model.Countries)
try this:
[Required(ErrorMessage = "Please select a Country")]
public string CountryCode{ get; set; }
public IEnumerable<SelectListItem> CountryList
{
get
{
return Country
.GetAllCountry()
.Select(Country=> new SelectListItem
{
Text = Country.Value,
Value = Country.Value
})
.ToList();
}
}
and then you could add a corresponding validation error message:
#Html.DropDownListFor(model => model.CountryCode, Model.CountryList, "select")
#Html.ValidationMessageFor(model => model.CountryCode)

Categories