Missed: % @habit.levels.each_with_index do |level, index| %> % if @habit.curren" name="description" /> Missed: % @habit.levels.each_with_index do |level, index| %> % if @habit.curren" />
53883

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

Question:

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/azhxK.png" data-original="https://i.stack.imgur.com/azhxK.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Then if those new boxes are checked another 3 checkboxes would show for that level.

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/St7X3.png" data-original="https://i.stack.imgur.com/St7X3.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

<strong>habits/_form.html.erb</strong>

<label id="<%= @habit.id %>" class="habit-id"> Missed: </label> <% @habit.levels.each_with_index do |level, index| %> <% if @habit.current_level >= (index + 1) %>

<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"} %>

<% end %> <% end %>

<strong>habit.js</strong>

$(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" }); } }); });

<strong>habit.rb</strong>

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

<strong>days_missed_controller</strong>

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: <a href="https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2" rel="nofollow">https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2</a>

<strong>Thank you!</strong>

Answer1:

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.

<strong>Example</strong>

<pre class="snippet-code-js lang-js prettyprint-override">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); } <pre class="snippet-code-html lang-html prettyprint-override"><div class="boxes"> <input type="checkbox"> <input type="checkbox"> <input type="checkbox"> </div>

<strong>EDIT</strong>

I've changed a couple of things in your original script

<ol><li>

Improved formatting

</li> <li>

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

</li> <li>

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

</li> <li>

Added the logic described above to your onchange event capture.

</li> <li>

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.

</li> </ol><pre class="lang-js prettyprint-override">$(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); });

Recommend