Moment / Jquery - Silly issue with a simple timeli

2019-09-10 02:49发布

I had alot of help from this community getting my timeline report to work correctly. The way this is setup is that it will get a date range by checking the ajax return. Then it will group all my entries by their day of the week. If there are no entries for a particular i that date range, then it will simply return "No entries today."

Fo far everything is working and you can see the example below: https://jsfiddle.net/j3yg2j7j/7/

However I noticed that if the last day in the date range is empty it ignores it. I need it to return "No entries today." even if the last day is empty.

Here is an example of the issue. https://jsfiddle.net/j3yg2j7j/6/

UPDATE: Found another weird issue. When i give it the range of 2016-05-02 to 2016-05-05. I start getting duplicate items.

https://jsfiddle.net/j3yg2j7j/5/

This is the Ajax request:

responseText: {
    d: {
        results: [{
            ID: "1",
            Description: "Test1",
            Date: "2016-05-02 09:45"
        }, {
            ID: "2",
            Description: "Test2",
            Date: "2016-05-02 10:45"
        }, {
            ID: "3",
            Description: "Test3",
            Date: "2016-05-03 11:45"
        }, {
            ID: "4",
            Description: "Test4",
            Date: "2016-05-03 11:45",
        }]
    }
}

This is the javascript:

      var items_by_date  = {}; // declare an object that will have date indexes
      $.ajax({url:"/SomeUrlBeginninWithSlash",
          dataType: 'json',
          cache: false,
          success: function (data) {
                    console.log("SUCCESS",data);    
                    drawTable(data.d.results);
          }
      });

 var drawTable = function(data) {
  // First sort the entries by date:
  data = data.sort(function(a, b) {
    return (moment(a.Date) - moment(b.Date));
  });

  // Find the date range to work with by looking at each end of the array:
  var firstDate = moment("2016-05-02");
  var lastDate = moment("2016-05-04");

  // loop through each day in that range, keeping track of a starting point i
  // so we don't have to keep checking already-passed events.
  var i = 0, // pointer to the first entry to check on the next date
    ret = ""; 
  for (var thisDate = firstDate; thisDate <= lastDate; thisDate.add(1, 'days')) {
    ret += '<tr><th>' + thisDate.format("dddd, MMMM D") + "</th></tr>";

    // check to see if the next entry is already beyond thisDate:
    if (moment(data[i].Date) > thisDate.endOf('day')) {
      ret += "<tr><td>No entries today.</td></tr>";
    } else {
      // starting at entry i, display all entries before the end of thisDate:
      for (var j = i; j < data.length; j++) {
        if (moment(data[j].Date) < thisDate.endOf('day')) {
          // the next one belongs on thisDate, so display it:
          ret += '<tr><td>' + moment(data[j].Date).format("HH:mm") + " - " + data[j].Description + "</td></tr>";
        } else {
          // next one is not for thisDate, so we can go on to the next day.
          i = j; // It'll start here, so we don't waste time looping over past events
          break; // (out of the inner loop)
        }
      }
    }
  }
  $('#x').html(ret);
}

I know im overlooking something simple but cant quite put my finger on it.

1条回答
Melony?
2楼-- · 2019-09-10 03:16

For the missing last day, you're setting lastDate to the beginning of May 4th -- it needs to be at the end of that day instead:

var lastDate = moment("2016-05-04").endOf('day');

The repeated events are because the code I wrote for your last question assumed that the last date in the list of entries would be the last date you'd want to display, so it didn't need to handle the case where you continue to loop through dates after running out of entries. That can be fixed by, well, handling that case:

if (i === data.length) {
   // we've run out of entries; don't try to check past the end of the data array:
   ret += "<tr><td>No entries today.</td></tr>";   
} else if (moment(data[i].Date) > thisDate.endOf('day')) {
  // The next entry is later than this day.
  ret += "<tr><td>No entries today.</td></tr>";
} else {
  // starting at entry i, display all entries before the end of thisDate:
  for (var j = i; j < data.length; j++) {
    if (moment(data[j].Date) < thisDate.endOf('day')) {
      // the next one belongs on thisDate, so display it:
      ret += '<tr><td>' + moment(data[j].Date).format("HH:mm") + " - " + data[j].Description + "</td></tr>";
    } else {
      // next one is not for thisDate, so we can go on to the next day.
      i = j; // It'll start here, so we don't waste time looping over past events
      break; // (out of the inner loop)
    }
  }
  // Did we run out of entries?  If so, need to update i here to prevent repeated display
  if (j === data.length) {
    i = j;
  }
}

https://jsfiddle.net/tt35rnoo/

However...

Given the number of times you've asked variations on this question, it may be better to keep things simple here. Try this less efficient but much less complicated version, which doesn't try to skip past already-displayed events on each loop:

  // loop through each day in that range
  var ret = ""; 
  for (var thisDate = firstDate; thisDate <= lastDate; thisDate.add(1, 'days')) {
    ret += '<tr><th>' + thisDate.format("dddd, MMMM D") + "</th></tr>";
    var showedAnEventToday=false;

    for (var j = 0; j < data.length; j++) {
        if (
            moment(data[j].Date) > thisDate.startOf('day') && 
            moment(data[j].Date) < thisDate.endOf('day')
        ) {

          showedAnEventToday = true;
          ret += '<tr><td>' + moment(data[j].Date).format("HH:mm") + " - " + data[j].Description + "</td></tr>";
        } 
    }
    if (!showedAnEventToday) {
        ret += '<tr><td>No events today.</td></tr>';
    }
  }
  $('#x').html(ret);

https://jsfiddle.net/ejaca00t/

查看更多
登录 后发表回答