Rails: How to add tooltip events in datepicker and limit them in few months

試著忘記壹切 提交于 2019-12-24 14:09:23

问题


I have a datepicker in which I want user to see coloured all the events created by admin. It would be nice to add the functionality to add a tooltip with the title of the event.

I know that jQueryUI's datepicker allows such a thing. I have to use the beforeShowDay method. But here comes the questions.

1) How will I pass the @events array to the jquery code? I know I can access to that array in the view but am I allowed to do something like this:

var events = @events;

2) Second and most important question. This approach will lead my application to get an enormous amount of events to handle. This will slow down everything when the events start to get a lot. How can I limit the events just in few months depending on today date?
Hope to be clear. Any help??

UPDATE 1 (first problem and a small part of second are solved) ok I managed to pass to javascript my instance events array like this:

<%= javascript_tag do %>
  var events = <%= raw @calendar_events.to_json %>
<% end %>

This way I can limit the events the way I want simply in the controller via scoping.
When I check in browser console events array is composed this way:

[[" Snap-happy athletes ca...arrival at London 2012 ", "2012-07-28T00:00:00Z"], ["AdWords API Office Hours EMEA", "2012-07-25T00:00:00Z"], ["Under the math", "2012-07-22T00:00:00Z"], ["Superman power", "2012-07-13T00:00:00Z"], ["Google I/O 2012 Keynote","2012-07-01T00:00:00Z"]]

Which is an array made like this [["title", "date of the events"], ...]
But how can I put them in the datepicker with beforeShowDday??

This is my first attempt but it's not working

$("#datepicker").datepicker({
  jQuery.each(events, function(index, event) {
    beforeShowDay: function(event[0]) {
      return [true, "", event[1]];
    }
  });
});

回答1:


From the documentation it looks like the array is just an order of things the jQuery UI is looking for.

The function takes a date as a parameter and must return an array with [0] equal to true/false indicating whether or not this date is selectable, [1] equal to a CSS class name(s) or "" for the default presentation, and [2] an optional popup tooltip for this date. It is called for each day in the datepicker before it is displayed.

Basically the function needs to return three items.

  1. Should the date be selectable
  2. Should you add a class to the day
  3. What is its tooltip

Here's an example in code

// what the function should return
return [
  (boolean) is the date selectable,
  (string) the class to add to the day,
  (string) the text to show when hovered over
]

Update: Stack Overflow (and I presume all Stack Exchange sites) use the following for displaying the "visited" calendar. I think this method is much better than mine so I'm replacing it.

The actual "visited" dates are stored in JSON like so.

{__YEAR__: {__MONTH__: {__DAY__:1}}}

Here's an example.

var visited = {2012: {1: {1:1, 3:1, 4:1, 5:1, 18:1,19:1}, {3: {4:1, 5:1}}}

Then inside beforeShowDay they make sure the visited object's keys exist. Here's my version of their code.

beforeShowDay: function(date) {
  var y = date.getFullYear(),
      m = date.getMonth() + 1,
      d = date.getDay(),

      hasVisited = visited[y] && visited[y][m] && visited[y][m][d];

  return [false, (hasVisited ? 'has-visited-class' : ''), 'date'];        
}

To generate the JSON needed to fill this in is very specific to your table structure. If you need help with creating the JSON I'll need a little more to go on.

Update 2

The problem is JavaScript can't call a function within an object, it's invalid syntax. The other thing is that I'm afraid it would be very inefficient looping through all of the items in the array.

The correct syntax for your code would look like this. But as I mentioned, I wouldn't suggest doing this because of inefficiency.

Note: in the line beforeShowDay: function(__PARAM__). The __PARAM__ is automatically passed by jQuery. Which means you need to make sure it's the value you are looking for, rather than asking jQuery if that's the value jQuery's looking for.

The other thing is that arrays start at 0. In fact, all programming languages start at zero. Therefore, to get the value at the index you want, you would do it like so.

var events = ['created a new product', '30-8-2012'];

console.log(events[0]); // "created a new product"
console.log(events[1]); // "30-8-2012"

Here's the corrected syntax of your code, but it will not work because you can't return from the .each() function like I have below. I'm only providing this so you can see how I'm about to correct what you have written.

$("#datepicker").datepicker({
  beforeShowDay: function(date) {
    jQuery.each(events, function(index, event) {
      var active_class = "no-activity";

      // make sure the event's date matches jQuery's date
      if( event[1] == date ) {
        active_class = "had-activity";
      }

      return [true, active_class, event[0]];
    }
  }
});

The Changes

Inside your controller you need to pull the events out in a very specific way. I'd suggest using a Ruby Hash. A Hash is a key-value pair. Which means you can set the key to your date, and the value to your title. This will allow you to easily match the date provided by jQuery and the dates in your event list.

This is what you need to add to your controller. I used a function called strftime() that will format the date. Basically I changed it to be "day-month-year", which will be easier to match with jQuery.

1. %e returns the day of the month without zero padding. So 1 not 01.

2. %-m returns the month without zero padding.

3. %Y returns a four digit year.

@events = {} # create an empty hash

# get all the events and add them to `@events`
CalendarEvent.select('date, title').all.map do |event|
  @events[event.date.strftime('%e-%-m-%Y')] = event.title
end

Then in your JavaScript you can get the @events with.

<% javascript_tag do %>
$(document).ready(function() {
  var events = <%= @events.to_json %>;

  $("#datepicker").datepicker({
    beforeShowDay: function(date) {
      var y = date.getFullYear(),
          m = date.getMonth() + 1,
          d = date.getDate(), // gets the day of the month
          formatted_date = d + '-' + m + '-' + y;

          hasVisited = events[formatted_date];

      return [true, (hasVisited ? 'has-visited-class' : ''), hasVisited];
    }
  });
});
<% end %>


来源:https://stackoverflow.com/questions/12178385/rails-how-to-add-tooltip-events-in-datepicker-and-limit-them-in-few-months

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!