SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 54
  1. #1
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Populated select boxes for date

    I am using the following function to generate three select boxes to select a date dd/mm/yyyy., with the current date selected:
    Code:
    <script type="text/javascript">
      var monthtext=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'];
      function populatedropdown(dayfield, monthfield, yearfield){
    		
        var today=new Date()
        var thisyear = today.getFullYear()
        var dayfield = document.getElementById(dayfield)
        var monthfield=document.getElementById(monthfield)
        var yearfield=document.getElementById(yearfield)
    		
        for (var i=1; i<31; i++)
        dayfield.options[i]=new Option(i, i+1)
        dayfield.options[today.getDate()]=new Option(today.getDate(), today.getDate(), true, true) //select today's day
    
        for (var m=0; m<12; m++)
        monthfield.options[m]=new Option(monthtext[m], monthtext[m])
        monthfield.options[today.getMonth()]=new Option(monthtext[today.getMonth()], monthtext[today.getMonth()], true, true) //select today's month
    
        for (var y=0; y<20; y++){
          yearfield.options[y]=new Option(thisyear, thisyear)
          thisyear+=1
        }
        yearfield.options[0]=new Option(today.getFullYear(), today.getFullYear(), true, true) //select today's year
    }
    </script>
    This is working actually fine. The only thing i'm fighting with is that with using this method every month has 31 days. Is there a existing plugin that can handle this or should I adjust this function? And if so where is the best place to look or find a tutorial about this subject!

    Thank you in advance
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  2. #2
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Hey donboe,

    This is nothing that we can't sort out
    Do you have some HTML to go with the JS?
    A link to a page would be even better.

  3. #3
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Pullo. The link to the test page is: here

    Like I said it is working fine, only when the month should display 30 days(April,June etc) or 28/29 days (Feb) it's obviously not working!
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  4. #4
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Hi donboe,

    Here is an idea of how one could go about things:

    Code:
    <!doctype html>
      <html>
      <head>
        <meta charset="utf-8">
        <title>Untitled Document</title>
      </head>
    
      <body>
        <form action="" name="someform">
          <select id="daydropdown"></select> 
          <select id="monthdropdown"></select> 
          <select id="yeardropdown"></select> 
        </form>
    
        <script type="text/javascript">
          var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'];
    
          function daysInMonth(month, year) {
            return new Date(year, month, 0).getDate();
          }
    
          function populateDates(){
            var today = new Date(),
                day = today.getUTCDate(),
                month = today.getUTCMonth(),
                year = today.getUTCFullYear(),
                daysInCurrMonth = daysInMonth(month, year);
    
            // Year
            for(var i = 0; i < 21; i++){
              var opt = document.createElement('option');
              opt.value = i + year;
              opt.text = i + year;
              yeardropdown.appendChild(opt);
            }
    
            // Month
            for(var i = 0; i < 12; i++){
              var opt = document.createElement('option');
              opt.value = months[i];
              opt.text = months[i];
              monthdropdown.appendChild(opt);
            }
    
            // Day
            for(var i = 0; i < daysInCurrMonth; i++){
              var opt = document.createElement('option');
              opt.value = i + 1;
              opt.text = i + 1;
              daydropdown.appendChild(opt);
            }
          }
    
          var daydropdown = document.getElementById("daydropdown"),
              monthdropdown = document.getElementById("monthdropdown"),
              yeardropdown = document.getElementById("yeardropdown");
    
          // Change handler for months
          monthdropdown.onchange = function(){
            var newMonth = months.indexOf(monthdropdown.value) + 1,
                newYear = yeardropdown.value;
            
            daysInCurrMonth = daysInMonth(newMonth, newYear);
    
            daydropdown.innerHTML = "";
            for(var i = 0; i < daysInCurrMonth; i++){
              var opt = document.createElement('option');
              opt.value = i + 1;
              opt.text = i + 1;
              daydropdown.appendChild(opt);
            }        
          }
    
          populateDates()
        </script>
      </body>
    </html>
    Is this going in the right direction?

    Note: the code is full of duplication and needs tidying up. Let me know if you would like to use this and then I will make everything more generic, as well as build in some code to handle leap years.

  5. #5
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Pullo. This is in one word brilliant The only small thing I am missing now is that the current day (5th) is not selected when I land on the page. What should I adjust to get the current day?

    Otherwise brilliant!
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  6. #6
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    No probs

    Quote Originally Posted by donboe View Post
    What should I adjust to get the current day?
    Well you could do it like this:

    Code:
    // Day
    for(var i = 0; i < daysInCurrMonth; i++){
      var opt = document.createElement('option');
      opt.value = i + 1;
      opt.text = i + 1;
      if(i === day-1){
        opt.setAttribute("selected", "selected")
      }
      daydropdown.appendChild(opt);
    }
    But this is all getting ugly and hacky.
    I'm a bit tied up right now, but I'll have a look at this tonight and tidy thing up a little.

    One question, what should happen when the user changes the month.
    Should the day default back to 1 or should it stay on the current value.

    For example, if I am on the 5th January and I change the month to the February, should the day dropdown display 1 or 5?

    Also, are you using jQuery for this project?
    We can easily do this in plain JS but jQuery makes the syntax a little nicer.

  7. #7
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Oh and by the way, the code already deals with leap years (just try going to Feb 2016 and seeing how many days there are).

  8. #8
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Like I said brilliant Pullo! I saw that form the leap year Yes when people change month I think the best way would be to default back to 1. Thanks a lot!!!!!!
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  9. #9
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    By the way. Yes im using jquery in this project
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  10. #10
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Hi donboe,

    I made this a bit more modular.

    You now specify a div with a class of dateDropdown and fill it with some fallback HTML which will be served to those people with JS disabled:

    Code:
    <div class="dateDropdown">
      <label for="dateField1">Please enter the date:</label>
      <input id="dateField1" type="text" placeholder="dd.mm.yyyy"/>
    </div>
    You can have as many of these dateDropdowns as you fancy on your page.

    You then include jQuery and my code which is wrapped in this:

    Code:
    DateWidget = { ... }
    Then you initialize it and it will add the appropriate dropdowns to all of the aforementioned divs.

    Code:
    DateWidget.init();
    It will also initialize each date widget to the current date.

    Here's a demo.

    And here's the code:

    Code:
    <!doctype html>
      <html>
      <head>
        <meta charset="utf-8">
        <title>Date widget</title>
        <style>div{ margin:15px; }</style>
      </head>
    
      <body>
        <div class="dateDropdown">
          <label for="dateField1">Please enter the date:</label>
          <input id="dateField1" type="text" placeholder="dd.mm.yyyy"/>
        </div>
    
        <div class="dateDropdown">
          <label for="dateField2">Please enter the date:</label>
          <input id="dateField2" type="text" placeholder="dd.mm.yyyy"/>
        </div>
    
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script type="text/javascript">
          var s,
          DateWidget = {
            settings: {
              months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'],
              day: new Date().getUTCDate(),
              currMonth: new Date().getUTCMonth(),
              currYear: new Date().getUTCFullYear(),
              yearOffset: 21,
              containers: $(".dateDropdown")
            },
    
            init: function() {
              s = this.settings;
              DW = this;
              s.containers.each(function(){
                DW.removeFallback(this);
                DW.createSelects(this);
                DW.populateSelects(this);
                DW.initializeSelects(this);
                DW.bindUIActions();
              })
            },
    
            getDaysInMonth: function(month, year) {
               return new Date(year, month, 0).getDate();
            },
    
            addDays: function(daySelect, numDays){
              $(daySelect).empty();
    
              for(var i = 0; i < numDays; i++){
                $("<option />")
                  .text(i + 1)
                  .val(i + 1)
                  .appendTo(daySelect);
              }
            },
    
            addMonths: function(monthSelect){
              for(var i = 0; i < 12; i++){
                $("<option />")
                  .text(s.months[i])
                  .val(s.months[i])
                  .appendTo(monthSelect);
              }
            },
    
            addYears: function(yearSelect){
              for(var i = 0; i < s.yearOffset; i++){
                $("<option />")
                  .text(i + s.currYear)
                  .val(i + s.currYear)
                  .appendTo(yearSelect);
              }
            },
    
            removeFallback: function(container) {
              $(container).empty();
            },
    
            createSelects: function(container) {
              $("<select class='day'>").appendTo(container);
              $("<select class='month'>").appendTo(container);
              $("<select class='year'>").appendTo(container);
            },
    
            populateSelects: function(container) {
              DW.addDays($(container).find('.day'), DW.getDaysInMonth(s.currMonth, s.currYear));
              DW.addMonths($(container).find('.month'));
              DW.addYears($(container).find('.year'));
            },
    
            initializeSelects: function(container) {
              $(container).find('.day').val(s.day);
              $(container).find('.currMonth').val(s.month);
              $(container).find('.currYear').val(s.year);
            },
    
            bindUIActions: function() {
              $(".month").on("change", function(){
                var daySelect = $(this).prev(), 
                    yearSelect = $(this).next(),
                    month = s.months.indexOf($(this).val()) + 1,
                    days = DW.getDaysInMonth(month, yearSelect.val());
                DW.addDays(daySelect, days);
              });
    
              $(".year").on("change", function(){
                var daySelect = $(this).prev().prev(), 
                    monthSelect = $(this).prev(),
                    month = s.months.indexOf(monthSelect.val()) + 1,
                    days = DW.getDaysInMonth(month, $(this).val());
                DW.addDays(daySelect, days);
              });
            }
          };
    
          DateWidget.init();
        </script>
      </body>
    </html>
    Last edited by Pullo; Jan 6, 2014 at 02:56. Reason: Updated code

  11. #11
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very nice indeed Pullo. Thanks a lot.
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  12. #12
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Hi Pullo.

    Can I ask a question? Why are you creating three Date objects to get the current day, month and year in settings? One should be enough.
    Last edited by Pullo; Jan 6, 2014 at 07:16. Reason: Replaced my name with my user name

  13. #13
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Yeah, I wasn't happy with that:
    I essentially wanted to do:

    Code:
    settings: {
      today: new.Date(),
      currDay: today.getUTCDate(),
      currMonth: today.getUTCMonth(),
      currYear: today.getUTCFullYear()
    },
    but didn't think it was possible to reference a previously declared attribute in this way.

    What would be the better approach here?

  14. #14
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Code:
            init: function() {
              var today = new Date();
              
              this.settings = {
                months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'],
                day: today.getUTCDate(),
                currMonth: today.getUTCMonth(),
                currYear: today.getUTCFullYear(),
                yearOffset: 21
              };
              
              s = this.settings;
              DW = this;
            }

  15. #15
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Yeah, ok, should've seen that

  16. #16
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    What about s? You are caching the settings, but you're doing that outside the DateWidget object. It's not pretty. Also, settings are DateWidget property, do you think it needs additional caching like this? Or DW?

  17. #17
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    I wanted to try and make this a little more modular for the OP, for example so it can just be dropped into a page with little configuration.

    The s thing sure doesn't look pretty, I agree with you there.
    I got the skeleton for everything from here: http://css-tricks.com/how-do-you-str...ttern-edition/

    If this can be improved, or if this was the wrong pattern to use, I'd be glad to hear it.

  18. #18
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Unfortunately for Chris Coyier, that's not the module pattern. The module pattern involves a private scope created by an IIFE.

    Anyway, caching a property like what you're trying to do with s is not useful. Consider what happens in the most likely to occur misuse scenario: if you fail to include its declaration. It will simply be added as a property to DateWidget, creating a reference for settings property in the same DateWidget object. Redundant.

    The current case, where you include its declaration, it's simply a reference, it doesn't cache more than an object property would.

    It's the right pattern, not using IIFE, because you don't need hidden state, and you need shared behavior. Just that s and DW are not really doing anything useful. I'll try and see if I can amend your widget.

  19. #19
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by myty View Post
    I'll try and see if I can amend your widget.
    I'd appreciate that!
    Look forward to your suggestions.

  20. #20
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Let's take this step by step. First step: let's disregard the HTML and the DOM.

    This is my idea of a starter MyDate class:

    Code:
    function MyDate() {};
    
    MyDate.prototype = {
      
        MONTHS: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'],
      
        YEAR_OFFSET: 21,
      
        getToday: function () {
            var today = new Date();
          
            return {
                day: today.getUTCDate(),
                month: today.getUTCMonth(),
                year: today.getUTCFullYear()
            }; 
        },
      
        getDaysInMonth: function(month, year) {
            return new Date(year, month, 0).getDate();
        }
      
    };
    
    > var date = new MyDate();
    > date
    > MyDate {MONTHS: Array[12], YEAR_OFFSET: 21, getToday: function, getDaysInMonth: function}

  21. #21
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Ok, with you so far.

  22. #22
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    I'm home now, back from work, so I can get into a little more details, just in case.

    The constructor function for the class is not doing anything at the moment. This will change, but right now I'm laying down the basics from which I start. It's always good to start from small.

    New objects will be based on the new MyDate class. There are things that are the same for every instance, every object. Those things belong in the class, the prototype object in this case, they don't need to be duplicated for every new object created. As an aside, that's one drawback of the module pattern: the code logic is duplicated for every other object based on it. We end up with a lot of redundant code logic, eating up memory.

    We call some of these common properties "constants". In current mainstream JavaScript, there is no constant concept implementation, so we declare them using all caps, merely a style convention.

    Some other common properties present in my class so far are, of course, the class methods.

    One thing to notice about these methods, is that getting the current date is no longer a one time thing upon object initialization. This is wrong. What if, between loading the page and the time the user actually uses the widget, the current date has changed?

    The other method, like the today method, has no ties with outside systems (DOM) so I just copied it from your original code.

    If there are no questions so far, I'll continue in my next post with building the class.

  23. #23
    Grüße aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,895
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by myty View Post
    I'm home now, back from work, so I can get into a little more details, just in case.
    Good stuff.
    I'm always surprised that you can post so much from work.
    You must have an understanding boss.

    Quote Originally Posted by myty View Post
    The constructor function for the class is not doing anything at the moment. This will change, but right now I'm laying down the basics from which I start. It's always good to start from small.
    Ok.
    It's nice to see how you would approach this.
    I basically started with a load of boilerplate and adapted it to suit.

    Quote Originally Posted by myty View Post
    New objects will be based on the new MyDate class. There are things that are the same for every instance, every object. Those things belong in the class, the prototype object in this case, they don't need to be duplicated for every new object created.
    Got it.

    Quote Originally Posted by myty View Post
    We call some of these common properties "constants". In current mainstream JavaScript, there is no constant concept implementation, so we declare them using all caps, merely a style convention.
    Same notation as Ruby, so seems familiar.

    Quote Originally Posted by myty View Post
    One thing to notice about these methods, is that getting the current date is no longer a one time thing upon object initialization. This is wrong. What if, between loading the page and the time the user actually uses the widget, the current date has changed?
    I don't see that particular scenario as overly problematic, but ok.

    Quote Originally Posted by myty View Post
    If there are no questions so far, I'll continue in my next post with building the class.
    No, that's all quite clear.
    That's not to say that I would have approached the problem like this (I wouldn't have), but I understand what you have done and why you have done it.
    Where it's going to get interesting is when it comes to tying this in to DOM elements.

    Thanks for taking the time to improve upon my solution!

  24. #24
    SitePoint Wizard donboe's Avatar
    Join Date
    Jun 2010
    Location
    Netherlands
    Posts
    2,068
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So what is the problem if it is working?
    “Good artists copy, great artists steal” (Pablo Picasso - 1934)

  25. #25
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    In the previous post I created an instance of MyDate class: date. So far, everything resides in the common prototype. But normally, every Mydate instance should have a different state to make it distinct, a state which should not be kept in the prototype, otherwise it would be the same for every date object created.

    The first thing that is specific to each MyDate instance is the HTML element it targets. I will create a targetElement property to hold this reference for every instance independently.

    date.html
    Code:
    <!doctype html>
      <html>
      <head>
        <meta charset="utf-8">
        <title>Date widget</title>
      </head>
    
      <body>
        <div class="dateDropdown">
          <label for="startDate">Please enter the start date:</label>
          <input id="startDate" type="text" placeholder="dd.mm.yyyy"/>
        </div>
    
        <div class="dateDropdown">
          <label for="endDate">Please enter the end date:</label>
          <input id="endDate" type="text" placeholder="dd.mm.yyyy"/>
        </div>
        
        <script src="date.js"></script>
        <script src="demo.js"></script>
      </body>
    </html>
    date.js
    Code:
    function MyDate(id) {
        this.targetElement = document.getElementById(id);
    };
    
    MyDate.prototype = {
      
        MONTHS: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec'],
      
        YEAR_OFFSET: 21,
      
        getToday: function () {
            var today = new Date();
          
            return {
                day: today.getUTCDate(),
                month: today.getUTCMonth(),
                year: today.getUTCFullYear()
            }; 
        },
      
        getDaysInMonth: function (month, year) {
            return new Date(year, month, 0).getDate();
        },
        
        toggle: function () {
            var elemStyle = this.targetElement.style;
            
            if (elemStyle.display === "none") {
                elemStyle.display = "";
            } else {
                elemStyle.display = "none";
            };
        }
      
    };
    demo.js
    Code:
    var sdat = new MyDate("startDate"),
        edat = new MyDate("endDate");
    
    sdat.toggle();
    Now the constructor function is finally doing something useful. It receives an id and it saves a reference to the target element.

    The toggle method is common to all MyDate instances so it goes in the common pot, the prototype. The only hasOwnProperty sdat and edat have is targetElement.

    This will make it the only property which can be different from instance to instance. sdat's targetElement is input#startDate, edat's targetElement is input#endDate.

    This way it's possible to independently toggle every targeted HTML element, using a unique and common class method.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •