How to call 3 new checkboxes upon checking 3 old checkboxes?

谁说我不能喝 提交于 2020-02-08 09:45:06

问题


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!


回答1:


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

  1. Improved formatting

  2. Changed the way that you find the level-id and habit-id to reduce complexity.

  3. I've moved the on change function into a named handler function so that it can be applied to the new checkboxes.

  4. Added the logic described above to your onchange event capture.

  5. 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);
});


来源:https://stackoverflow.com/questions/30109624/how-to-call-3-new-checkboxes-upon-checking-3-old-checkboxes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!