如何使 Javascript 生成的复选框持续存在?
How to make Javascript generated checkboxes persist?
脚本中的 "ajax" 向服务器发送 post 或删除消息。包含 ajax 的 javascript 是添加复选框的内容。我们如何使创建的复选框元素持久化,以便当用户刷新页面时它们仍然存在?
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() {
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);
});
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
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
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
这是要点:https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
如果您需要任何进一步的解释、代码或图片,请告诉我:)
最简单的方法是使用本地存储(存储在用户浏览器中)。该功能存在于现代浏览器中,因此当您不需要支持旧版浏览器时,它是最佳选择。
用法也非常简单,只需在 "localStorage" 变量上设置和读取属性即可:
# Set one value
localStorage.myapp_level1_flag1 = true;
# read the value
if (localStorage.myapp_level1_flag1) {
...
}
你当然应该给变量起有意义的名字。分配给 localStorage 的值将跨会话保存。还有一个变量"sessionStorage",只保存一个session的数据
此外,数据由设置的域分隔。所以域X不能访问域Y设置的数据。
从 IE8 开始大致支持本地存储,并且与 cookie 相比具有优势,即数据不会在每次请求时都传输到服务器。在本地存储存在之前,使用 cookie 会增加一些性能开销。
积分
我建议在您的代码中的两个位置集成本地存储(如果我理解您的 JS 大纲的话):
(of course, you say, that you don't understand JS to much, that makes
the thing much more difficult, because the solution hinges completely
on local storage at the browser side -- but else you would need to
transfer all the data from your server side (which could be necessary
in the long run to prevent data duplication))
第一个位置:创建复选框时(只是一个粗略的示例):
if (localStorage.habit_level1_flag1) {
$(this).parent().append($('<input type="checkbox" class="habit-check" checked>'));
}
else {
$(this).parent().append($('<input type="checkbox" class="habit-check">'));
}
另一个位置在更改处理程序处:
if ($(this).is(":checked")) {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed",
method: "POST"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
} else {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
}
在此处查看有关 localStorage 的更多信息。
脚本中的 "ajax" 向服务器发送 post 或删除消息。包含 ajax 的 javascript 是添加复选框的内容。我们如何使创建的复选框元素持久化,以便当用户刷新页面时它们仍然存在?
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() {
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);
});
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
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
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
这是要点:https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
如果您需要任何进一步的解释、代码或图片,请告诉我:)
最简单的方法是使用本地存储(存储在用户浏览器中)。该功能存在于现代浏览器中,因此当您不需要支持旧版浏览器时,它是最佳选择。
用法也非常简单,只需在 "localStorage" 变量上设置和读取属性即可:
# Set one value
localStorage.myapp_level1_flag1 = true;
# read the value
if (localStorage.myapp_level1_flag1) {
...
}
你当然应该给变量起有意义的名字。分配给 localStorage 的值将跨会话保存。还有一个变量"sessionStorage",只保存一个session的数据
此外,数据由设置的域分隔。所以域X不能访问域Y设置的数据。
从 IE8 开始大致支持本地存储,并且与 cookie 相比具有优势,即数据不会在每次请求时都传输到服务器。在本地存储存在之前,使用 cookie 会增加一些性能开销。
积分
我建议在您的代码中的两个位置集成本地存储(如果我理解您的 JS 大纲的话):
(of course, you say, that you don't understand JS to much, that makes the thing much more difficult, because the solution hinges completely on local storage at the browser side -- but else you would need to transfer all the data from your server side (which could be necessary in the long run to prevent data duplication))
第一个位置:创建复选框时(只是一个粗略的示例):
if (localStorage.habit_level1_flag1) {
$(this).parent().append($('<input type="checkbox" class="habit-check" checked>'));
}
else {
$(this).parent().append($('<input type="checkbox" class="habit-check">'));
}
另一个位置在更改处理程序处:
if ($(this).is(":checked")) {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed",
method: "POST"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
} else {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
}
在此处查看有关 localStorage 的更多信息。