Javascript 如何处理嵌套表单的条件验证?
我似乎无法理解以下几点: 我将cocoon用于嵌套表单,在每个表单中,通过FlatPicker请求开始日期和结束日期。我想做两件事中的一件(以最简单的为准)Javascript 如何处理嵌套表单的条件验证?,javascript,ruby-on-rails,cocoon-gem,flatpickr,Javascript,Ruby On Rails,Cocoon Gem,Flatpickr,我似乎无法理解以下几点: 我将cocoon用于嵌套表单,在每个表单中,通过FlatPicker请求开始日期和结束日期。我想做两件事中的一件(以最简单的为准) 验证提交的日期范围之间是否没有重叠,但由于日期尚未在数据库中,我无法在验证中验证它们 不要通过禁用在日历中显示不可用的日期 形式 @年龄\表\列表,值\方法::id,标签\方法:false%> 每期客人的价格: 再加一个句号 $(文档).ready(函数(){ //$(文档).find(“#第一个#日期”)).flatpickr();
- 验证提交的日期范围之间是否没有重叠,但由于日期尚未在数据库中,我无法在验证中验证它们
- 不要通过禁用在日历中显示不可用的日期
@年龄\表\列表,值\方法::id,标签\方法:false%>
每期客人的价格:
再加一个句号
$(文档).ready(函数(){
//$(文档).find(“#第一个#日期”)).flatpickr();
const startDateInput=$(document.find(“.first\u date”)
const endDateInput=$(document.find(“.second_date”)
if(startDateInput&&endDateInput){
const unvailableDates=JSON.parse(document.querySelector(“.widget content”).dataset.unavailable)
FlatPicker(起始日期输入{
//minDate:“今天”,
//日期格式:“d-m-Y”,
禁用:不可用日期,
格式:“d-m-Y”,
altFormat:“d-m-Y”,
altInput:是的,
onChange:函数(selectedDates,selectedDate){
如果(selectedDate==''){
endDateInput.disabled=true;
}
让minDate=selectedDates[0];
minDate.setDate(minDate.getDate()+1);
endDateCalendar.set('minDate',minDate);
endDateInput.disabled=false;
}
});
常量结束日期日历=
FlatPicker(endDateInput{
//日期格式:“d-m-Y”,
禁用:不可用日期,
格式:“d-m-Y”,
altFormat:“d-m-Y”,
altInput:是的,
},
);
};
});
嵌套形式
<div class="nested-fields border-bottom">
<div class="row">
<div class="col col-sm-6"><%= f.input :price, placeholder: "e.g. 12.99" %></div>
</div>
<div class="row">
<div class="col col-sm-6"><%= f.input :start_date,
as: :string,
label:"Start date",
placeholder: "From",
wrapper_html: { class: "inline_field_wrapper" },
input_html:{ class: "first_date"} %></div>
<div class="col col-sm-6"><%= f.input :end_date,
as: :string,
label:"End date",
placeholder: "to",
wrapper_html: { class: "inline_field_wrapper" },
input_html:{ class: "second_date"} %></div>
</div>
<div hidden class= "widget-content" data-unavailable="<%= @extra_guest.unavailable_dates.to_json %>"></div>
<div class="col col-sm-6 option-price-delete">
<%= link_to_remove_association f do %>
<i class="fas fa-trash"> Delete price</i>
<% end %>
</div>
</div>
<script>
$(document).on('cocoon:after-insert', function(e, added_guest_price_form){
// $(added_guest_price_form.find("#first_date")).flatpickr();
const startDateInput = $(added_guest_price_form.find(".first_date"))
const endDateInput = $(added_guest_price_form.find(".second_date"))
if (startDateInput && endDateInput) {
const unavailableDates = JSON.parse(document.querySelector('.widget-content').dataset.unavailable)
// console.log(unvailableDates)
flatpickr(startDateInput, {
format: "d-m-Y",
altFormat: "d-m-Y",
altInput: true,
// minDate: 'today',
// dateFormat: 'd-m-Y',
disable: unavailableDates,
onChange: function(selectedDates, selectedDate) {
if (selectedDate === '') {
endDateInput.disabled = true;
}
let minDate = selectedDates[0];
minDate.setDate(minDate.getDate() + 1);
endDateCalendar.set('minDate', minDate);
endDateInput.disabled = false;
}
});
const endDateCalendar =
flatpickr(endDateInput, {
format: "d-m-Y",
altFormat: "d-m-Y",
altInput: true,
// dateFormat: 'd-m-Y',
disable: unavailableDates,
},
);
};
});
</script>
删除价格
$(文档).on('cocoon:after insert',函数(e,添加了\u guest\u price\u表单){
//$(添加了_guest_price_form.find(#first_date)).flatpickr();
const startDateInput=$(添加了\u guest\u price\u form.find(“.first\u date”))
const endDateInput=$(添加了\u guest\u price\u form.find(“.second\u date”))
if(startDateInput&&endDateInput){
const unavailableDates=JSON.parse(document.querySelector('.widget content').dataset.unavailable)
//console.log(不可用日期)
FlatPicker(起始日期输入{
格式:“d-m-Y”,
altFormat:“d-m-Y”,
altInput:是的,
//minDate:“今天”,
//日期格式:“d-m-Y”,
禁用:不可用日期,
onChange:函数(selectedDates,selectedDate){
如果(selectedDate==''){
endDateInput.disabled=true;
}
让minDate=selectedDates[0];
minDate.setDate(minDate.getDate()+1);
endDateCalendar.set('minDate',minDate);
endDateInput.disabled=false;
}
});
常量结束日期日历=
FlatPicker(endDateInput{
格式:“d-m-Y”,
altFormat:“d-m-Y”,
altInput:是的,
//日期格式:“d-m-Y”,
禁用:不可用日期,
},
);
};
});
验证器
class ExtraGuestPriceAvailabilityValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
extra_guest_prices = ExtraGuestPrice.where("extra_guest_id =?", record.extra_guest_id)
extra_guest_price = ExtraGuestPrice.where("id=?", record.id)
if extra_guest_price.empty?
date_ranges = extra_guest_prices.map { |b| b.start_date..b.end_date }
date_ranges.each do |range|
if range.include? value
record.errors.add(attribute, "is overlapping with another period")
end
end
else
date_ranges = extra_guest_prices.where.not('id=?', record.id).map { |b| b.start_date..b.end_date }
date_ranges.each do |range|
if range.include? value
record.errors.add(attribute, "is overlapping with another period")
end
end
end
end
end
类ExtraGuestPriceAvailabilityValidator
您如何设置验证器?我认为您正在验证每个ExtraGuestPrice,您应该立即验证整个集合
差不多
class ExtraGuest
validate :no_dates_overlap
def no_dates_overlap
ranges = [] # cache proccessed date ranges
# iterate over all extra_guest_prices
extra_guest_prices.each do |egp|
if ranges.any? { |rng| rng.include?(egp.start_date) || rng.include?(egp.end_date) }
# if a previous range includes this dates, add the error and break the loop
errors.add(:extra_guest_prices, "Dates overlap")
break
else
# else, cache it and check the next
ranges << (egp.start_date..egp.end_date)
end
end
end
类外部来宾
验证:没有日期重叠
def无日期重叠
范围=[]#缓存已处理的日期范围
#迭代所有额外的客人价格
额外的客人价格。每个都是埃及镑|
如果有的话?{| rng | rng.include?(egp.start_date)| rng.include?(egp.end_date)}
#如果以前的范围包括此日期,则添加错误并中断循环
错误。添加(:额外的客人价格,“日期重叠”)
打破
其他的
#否则,缓存它并检查下一个
非常感谢你!这确实正确地触发了验证:)现在,我只需要找到一种显示错误消息的方法,因为它不会显示在表单中(在幕后,它不会在无日期重叠时进行验证
,但在表单中,它显示了额外客人价格.开始日期和额外客人价格.结束时的积极验证。)_date@techquestion有点离题了,我希望你们能尝试一下我自己的gem用于嵌套表单,它类似于cocoon,但没有gem,也没有jquery依赖项,是吗不太难尝试,因为它非常相似。结束离题的hahatypo,“在幕后,它确实在没有日期重叠的情况下进行验证。@arieljuod,很酷,你做了一块宝石,我一定会看一看;)如果你不想在日期上添加验证,而不是错误。添加(:额外客人价格,…)
doegp.errors.add(:开始日期,…)
class ExtraGuest
validate :no_dates_overlap
def no_dates_overlap
ranges = [] # cache proccessed date ranges
# iterate over all extra_guest_prices
extra_guest_prices.each do |egp|
if ranges.any? { |rng| rng.include?(egp.start_date) || rng.include?(egp.end_date) }
# if a previous range includes this dates, add the error and break the loop
errors.add(:extra_guest_prices, "Dates overlap")
break
else
# else, cache it and check the next
ranges << (egp.start_date..egp.end_date)
end
end
end