DateRangePicker з StimulusJS, Import maps, бібліотека Ransack

pic

Daterangepicker — це надзвичайно популярна бібліотека. На жаль, вона залежить від jQuery. Але є переписаний варіант, що використовує vanilla JS: vanilla-datetimerange-picker.

1. Показати Daterangepicker за допомогою StimulusJS

rails g stimulus daterangepicker
// app/javascript/controllers/daterangepicker_controller.js  
import { Controller } from "@hotwired/stimulus"  

export default class extends Controller {  
 connect() {  
 new DateRangePicker(this.element, {})  
 }  
}




2. Покращення імпорту активів

Імпортування через CDN у файлах Rails є поганою практикою.

Ми можемо перемістити тег `вapplication.css`:

/* app/assets/stylesheets/application.css */  
@import url('https://cdn.jsdelivr.net/gh/alumuko/vanilla-datetimerange-picker@latest/dist/vanilla-datetimerange-picker.css');

І імпортувати moment за допомогою import maps:

./bin/importmap pin moment
// app/javascript/application.js  
import moment from 'moment'  
window.moment = moment

Тепер ви можете видалити 2 з 3 CDN посилань:

-  
-  

vanilla-daterange-picker не існує як npm пакет, тому немає простого способу імпортувати його.

Я спробував скопіювати код DateRangePicker у файл app/assets/javascripts/libraries/[email protected] і імпортувати його в application.js:

// app/javascript/application.js  
import { DateRangePicker } from 'vanilla-daterange-picker@3-1'  
window.DateRangePicker = DateRangePicker

3. Відправка та пошук за діапазоном дат

<%= form_with url: events_path, method: :get do |form| %>  
 <%= form.text_field :start_date_between, value: params[:start_date_between], data: {controller: "daterangepicker"} %>  
 <%= form.submit %>  
<% end %>

Це надасть дані у форматі params[:start_date_between] = "05/01/2023 - 06/30/2023"

Ми будемо шукати по моделі Event за полем start_date:datetime:

# app/controllers/events_controller.rb  
class EventsController < ApplicationController  
 def index  
 # params[:start_date_between] = "05/01/2023 - 06/30/2023"  
 if params[:start_date_between].present?  
 between_data_range = params[:start_date_between].split(' - ').map { |date| Date.strptime(date, '%m/%d/%Y') }  
 @events = Event.where(start_date: between_data_range[0]..between_data_range[1]).order(start_date: :desc)  
 else  
 @events = Event.all.order(start_date: :desc)  
 end  
 end  
end

Інші способи для парсингу дат і пошуку по діапазону дат:

starts = params[:start_date_between].split(" - ").first.to_date  
ends = params[:start_date_between].split(" - ").last.to_date  
@events = Event.where(start_date: starts..ends).order(start_date: :desc)  

starts = params[:start_date_between].split(" - ").first  
ends = params[:start_date_between].split(" - ").last  
@events = Event.where("start_date >= ? AND start_date <= ?", starts, ends).order(start_date: :desc)

4.

Відправка та пошук з Ransack

bundle add ransack
// app/controllers/events_controller.rb  
class EventsController < ApplicationController  
 def index  
 @q = Event.all.ransack(params[:q])  
 @events = @q.result(distinct: true)  
 end  
end
// app/models/event.rb  
class Event < ApplicationRecord  
 def self.ransackable_attributes(auth_object = nil)  
 ["start_date"]  
 end  
end

Активуємо новий between ransacker, який приймає дані у форматі 06 Feb 2022 - 25 Apr 2023 і шукає значення datetime між цими датами. Отже, `startdate_between` прийматиме дані у вказаному форматі.

# config/initializers/ransack.rb  
Ransack.configure do |config|  
 config.add_predicate "between",  
 arel_predicate: "between",  
 formatter: proc { |v| Range.new(*v.split(" - ").map { |s| DateTime.parse(s) }) },  
 validator: proc { |v| v.present? },  
 type: :string  
end

Показуємо форму з пошуком:

<%= form_with url: events_path, method: :get do |form| %>  
 <%= form.text_field :start_date_between, value: params.dig(:q, :start_date_between), data: {controller: "daterangepicker"} %>  
 <%= form.submit %>  
<% end %>

Тепер все повинно працювати!

5. Налаштування та розширення DateRangePicker

Ось кілька чудових налаштувань, які ви можете використати, щоб зробити ваш daterangepicker виглядати ось так:

pic

import { Controller } from "@hotwired/stimulus"  

// Підключається до data-controller="daterangepicker"  
export default class extends Controller {  
 initialize() {  
 const ranges = {  
 Today: [moment(), moment()],  
 Yesterday: [moment().subtract('days', 1), moment().subtract('days', 1)],  
 'Last 7 Days': [moment().subtract('days', 6), moment()],  
 'Last 30 Days': [moment().subtract('days', 29), moment()],  
 'This Month': [moment().startOf('month'), moment().endOf('month')],  
 'Last Month': [moment().subtract('month', 1).startOf('month'), moment().subtract('month', 1).endOf('month')],  
 'Last 365 Days': [moment().subtract('days', 364), moment()],  
 }  

 this.dateRangePicker = new DateRangePicker(this.element, {  
 alwaysShowCalendars: true,  
 ranges: ranges,  
 opens: 'left',  
 autoApply: true,  
 showWeekNumbers: true,  
 // locale: { format: 'MMM DD, YYYY' }, // Apr 27, 2023 - Apr 27, 2023  
 })  
 }  
}

Щасливого кодування !!!

Перекладено з: DateRangePicker with StimulusJS, Import maps, gem Ransack