那么,如果这些新的复选框被选中另外3复选框会显示该水平。
习惯/ _form.html.erb
<标签ID =<%= @ habit.id%>中类=习惯-ID>错过:其中; /标签>
<%@ habit.levels.each_with_index办|水平,指数| %>
<%@如果habit.current_level> =(索引+ 1)%>
&其中p为H.;
<标签ID =<%= level.id%>中类=级ID>平<%=指数+ 1%计算值:< /标签>
<%= check_box_tag为零,真正的,level.missed_days> 0,{类:习惯检查}%>
<%= check_box_tag为零,真正的,level.missed_days> 1,{类:习惯检查}%>
<%= check_box_tag为零,真正的,level.missed_days> 2,{类:习惯检查}%>
&所述; / P>
<%结束%GT;
<%结束%GT;
habit.js
$(文件)。就绪(函数()
{
$(习惯检查)。改变(函数()
{
习惯= $(本).parent()兄弟(习惯-ID。)(第)ATTR(ID)。;
级= $(本).siblings(电平-ID)的第一()ATTR(ID)。;
如果($(本)。是(:选中))
{
$阿贾克斯(
{
网址:/习惯/+习惯+/级别/+等级+/ days_missed
方法:POST
});
}
其他
{
$阿贾克斯(
{
网址:/习惯/+习惯+/级别/+等级+/ days_missed / 1,
方法:DELETE
});
}
});
});
habit.rb
类习性<的ActiveRecord :: Base的
belongs_to的:用户
的has_many:意见为::commentable
的has_many:水平
连载:承诺,阵列
验证:date_started,presence:真
before_save:current_level
acts_as_taggable
适用范围:private_submit, - > {其中,(private_submit:真)}
适用范围:public_submit, - > {其中,(private_submit:假)}
attr_accessor:missed_one,:missed_two,:missed_three
高清save_with_current_level
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.save
结束
高清self.committed_for_today
today_name =日期:: DayNames中[Date.today.wday] .downcase
IDS = all.select {| H | h.committed.include? today_name} .MAP(安培;:ID)
其中,(ID:IDS)
结束
高清current_level_strike
各级[current_level - 1]#记得数组索引从0开始
结束
高清current_level
返回0,除非date_started
高清committed_wdays
committed.map做|天|
日期:: DAYNAMES.index(day.titleize)
结束
结束
高清n_days
((date_started.to_date).. Date.today).Count之间做|日期|
committed_wdays.include? date.wday
结束 - self.missed_days - self.days_lost
结束
案例n_days
当0..9
1
当10..24
2
当25..44
3
当45..69
4
当70..99
五
其他
6
结束
结束
结束
days_missed_controller
类DaysMissedController<的ApplicationController
before_action:LOGGED_IN_USER,只有:[:创建:摧毁]
DEF创建
习惯= Habit.find(PARAMS [:habit_id])
habit.missed_days = habit.missed_days + 1
habit.save!
水平= habit.levels.find(PARAMS [:level_id])
level.missed_days = level.missed_days + 1
level.save!
头:OK#此方法返回一个200成功状态code空响应
如果missed_days == 3
missed_days = 0
days_lost + = pending_days
pending_days + = 1
pending_days = 0
结束
结束
DEF破坏
习惯= Habit.find(PARAMS [:habit_id])
habit.missed_days = habit.missed_days - 1
habit.save
水平= habit.levels.find(PARAMS [:level_id])
level.missed_days = level.missed_days - 1
level.save!
头:OK#此方法返回一个200成功状态code空响应
结束
结束
如果您需要进一步的解释,code或照片,请不要犹豫,问,你也可以在这里找到你的自由裁量权我额外的code:的 https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
谢谢!
解决方案附加的处理程序变更
事件,这与属性计算有多少投入要素的每个复选框类型=复选框
这是:没有(:选中)
有。如果没有选中框下添加三箱和相同的Click事件处理程序附加到每一个新的对话框。每次所有的箱子都装满它会增加三个新的。
这是脚本的相关逻辑部分
如果(element.querySelectorAll(!'输入[类型=复选框]:没有(:选中)。)长){
/ *新增三个复选框* /
}
如果有型复选框不具有任何输入字段的状态检查,length属性将是未定义和解决为false。如果有输入字段相匹配的previously陈述的标准,length属性将是1或更高的数字值,将解析为真。
示例
VAR boxWrap = document.querySelector('盒子');
VAR handleChange =功能(){
如果(boxWrap.querySelectorAll('输入[类型=复选框]:没有(:选中)!。)长){
addBoxes(3);
}
};
VAR addBoxes =功能(N){
对于(I = 0; I&n种;我++){
VAR箱= document.createElement方法(输入);
box.type =复选框;
box.addEventListener('变',handleChange,假);
boxWrap.appendChild(箱);
}
};
盒= boxWrap.querySelectorAll('输入[类型=复选框]');
对于(VAR I = 0; I< boxes.length;我++){
盒[I] .addEventListener('改变',handleChange,假);
}
< DIV CLASS =盒子>
<输入类型=复选框>
<输入类型=复选框>
<输入类型=复选框>
< / DIV>
修改
我已经改变了一些东西,你的原剧本
改进格式
改,你觉得水平-id和习惯-id来降低复杂性的方式。
我搬到了上改变功能到一个名为处理函数,以便它可以被应用到新的复选框。
补充上述逻辑在onchange事件捕获。
我已经包括了如何添加新的复选框一个基本的例子,你将需要更改HTML并添加逻辑,以确定哪些属性应该是。
$(文件)。就绪(函数(){
VAR handleChange =功能(){
习惯= $(本).parent()preV()ATTR(ID)。;
水平= $('标签',$(本).parent())ATTR(ID)。
如果($(本)。是(:选中)){
$阿贾克斯({
网址:/习惯/+习惯+/级别/+等级+/ days_missed
方法:POST
});
} 其他 {
$阿贾克斯({
网址:/习惯/+习惯+/级别/+等级+/ days_missed / 1,
方法:DELETE
});
}
如果($('输入[类型=复选框]:没有(:选中)!,$(本).parent())长。){
/ *这只是一个例子,你将不得不ammend这个* /
$(本).parent()追加($('<输入类型=复选框级=习惯检查>'));
$(本).parent()追加($('<输入类型=复选框级=习惯检查>'));
$(本).parent()追加($('<输入类型=复选框级=习惯检查>'));
$(习惯检查。)对('改变',handleChange)。
}
}
$(习惯检查。)对('改变',handleChange)。
});
Then if those new boxes are checked another 3 checkboxes would show for that level.
habits/_form.html.erb
<label id="<%= @habit.id %>" class="habit-id"> Missed: </label>
<% @habit.levels.each_with_index do |level, index| %>
<% if @habit.current_level >= (index + 1) %>
<p>
<label id="<%= level.id %>" class="level-id"> Level <%= index + 1 %>: </label>
<%= check_box_tag nil, true, level.missed_days > 0, {class: "habit-check"} %>
<%= check_box_tag nil, true, level.missed_days > 1, {class: "habit-check"} %>
<%= check_box_tag nil, true, level.missed_days > 2, {class: "habit-check"} %>
</p>
<% end %>
<% end %>
habit.js
$(document).ready(function()
{
$(".habit-check").change(function()
{
habit = $(this).parent().siblings(".habit-id").first().attr("id");
level = $(this).siblings(".level-id").first().attr("id");
if($(this).is(":checked"))
{
$.ajax(
{
url: "/habits/" + habit + "/levels/" + level + "/days_missed",
method: "POST"
});
}
else
{
$.ajax(
{
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
}
});
});
habit.rb
class Habit < ActiveRecord::Base
belongs_to :user
has_many :comments, as: :commentable
has_many :levels
serialize :committed, Array
validates :date_started, presence: true
before_save :current_level
acts_as_taggable
scope :private_submit, -> { where(private_submit: true) }
scope :public_submit, -> { where(private_submit: false) }
attr_accessor :missed_one, :missed_two, :missed_three
def save_with_current_level
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.levels.build
self.save
end
def self.committed_for_today
today_name = Date::DAYNAMES[Date.today.wday].downcase
ids = all.select { |h| h.committed.include? today_name }.map(&:id)
where(id: ids)
end
def current_level_strike
levels[current_level - 1] # remember arrays indexes start at 0
end
def current_level
return 0 unless date_started
def committed_wdays
committed.map do |day|
Date::DAYNAMES.index(day.titleize)
end
end
def n_days
((date_started.to_date)..Date.today).count do |date|
committed_wdays.include? date.wday
end - self.missed_days - self.days_lost
end
case n_days
when 0..9
1
when 10..24
2
when 25..44
3
when 45..69
4
when 70..99
5
else
6
end
end
end
days_missed_controller
class DaysMissedController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
def create
habit = Habit.find(params[:habit_id])
habit.missed_days = habit.missed_days + 1
habit.save!
level = habit.levels.find(params[:level_id])
level.missed_days = level.missed_days + 1
level.save!
head :ok # this returns an empty response with a 200 success status code
if missed_days == 3
missed_days = 0
days_lost += pending_days
pending_days += 1
pending_days = 0
end
end
def destroy
habit = Habit.find(params[:habit_id])
habit.missed_days = habit.missed_days - 1
habit.save
level = habit.levels.find(params[:level_id])
level.missed_days = level.missed_days - 1
level.save!
head :ok # this returns an empty response with a 200 success status code
end
end
If you need further explanation, code, or pictures please don't hesitate to ask, you can also find at your discretion my additional code here: https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
Thank you!
解决方案Attach a handler for the change
event to each check box which counts how many input elements with the attribute type="checkbox"
which are :not(:checked)
there are. If there are no unchecked boxes, add three boxes and attach the same click event handler to each new box. Every time all of the boxes are filled it will add three new ones.
This is the relevant logic part of the script
if(!element.querySelectorAll('input[type="checkbox"]:not(:checked)').length) {
/* add three checkboxes */
}
If there are no input fields of type checkbox which do not have the status checked, the length property will be undefined and resolve to false. If there are input field which match the previously stated criteria, the length property will be a number value of 1 or higher and will resolve to true.
Example
var boxWrap = document.querySelector('.boxes');
var handleChange = function() {
if (!boxWrap.querySelectorAll('input[type="checkbox"]:not(:checked)').length) {
addBoxes(3);
}
};
var addBoxes = function(n) {
for (i = 0; i < n; i++) {
var box = document.createElement('input');
box.type = 'checkbox';
box.addEventListener('change', handleChange, false);
boxWrap.appendChild(box);
}
};
boxes = boxWrap.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < boxes.length; i++) {
boxes[i].addEventListener('change', handleChange, false);
}
<div class="boxes">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
</div>
EDIT
I've changed a couple of things in your original script
Improved formatting
Changed the way that you find the level-id and habit-id to reduce complexity.
I've moved the on change function into a named handler function so that it can be applied to the new checkboxes.
Added the logic described above to your onchange event capture.
I've included a basic example of how to add the new checkboxes, you will need to change the html and add logic to determine what the attributes should be.
$(document).ready(function() {
var handleChange = function() {
habit = $(this).parent().prev().attr("id");
level = $('label', $(this).parent()).attr("id");
if ($(this).is(":checked")) {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed",
method: "POST"
});
} else {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
}
if (!$('input[type="checkbox"]:not(:checked)', $(this).parent()).length) {
/* this is just an example, you will have to ammend this */
$(this).parent().append($('<input type="checkbox" class="habit-check">'));
$(this).parent().append($('<input type="checkbox" class="habit-check">'));
$(this).parent().append($('<input type="checkbox" class="habit-check">'));
$(".habit-check").on('change',handleChange);
}
}
$(".habit-check").on('change',handleChange);
});