We dynamically populate our dropdownlist with several event dates from the database.
Currently, all dates less than today's date are disabled and can't be viewed by our users.
The next available date greater than today's date becomes the default dropdownlist value and all future dates are avaiable and visible in the dropdownlist.
For instance, if we have the following dates on our datebase:
2/12/2013
12/20/203
5/21/2014
8/8/2014
10/22/2014
since three of the dates ( 2/12/2013,12/20/203,5/21/2014 ) are less than today's date, these dates are disabled and not viewable.
The closest available date greater than today's date is 8/8/2014 and this becomes the default dropdownlist value.
Finally all future dates like 10/22/2014 are also available in the dropdownlist.
Here are the code snips that make this happen:
//the markup
<asp:DropDownList id="txtEventDate" runat="server">
</asp:DropDownList>
//Code that dynamically populates dropdownlist
Dim cmd As New SqlCommand("Select convert(datetime, dates, 103) dates, CONVERT(VARCHAR(12), dates, 107) as datelist from events", New SqlConnection(ConfigurationManager.ConnectionStrings("Events").ConnectionString))
cmd.Connection.Open()
Dim ddlValues As SqlDataReader
ddlValues = cmd.ExecuteReader()
txtEventDate.DataSource = ddlValues
txtEventDate.DataValueField = "dates"
txtEventDate.DataTextField = "datelist"
txtEventDate.DataBind()
cmd.Connection.Close()
cmd.Connection.Dispose()
//Code that displays only future dates with next available future date as default dropdownlist value
For Each items As ListItem In txtEventDate.Items
If (DateTime.Parse(items.Value).CompareTo(DateTime.Today)) < 0 Then
items.Enabled = False
End If
Next
Our users would like to change the process so they would be allowed to go back to an older date and make some changes if they needed to.
Any ideas how to address this problem?
Public Sub PopulateDates()
Dim cmd As New SqlCommand("Select convert(datetime, dates, 103) dates, CONVERT(VARCHAR(12), dates, 107) as datelist from events", New SqlConnection(ConfigurationManager.ConnectionStrings("events").ConnectionString))
cmd.Connection.Open()
Dim lstDates As New List(Of DateTime)()
Using rdr As SqlDataReader = cmd.ExecuteReader()
If rdr.Read() Then
lstDates.Add(DirectCast(rdr("dates"), DateTime))
End If
End Using
lstDates = lstDates.OrderBy(Function(x) x.[Date]).ToList()
Dim nearestDate = lstDates.OrderBy(Function(t) Math.Abs((t - DateTime.Now).Ticks)).First()
txtEventDate.DataSource = lstDates
txtEventDate.DataBind()
txtEventDate.SelectedIndex = txtEventDate.Items.IndexOf(txtEventDate.Items.FindByValue(nearestDate.ToString()))
cmd.Connection.Close()
cmd.Connection.Dispose()
End Sub
Per your comment it seems like you want to let the user change the older dates. So remove your For Each
that disables the older dates.
First you need to find the nearest date equal or closer to current date like below
Dim nearestDate = ddlValues.OrderBy(Function(t) Math.Abs((t.dates - DateTime.Now).Ticks)).First()
Then after you do the data binding keep the nearest date default selected using FindByValue
or FindByText
txtEventDate.SelectedIndex = txtEventDate.Items.IndexOf(txtEventDate.Items.FindByValue(nearestDate.ToString()))
Side Note: always try using using
statements for your db connection objects like SqlConnection
, SqlCommad
etc so the resources used by these objects are freed up after usage.
UPDATE 1: Based on what you reported in your comment, I made few changes as to the date format ( it was not part of your initial question) etc and here is the complete code for PopulateDates()
. Also make sure you don't run the foreach
you earlier had to set the nearest date because it might set wrong values. If you get wrong values then better put breakpoint and see which object returns unexpected data.
Public Sub PopulateDates()
Dim cmd As New SqlCommand("Select dates from events", New SqlConnection(ConfigurationManager.ConnectionStrings("events").ConnectionString))
cmd.Connection.Open()
Dim lstDates As New List(Of DateTime)()
Using rdr As SqlDataReader = cmd.ExecuteReader()
If rdr.Read() Then
lstDates.Add(DirectCast(rdr("dates"), DateTime))
End If
End Using
Dim stDates As List(Of [String]) = lstDates.OrderBy(Function(o) o.[Date]).[Select](Function(x) x.[Date].ToString("MMM dd, yyyy")).ToList()
Dim nearestDate = lstDates.OrderBy(Function(t) Math.Abs((t - DateTime.Now).Ticks)).First()
// Dim nearestDate = lstDates.First(Function(x) x >= DateTime.Now.[Date]) // this does the trick too
txtEventDate.DataSource = stDates
txtEventDate.DataBind()
txtEventDate.SelectedIndex = txtEventDate.Items.IndexOf(txtEventDate.Items.FindByValue(nearestDate.ToString("MMM dd, yyyy")))
cmd.Connection.Close()
cmd.Connection.Dispose()
End Sub
Here is the link to the DEMO (unfortunately it's in C#) I set up to show how it return me the correct data.
UPDATE 2: Here is your complete working version (hopefully it works). I tried this locally to load the data from database and retrieving through the DataReader
and everything works the way you wanted.
You reported in your comment saying only one item was returned when accessing from the DataReader, it's because your original code had If rdr.Read() Then
which will exit after the first record but rather we need to use while
to iterate the complete list.
Regarding Value
field and Text
of the dropdownlist holding different date format, I've created a Dictionary
collection to achieve this. Here is your complete code for PopulateDates()
.
Public Sub PopulateDates()
Dim cmd As New SqlCommand("Select dates from events order by dates", New SqlConnection(ConfigurationManager.ConnectionStrings("events").ConnectionString))
cmd.Connection.Open()
Dim list As New Dictionary(Of String, DateTime)()
Using rdr As SqlDataReader = cmd.ExecuteReader()
Dim dt As DateTime
While rdr.Read()
dt = DateTime.Parse(rdr("dates").ToString())
list.Add(dt.ToString("MM/dd/yyyy"), dt)
End While
End Using
txtEventDate.DataSource = list
txtEventDate.DataTextField = "Value"
txtEventDate.DataValueField = "key"
txtEventDate.DataTextFormatString = "{0:MMM dd, yyyy}"
txtEventDate.DataBind()
Dim nearestDate = list.First(Function(x) x.Value >= DateTime.Now.[Date]).Key
txtEventDate.SelectedIndex = txtEventDate.Items.IndexOf(txtEventDate.Items.FindByValue(nearestDate.ToString()))
cmd.Connection.Close()
cmd.Connection.Dispose()
End Sub
And the HTML markup looks like the format you wanted.
Totally untested, but would something like the following do what you want? Your list of items will need to be sorted, if it's not already, but this should find the first item that is for today or later and set it as the selected item in the drop-down.
Update - try SelectedValue
instead!
For Each items As ListItem In txtEventDate.Items
If (DateTime.Parse(items.Value).CompareTo(DateTime.Today)) >= 0 Then
txtEventDate.SelectedValue = items.Value
Exit For
End If
Next
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.