I'm learning MVC 5 and I can't find the reason why I can't reach the List of names in the View? I'm sure I have done something wrong, but I can't see why and would preciate some help to be able to continue.
In the Controller I have tested to use ViewBag and pass the List with return and then use #Model.
Model Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MVC_1.Models
{
public class ListNames
{
public static List<string> names;
// Constructor
public ListNames()
{
// Create list
names = new List<string>();
// Add some names to list
names.Add("Anna");
names.Add("Linda");
names.Add("Petra");
}
}
}
Controller:
public ActionResult ListNames(List<string> Names)
{
ViewBag.Name = Names[0];
return View(Names);
}
View:
#model MVC_1.Models.ListNames
#{
ViewBag.Title = "ListNames";
}
<h2>ListNames</h2>
<p>#ViewBag.Name</p>
<p>#Model.????</p>
You forgot to add get and set to the list inside the model;
public class ListNames
{
public List<string> names { get; set; }
//rest of the code
}
As #stephen-muecke mentioned you action returns List<string> and the view is expecting the ListNames model. A solution will be like below
public ActionResult ListNames()
{
var listNames = new MVC_1.Models.ListNames();
ViewBag.Name = listNames.names[0];
return View(listNames);
}
View:
#model MVC_1.Models.ListNames
#{
ViewBag.Title = "ListNames";
}
<h2>ListNames</h2>
<p>#ViewBag.Name</p>
#foreach(var name in Model.names)
{
<p>#name</p>
}
Related
I want to use the list of state controller in a district controller. Are there any better ideas.
I have tried one which is working
I put this code in the district controller by using constructor injection.
In this case, the entire code needs to be placed in the district controller.
Is there any way to reduce the code. A better way?
#region StateDropDown
public List<SelectListItem> StateDropDown()
{
List<SelectListItem> selectListItem = new List<SelectListItem>();
List<StateViewModel> stateList = Mapper.Map<List<State>, List<StateViewModel>>(_stateBusiness.GetStateForSelectList());
if (stateList != null)
foreach (StateViewModel state in stateList)
{
selectListItem.Add(new SelectListItem
{
Text = state.Description,
Value = state.Code.ToString(),
Selected = false
});
}
return selectListItem;
}
#endregion StateDropDown
This is what the term 'reusability' is invented for. Place the code in another file and make calls to it from any number of controllers you want, like code below.
//StateBusiness.cs
public class StateBusiness
{
public List<SelectListItem> GetStatesForDropdown()
{
//your logic here
return new List<SelectListItem>();
}
}
//StateController.cs
public class StateController : Controller
{
var state = new StateBusiness();
public ActionResult Index()
{
//call your code here
var states = state.GetStatesForDropdown();
//and do whatever you want
ViewBag.states = states;
return View();
}
}
//DistrictController.cs
public class DistrictController : Controller
{
var state = new StateBusiness();
public ActionResult Index()
{
//call it from here just the same
var states = state.GetStatesForDropdown();
ViewBag.states = states;
return View();
}
}
I don't know about better, but you could shorten this considerably using linq Select.
Mapper.Map<List<State>, List<StateViewModel>>(_stateBusiness.GetStateForSelectList())?
.Select(state => new SelectListItem
{
Text = state.Description,
Value = state.Code.ToString(),
Selected = false
}))?.ToList() ?? List<SelectListItem>();
If you using core one option might be to keep this off the controller and use a TagHelper this will let you inject the options into the tag with a simple attribute state-items reducing controller dependencies and keeping this state off the ViewBag while being more reusable.
Here is how it wold look in the view:
<select asp-for="State" state-items />
The TagHelper:
[HtmlTargetElement("select", Attributes = "state-items")]
public class StateItemsTagHelper : TagHelper {
private readonly StateBusiness _stateBusiness;
[HtmlAttributeName("asp-for")]
public ModelExpression For { get; set; }
public StateItemsTagHelper(StateBusiness stateBusiness) {
this._stateBusiness = stateBusiness;
}
public override void Process(TagHelperContext context, TagHelperOutput output) {
content.TagMode = TagMode.StartTagAndEndTag;
var value = For?.Model as string;
var items = _stateBusiness.GetStateForSelectList()?.Select(state => new SelectListItem {
Text = state.Description,
Value = state.Code.ToString(),
Selected = value == state.Code.ToString()
})) ?? Enumerable.Empty<SelectListItem>();
foreach(var item in items) {
output.Content.AppendHtml(item.ToHtmlContent());
}
}
}
For reusability item.ToHtmlContent is an extension method:
public static IHtmlContent ToHtmlContent(this SelectListItem item) {
var option = new TagBuilder("option");
option.Attributes.Add("value", item.Value);
if(item.Selected) {
option.Attributes.Add("selected", "selected");
}
option.InnerHtml.Append(item.Text);
return option;
}
I'm storing list of string in to a session. Then I don't know how to get those data to display in my view.
This is my code:
public List<Details> d = new List<Details>();
[HttpPost]
public void getDatas(string destination)
{
XElement rootele = XElement.Load(Server.MapPath("~/XmlFiles/CruiseData/cruiseprodutstwo.xml"));
var getneededData = rootele.Elements("CruiseProduct")
.Where(l => l.Element("Location").Value == destination)
.Select(s => s.Element("Name").Value);
foreach (var itm in getneededData)
{
d.Add(new Details
{
cruiseName = itm
});
}
Session["names"] = d;
Response.Redirect("Check",true);
}
This is my check action method
public ActionResult Check()
{
var chk = Session["names"];
return View();
}
You can store your data in ViewBag, then retrieve them in view:
public ActionResult Check()
{
ViewBag.SessionData = Session["names"] as List<DetailsList>;
Return View();
}
Then in your view, use simply as
#If (ViewBag["SessionData"]!= null){
// Do jobs with SessionDetails what you want
}
Hope this helps.
Controller
public ActionResult Check()
{
var chk = Session["names"];
List<Details> list = Session["names"] as List<Details>;
ViewBag.MyList = list ;
return View();
}
View
#ViewBag.MyList
// e.g.
#foreach (var item in ViewBag.MyList) { ... }
Firstly, it is better to use ViewBag, ViewData and/or TempData when playing with MVC.
The use is quite simple for all the three. Here are the steps :
You assign them some value/object : ViewBag.SomeField = SomeValue;
You use them on your view side : #ViewBag.SomeField.
Here are some link that will definitely get you through :
ViewBag ViewData and TempData
ViewBag ViewData and TempData Basics
Since you are redirecting to an action method here, I would suggest using TempData for your case and using that in the view.
Hope this helps.
I have a list of incidents which can have associated jobs. I Have a separate views for incidents and jobs. From the incident index page I have the following link to create a new job for that incident:
#Html.ActionLink("Create","Create", "Job", new { id = item.IncidentID }, null)
which takes the incident ID from that field and loads the Job view. I want to pass the ID as a default value for creating a new job, so the job will be assigned the incident ID.
I made this controller:
public ActionResult Create(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var newid = id;
ViewBag.ActionCode = new SelectList(db.ActionTypes, "ActionCode", "ActionType1");
ViewBag.IncidentID = new SelectList(db.Incidents, "IncidentID", "DefectFreeText");
return View();
}
How can I assign a default value to the form on the create job view ? I thought something like this:
#Html.EditorFor(model => model.IncidentID, id/newid)
Can anyone help me figure out what I am doing wrong?
I am assuming you want to set a default item for your Incidents dropdown list when user pass that to your create action method as a querystring. I would avoid using ViewBag approach to transfer your dropdown list data to the view and switch to a strongly typed viewmodel approach.
First create a viewmodel for our create view.
public class CreateJobVM
{
public int IncidentID { set;get;}
public int ActionTypeID { set;get;}
public List<SelectListItem> ActionTypes { set;get;}
public List<SelectListItem> Incidents{ set;get;}
public CreateJobVM()
{
ActionTypes =new List<SelectListItem>();
Incidents=new List<SelectListItem>();
}
}
And in your GET view,
public ActionResult Create(int? id)
{
var vm=new CreateJobVM();
vm.ActionTypes=GetActionTypes();
vm.Incidents=GetIncidents();
if(id.HasValue)
{
//set the selected item here
vm.IncidentID =id.Value;
}
return View(vm);
}
Assuming GetActionTypes and GetIncidents method returns a list of SelectListItems, From a DB table/ XML /whatever place you have data
public List<SelectListItem> GetActionTypes()
{
List<SelectListItem> actionTypesList = new List<SelectListItem>();
actionTypesList = db.ActionTypes
.Select(s => new SelectListItem { Value = s.ID.ToString(),
Text = s.Name }).ToList();
return actionTypesList;
}
and in your view which is strongly typed to CreateJobVM
#model CreateJobVM
#using(Html.Beginform())
{
#Html.DropDownListFor(s=>s.ActionTypeID ,Model.ActionTypes)
#Html.DropDownListFor(s=>s.IncidentID,Model.Incidents)
<input type="submit" />
}
When you post the form you can check the property values to get the values user selected in the form
[HttpPost]
public ActionResult Create(CreateJobVM model)
{
//check for model.IncidentID, ActionTypeID
// to do : Save and redirect
}
Just pass it with the help of ViewBag/ViewData
ViewBag.DefaultId=id;
return View();
If you have a model based view
YourViewModel.DefaultId=id;
return View(YourViewModel);
In View,
#ViewBag.DefaultId
or with ViewModel
YourViewModel.DefaultId
I have a class that I populate when a user navigates to a certain page, /Home/About, within my MVC4 application. I populate a class with data and I would like to have in my view that data in a drop down list.
My class looks like this: (UPDATED)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
public class WorkSection : List<WorkSection>
{
[Required]
[Display(Name = "WorkSection")]
public int ID { get; set; }
public string Code { get; set; }
public SelectList WorkSections { get; set; }
public WorkSection()
{
// Default Constructor
}
public WorkSection(int id, string code)
{
this.ID = ws_id;
this.Code = code;
}
}
How do I take this populated List of type WorkSection and make that the data source for my drop down list? I would like to display the Code and Source field in a concatenated fashion, like "Code:Source" within the drop down list with the ID as the selected item's value.
UPDATE for ActionResult, where code will be called from on /Home/About
public ActionResult About()
{
WorkSection model = new WorkSection();
OracleConnection con = new OracleConnection();
con.ConnectionString = "omitted";
try
{
con.Open();
}
catch (Exception ex)
{
throw ex;
}
try
{
OracleDataReader reader = null;
// Work Section
OracleCommand cmd = new OracleCommand("SELECT ID, CODE FROM MyTable ORDER BY CODE", con);
reader = cmd.ExecuteReader();
while (reader.Read())
{
model.Add(new WorkSection()
{
ID = Int16.Parse(reader["ID"].ToString()),
Code = reader["CODE"].ToString()
});
}
model.WorkSections = BuildSelectList(model.WorkSections, m => m.ID, m => m.Code);
con.Close();
con.Dispose();
}
catch (Exception ex)
{
throw ex;
}
return View(model);
}
First up, we need a view model to encapsulate the data for the view:
public class TestViewModel
{
[Required]
[Display(Name = "Work section")]
// This represents the selected ID on the dropdown
public int WorkSectionId { get; set; }
// The dropdown itself
public SelectList WorkSections { get; set; }
// other properties
}
Next up, we need a way to populate the SelectList. I wrote a custom method a while ago to do just that:
private SelectList BuildSelectList<TSource>(IEnumerable<TSource> source,
Expression<Func<TSource, int>> valueKey, Expression<Func<TSource, string>> textKey,
object selectedValue = null)
{
var selectedValueKey = ((MemberExpression)(MemberExpression)valueKey.Body).Member.Name;
var selectedTextKey = ((MemberExpression)(MemberExpression)textKey.Body).Member.Name;
return new SelectList(source, selectedValueKey, selectedTextKey, selectedValue);
}
This uses expression trees for type-safety, ensuring problems are caught at compile-time, rather than run-time. SelectList also uses one property for the text key and one for the value key. In your situation, this obviously creates a problem, because you want to combine Code and Source to form the text key. In order to get around that, you'll need to create a new property in WorkSection that combines both:
public string CodeSource
{
get { return this.Code + ":" + this.Source; }
}
That way, you can use that to create the SelectList as normal. To do that, your action might like something like:
public ActionResult Index()
{
var workSections = // ... fetch from database
TestViewModel model = new TestViewModel();
model.WorkSections = BuildSelectList(workSections, m => m.ID, m => m.CodeSource);
return View(model);
}
You can use that in the view like so:
#Html.DropDownListFor(m => m.WorkSectionId, Model.WorkSections, "--Please Select--")
#Html.ValidationMessageFor(m => m.WorkSectionId)
One final note on BuildSelectList. The method has saved me a lot of time when dealing with dropdowns in general. So much so that I now define it as a public method on a base controller, which I then derive all of my controllers from. However, if you want to do that, you'll want to mark it with the [NonAction] attribute so it doesn't interfere with routing.
Update per comments
public class BaseController : Controller
{
[NonAction]
public SelectList BuildSelectList<TSource>(IEnumerable<TSource> source,
Expression<Func<TSource, int>> valueKey, Expression<Func<TSource, string>> textKey,
object selectedValue = null)
{
var selectedValueKey = ((MemberExpression)(MemberExpression)valueKey.Body).Member.Name;
var selectedTextKey = ((MemberExpression)(MemberExpression)textKey.Body).Member.Name;
return new SelectList(source, selectedValueKey, selectedTextKey, selectedValue);
}
}
Then you'd derive your controllers from BaseController instead:
public HomeController : BaseController
{
//
}
#Hmtl.DropdownListFor(m=>m.YourNameForSelectedWorkSectionId, Model.WorkSections.Select(x => new SelectListItem { Text = x.Code +":"+x.Source, Value = x.ID}))
hi i am doing my project in mvc4 using c#
i have list in my controller
public ActionResult Gallery()
{
string folderpath = Server.MapPath("~/Content/Gallery/GalleryImages");
List<String> currentimage = new Gallery().GetGalleryName(folderpath);
return View(currentimage);
}
i want to list the items in currentimage in my view , how it possible, i am trying the following
#model List<String>
#foreach(var item in Model)
{
<p>
#item // what will be write here..
</p>
}