【问题标题】:The Mystery of the Disappearing Checkmarks消失的复选标记之谜
【发布时间】:2015-06-26 03:38:30
【问题描述】:

如果用户点击一个复选框,下面的代码会触发,但复选标记有时会消失,因此该框在应该选中时未被选中。

$(document).on("page:change", 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"
       });
    }
  });
});

# I ALSO TRIED USING LOCAL STORAGE, BUT IT HAD THE SAME PROBLEM.
# VERSION 2

$(document).on("page:change", 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"
          });
          localStorage.setItem("habit_"+habit+"_"+level, true);
        } else {
          $.ajax({
            url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
            method: "DELETE"
          });
          localStorage.setItem("habit_"+habit+"_"+level, false);
        }
  });
});

显示页面调用 AJAX

<div class="strikes">
  <% if @habit.current_level_strike %> 
    <div class="btn" id="red"> <label id="<%= @habit.id %>" class="habit-id">Strikes:</label>
  <% else %> 
    <div class="btn" id="gold"> <label id="<%= @habit.id %>" class="habit-id-two">Strikes:</label>
  <% end %>
    <% @habit.levels.each_with_index do |level, index| %>
      <% if @habit.current_level >= (index + 1) %>
        <p>
          <% if @habit.current_level_strike %> 
            <label id="<%= level.id %>" class="level-id">Level <%= index + 1 %>:</label> 
          <% else %> 
            <label id="<%= level.id %>" class="level-id-two">Level <%= index + 1 %>:</label> 
          <% end %>
          <%= 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 %>
  </div>
</div>

这就是 AJAX 触发的目标,days_missed_controller.rb。

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
    if level.missed_days == 3
      level.missed_days = 0
      level.days_lost += habit.calculate_days_lost + 1
    end
    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

这是它的gist。请不要犹豫,要求进一步的代码或澄清:]

我在删除 turbolinks 时也遇到了这个问题,我认为这可能是问题所在,但事实并非如此。

【问题讨论】:

  • 点击复选框时是否触发页面加载?
  • 另外,尝试将page:change 更改为page:load
  • 您可以尝试为复选框设置唯一名称,这可能是某些浏览器在单击具有相同名称的复选框时会改变复选框的状态。
  • @fylooi 我都试过了,但都没有正常工作,并且在选中该框时没有触发页面加载,但 AJAX 确实触发了。
  • 哪些事件可以改变复选框的选中状态?似乎唯一应该能够这样做的是单击事件本身(您在上面注意到,“选中该框时不会触发页面加载”)。但是,如果复选标记状态如您所指示的那样不同步,则其他东西也必须改变其状态。我没有看到任何迹象表明复选标记状态正在基于更改回调或由于 AJAX 调用而更新。但我猜这是你问题的根源。

标签: javascript jquery ruby-on-rails ruby ajax


【解决方案1】:

好的,找到了这个讨厌的东西!

问题在于您生成的 HTML。事实证明,有问题的最终会执行 AJAX 调用...无效 URL(导致 404's)!

在您的显示视图中,您有如下代码:

<% if @habit.current_level_strike %> 
  <div class="btn" id="red"> <label id="<%= @habit.id %>" class="habit-id">Strikes:</label>
<% else %> 
  <div class="btn" id="gold"> <label id="<%= @habit.id %>" class="habit-id-two">Strikes:</label>
<% end %>

<!-- [...] -->

<% if @habit.current_level_strike %> 
  <label id="<%= level.id %>" class="level-id">Level <%= index + 1 %>:</label> 
<% else %> 
  <label id="<%= level.id %>" class="level-id-two">Level <%= index + 1 %>:</label> 
<% end %>

为什么会有问题?好吧,在你的 JavaScript 中,你依赖于 .habit-id 和 .level-id 的确切类:

habit = $(this).parent().siblings(".habit-id").first().attr("id");
level = $(this).siblings(".level-id").first().attr("id");

根据 show view 的 HTML,有时会生成正确的类,有时会生成带有 *-two 附录的类(habit-id-two 和 level-id-two)。

如果您尝试修复类名,那么所有类名都与您的 JavaScript 所期望的格式相同(.siblings(".habit-id") 和 .siblings(".level-id")),问题就会消失。

更好的解决方案(是的,可以稍微简化一下;))

如果我们预生成 url,然后像这样在 HTML 中设置它们:

<div class="strikes">
  <!-- [...] -->
    <% @habit.levels.each_with_index do |level, index| %>
      <% if @habit.current_level >= (index + 1) %>
        <p data-submit-url="<%= habit_level_days_missed_index_path({ habit_id: @habit.id, level_id: level.id }) %>"
           data-delete-url="<%= habit_level_days_missed_path({ habit_id: @habit.id, level_id: level.id, id: 1 }) %>">
          <!-- [...] -->
        </p>
      <% end %>
    <% end %>
  </div>
</div>

然后,您的 JavaScript 可以简化为:

$(document).on("page:change", function() {
  $(".habit-check").change(function()
  {
    var submitUrl = $(this).parents("p").data("submit-url");
    var deleteUrl = $(this).parents("p").data("delete-url");

    if($(this).is(":checked"))
    {
       $.ajax(
       {
         url: submitUrl,
         method: "POST"
       });
    }
    else
    {
       $.ajax(
       {
         url: deleteUrl,
         method: "DELETE"
       });
    }
  });
});

请注意,在生成 delete-url 时,我使用了id 的硬编码值,即1(试图重现您的原始行为),在:

data-delete-url="<%= habit_level_days_missed_path({ habit_id: @habit.id, level_id: level.id, id: 1 }) %>"

对应于:

url: "/habits/" + habit + "/levels/" + level + "/days_missed/1"

在您的代码中。你100%确定这是你想要的吗?

希望对您有所帮助!如果您有任何问题 - 我非常乐意提供帮助/解释!

祝你好运!

【讨论】:

  • 通过您更简单的解决方案,我们得到:ActionController::UrlGenerationError in Habits#show Showing /Users/galli01anthony/Desktop/Pecoce/app/views/habits/show.html.erb where line #30 raised: No route matches {:action=&gt;"create", :controller=&gt;"days_missed", :id=&gt;"5"} missing required keys: [:habit_id, :level_id]
  • 这太棒了。我已经为此苦苦挣扎了很久!我将如何使用 (.siblings(".habit-id") 和 .siblings(".level-id")) 来做不太简单的版本
  • 想快速聊天吗?
  • 大约 30 分钟就可以了?
  • 完美!在此期间我会继续玩:]
猜你喜欢
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
相关资源
最近更新 更多