简体   繁体   中英

How do I make the closest future date to today's date the default dropdownlist value?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM