I have a view which has roughly 10 dropdowns, when I load this page against an ID which has no data saved against it the dropdowns have the selected value of "Please Select" which is create as im creating a new record.
When I navigate back to this view with an ID that has data saved against it, the selected values of each drop down is set by the data I pass in to the view which again is correct.
But if I then reload the page with an ID that has no data saved against it, the selected values of the drop downs are set from the previous record! I have debugged this over and over and for the ID that has no data linked it I can see its passing in NULL for the selected values for each drop downs. I'm assuming this is to do with the ModelState? So I tried the following at the beginning of my controller
ModelState.Clear();
Before the load method is called, but the issue still exists has anyone come across this? I've googled for a solution but the only things that come up are "MVC Dropdown doesn't remember the selected value" which is the opposite to the issue I have.
Update *
I think I have found the issue, I'm currently using how to cache objects in MVC so when I load the dropdowns from the db for the page I then store them in the cache as follows:
if (CacheExtension.IsIncache("ListType"))
{
model.ListType = CacheExtension.GetFromCache<List<SelectListItem>>("ListType");
model.ListTime = CacheExtension.GetFromCache<List<SelectListItem>>("ListDuration");
model.ListPostageOption = CacheExtension.GetFromCache<List<SelectListItem>>("ListPostage");
model.ListPricingType = CacheExtension.GetFromCache<List<SelectListItem>>("ListPrice");
}
else
{
const string queryMultiple = #"
SELECT StatusId, StatusDescription from [Status].table1
SELECT StatusId, StatusDescription from [Status].table2
SELECT StatusId, StatusDescription from [Status].table3
SELECT StatusId, StatusDescription from [Status].table4";
using (var sqlCon = new SqlConnection(Con.ReturnDatabaseConnection()).QueryMultiple(queryMultiple))
{
var duration = sqlCon.Read().ToList();
var type = sqlCon.Read().ToList();
var options = sqlCon.Read().ToList();
var pricing = sqlCon.Read().ToList();
model.ListType = new List<SelectListItem>();
model.ListTime = new List<SelectListItem>();
model.ListPostageOption= new List<SelectListItem>();
model.ListPricingType = new List<SelectListItem>();
model.ListType .AddRange(
type.Select(
item => new SelectListItem { Text = item.StatusDescription, Value = item.StatusId.ToString() }));
model.ListTime.AddRange(
duration.Select(
item => new SelectListItem { Text = item.StatusDescription, Value = item.StatusId.ToString() }));
model.ListPostageOption.AddRange(
options.Select(
item => new SelectListItem { Text = item.StatusDescription, Value = item.StatusId.ToString() }));
model.ListPricingType.AddRange(
pricing.Select(
item => new SelectListItem { Text = item.StatusDescription, Value = item.StatusId.ToString() }));
// Cache everything
CacheExtension.SaveTocache("ListType", model.ListAdvertType, new DateTime(1));
CacheExtension.SaveTocache("ListDuration", model.ListDuration, new DateTime(1));
CacheExtension.SaveTocache("ListPostage", model.ListPostageOption, new DateTime(1));
CacheExtension.SaveTocache("ListPrice", model.ListPricingType, new DateTime(1));
}
}
and I re-load the page instead of calling the database I check the cache, if it exists I pull from there (this is where the problem is) I have just commented out the pulling from the cache and it works the dropdowns no longer remember the previous values but why?
I know this is an old question, but as there was no concrete answer here for me when I stumbled onto this question during my own similar issue, I thought I would go ahead and put an answer in that worked for me and explains why its happening.
The best answer above is from #StephenMuecke, as his suggestion about
storing the collections instead of a SelectList is spot on.
The reason is because with any form of in-memory caching, the cached objects returned are pointers to the object in cache, so any change made to the returned cache object is actually written to the cache. In my case I was storing a List<SelectListItem>. Each SelectListItem has a selected attribute, and on my cshml pages when I used that List<SelectListItem> in a DropDownListFor(...) razor statement, it would assign whatever item was selected back into the cache.
The problem would arise on the next page load for a different record, if that dropdownvalue was null, the cached list I retrieved retained the last saved selected item, and because the new item was null, it was not overwritten, thus it would show the previously selected value when it should have been null and nothing should have been selected.
To fix:
Cache List<YourObjectName>, and on retrieval convert it to a
List<SelectListItem>.
Other options include cloning or deserializing/serializing the
List<SelectListItems> from cache.
Final option is don't use in-memory cache, use an out of process or
distributed cache mechanism, as this will effectively serialize and
deserialize the object.
Good day sirs.
Related
Have some problems trying to solve this. Have two DropDownListFor where the first is populated with data and the second should be populated using the selected value from the first.
Lets say the first DropDownlist contains these data:
RoutesList;
Value = "CoOs", Text = "Copenhagen - Oslo",
Value = "StOs", Text = "Stockholm - Oslo",
Value = "OsCo", Text = "Oslo - Copenhagen"
In my razor view I'm trying to create a new list based on the selected value.
How do I get the selected value, lets say "StOs" and format it so it only contains the first two letters "St"? Trying to do this with C# and not Jquery.
My code
// Loads RoutesList to departureRouteSelectList
var departureRouteSelectList = Model.RoutesList;
// Finds selected value
var selectedItem = departureRouteSelectList.Select(x => x.Value);
// Create new selectList for returnRoute
List<SelectListItem> returnRouteSelectList = null;
I'm not sure if the "Select" command does what I want and getting the "StOs"?
Understanding what you want make me think this post will resolve your problem:
Can't get my DropDownListFor to select a selected SelectListItem item in a Dropdown menu
I'm looking into creating an Edit page for a Company object that has multiple categories (that are predefined in a list). I have the list being sent through the ViewBag, and have the categories that the user selected in the Create page in an Array thanks to a ViewModel.
I can't figure out a way to have the ListBox prepopulate with the multiple values in my array. I was playing around with jQuery and was able to get one of the values to be selected, but when I try more than one nothing shows up. Any ideas?
#Html.ListBox("Category", new SelectList(ViewBag.Category, "Text", "Value"))
The SelectListItem object has a Selected property to indicate this. So I guess it would come down to how you build the SelectList. Currently you do this:
new SelectList(ViewBag.Category, "Text", "Value")
Which works, but gives you no control over the individual SelectListItems. Instead of building a SelectList, you can build an IEnumerable<SelectListItem> using the same method overload. Initially that might look like this:
ViewBag.Category.Select(c => new SelectListItem
{
Text = c.Text,
Value = c.Value
});
At this point you have more control over the individual items. Now it's just a matter of determining which ones should be selected. How do you determine that? Is it a property on the Category object? Something like this?:
ViewBag.Category.Select(c => new SelectListItem
{
Text = c.Text,
Value = c.Value,
Selected = c.Selected
});
Or perhaps some other condition?:
ViewBag.Category.Select(c => new SelectListItem
{
Text = c.Text,
Value = c.Value,
Selected = c.SomeValue == SomeCondition
});
How you determine that is up to you, and ideally something you can logically add to the backing model being used here.
I am creating an MVC project with a table using the JQGrid plugin. I would like to use a DropDownList to allow the user to specify a value, that will be used in an SQL query to retrieve specific data from the table. I.e. user can select a country from the list, and the table will display items only from that country.
My problem is, that I cannot figure out how to retrieve the selected item from the DropDownList, within my data bind function for my table, within my controller class.
DropDownList in the View
<%= Html.DropDownList("Countries")%>
Setting up the DropdownList in my controller
//dt is a DataTable which holds the values for my list
List<SelectListItem> countries = new List<SelectListItem>();
for (int i = 0; i < dt.Rows.Count; i++)
countries.Add(new SelectListItem { Text = dt.Rows[i][0].ToString(), Value = "" + i });
JsonResult DataBind() method where I would like to access the selected value
public JsonResult Charges_DataRequested()
{
string country = "Dropdownbox Selected Text";
}
The problem seems to be that within a JsonResult function I don't have access to the ViewData or my ViewModel, which always seem to be null when I try and access them. I am very new to MVC and web development, any advice would be very welcome.
Thanks for the answer, it put me on the right track. I realized that the grid also has a postdata parameter. I was able to create a javascript postback function for my dropdownlist, and call the jqGrid 'setGridParam' function to add my dropdownlist text to the grid postdata. I could also trigger a grid reload, and grab the string in my controller Jsonresult function.
The Javascript
$('#Countries').change(function() {
var value = $("#Countries option:selected").text();
$("#ChargesGrid").setGridParam ({
postData:{
selectedCountry:$("#Countries option:selected").text()}
});
$("#ChargesGrid").trigger("reloadGrid");
alert(value);
});
The controller
public JsonResult Charges_DataRequested(string selectedCountry)
{
string country = selectedCountry;
}
jqGrid has got a userdata property where you could store this data so it would be available on post. It may mean you'd have to update this dropdown changes.
jQuery("#GridId").getGridParam('userData').SelectedText
I've only used this the other to set data on loading but think it could work the other way around for you. I would have set the SelectedText above in a controller action when creating the grid json as
userdata = new { SelectedText = "SomeValue" }
The only trouble would be if it were a private set equivalent within the jqGrid code.
Ok, this has been a head scratcher for me. I have a ListBox I am binding to a linq query like so:
private IQueryable<Feed> _feeds;
public IQueryable<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = feedsQuery;
}
return _feeds;
}
}
public Options()
{
InitializeComponent();
this.DataContext = Feeds;
}
(For the record I've also tried List, instead of IQueryable)
Everything shows up great and I have a databound form that allows you to edit a record and all of those changes work just fine, the modified data shows up in the list.
The problem comes with I add an item. Nothing shows up in the list. The data goes into the database fine, but the only way to see the data is closing and restarting my app. I'm using the code below as an example:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
_db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
(with or without the _db.Refresh nothing happens)
What's going on?
You are doing everything right, you jus need to use ObservableCollection. This will notify the ListBox about any changes in the list and refresh it automatically.
From MSDN
In many cases the data that you work
with is a collection of objects. For
example, a common scenario in data
binding is to use an ItemsControl
such as a ListBox, ListView, or
TreeView to display a collection of
records.
P.S. you don't need a db refresh
Unless notified otherwise, the ListBox only iterates once over its ItemsSource. Your query is only being run once.
The query object doesn't know when the database changes (and Refresh doesn't help; see below)--it's up to you to know (or anticipate) that and to rerun relevant queries at the appropriate times.
Stan R mentions ObservableCollection. That's fine, but simply storing the result of your query in an ObservableCollection won't solve the problem unless you do some work to update the collection yourself when the database changes. This means rerunning the query and manually adding new items and removing deleted items from the collection. (You could alternatively just rerun the query and set the entire result back in to the ListBox, but that means a whole new set of items will be created--not very performant, and maybe not what you want for other reasons.)
As an aside, your call to DataContext.Refresh is probably not doing what you think it is. From the docs:
This method is useful after an optimistic concurrency error to bring items into a state for another attempt. It updates the state of the primitive fields and properties on the objects.
Okay. I'm not positive this is 100% the correct way to use the ObservableCollection, but this seems to work:
private ObservableCollection<Feed> _feeds;
public ObservableCollection<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = new ObservableCollection<Feed>();
foreach (var item in feedsQuery)
{
_feeds.Add(item);
}
}
return _feeds;
}
}
And add my item:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
// manually update the list
Feeds.Add(feed);
It took me a little while to figure out I had to update the list manually (thanks Ben), but it all seems to work. Sorting would be nice, but I'll worry about that another time.
I have the following code which is meant to populate a dropdown with a bunch of integer values and make the currently selected value (in this case, 13) be the selected item.
I've used the same technique but for string values and it works great, remembering each time when I get to the view what the current value is.
In controller:
var x = new[] { 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
ViewData["Field"] = new SelectList(x, 13);
In view:
<%=Html.DropDownList("Field", (IEnumerable<SelectListItem>)ViewData["Field"])%>
When I debug and watch the ViewData["Field"] object, it does have a selectedValue of 13 and so it must be reaching the View but getting ignored there as all I see on the page is a dropdown with the values 1 to 15, but with 1 showing (none selected so shows the first one)
Is this a bug or am I doing something really stupid?
Thanks
Graeme
I seem to recall that it doesn't actually use the Selected property of the SelectList element. I usually have one ViewData item be the select list and another be the selected value.
Controller:
var x = new[] { 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
ViewData["Fields"] = new SelectList(x);
ViewData["Field"] = 13;
View
<%= Html.DropDownList("Field", (IEnumerable<SelectListItem>)ViewData["Fields"] ) %>
This was happening to me! I was pulling my hair out for hours, but I eventually figured it out. In my case I was creating a drop-down list like this:
<%= Html.DropDownList("bookId", Model.ProductMenu, new { onchange = "goToBook();" })%>
And it was not printing the selected option. But the dropdown right next to it was working fine:
<%= Html.DropDownList("segmentIndex", Model.SegmentMenu, new { onchange = "goToSegment();" })%>
They were being generated the exact same way in the controller, and the debugger would always show the properly selected value as the view was returned. So what the heck?
The difference was in the view itself. "bookId" in my app happens to be a route/querystring value and segmentIndex is not. Simply changing the name "bookId" in the view to "bookIdBLAH" fixed it!