How to use LocalStorage to make checkboxes persist? - javascript

How can we make the checkboxes persist for a user even when he reloads the page?
Please if you have the Javascript expertise can you help me with the relevant AJAX calls or give me some further guidance so I can pursue the answer on my own.
Every three boxes the user checks a new set of three boxes will show. How can we keep these AJAX induced boxes from disappearing?
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"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
} else {
$.ajax({
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
localStorage.setItem("habit_"+habit+"_"+level, true);
}
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
Here's the gist of it: https://gist.github.com/RallyWithGalli/c66dee6dfb9ab5d338c2
Please let me know if you need any further explanation, code, or pictures. Thank you so much for your time!

Looking at your code, shouldnt one of the setItem calls on localstorage set checkbox value to false
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);//<--- ? ?
}
i made a quick fiddle to show how you can pass objects into localStorage, and load them later.
When you first load the page, check if user has something saved, if so, skip ajax requests etc, and simply create the rows based on the info on localStorage.
http://jsfiddle.net/rainerpl/s39c9fws/18/
<div id="container">
<div class="row" id="row_1">
<span class="label">Row 1:</span>
<input type="checkbox" name="test" id="check_1" value="1" />
<input type="checkbox" name="test" id="check_2" value="1" />
<input type="checkbox" name="test" id="check_3" value="1" />
</div>
</div>
<input type="button" value="clear saved values" onclick="localStorage.setItem('checkbox_rows', false)"/>
<input type="button" value="add new row" onclick="addNewRow()"/>
var saveChecks = function() {
var rows = $(".row"), saveObj = [], alreadySavedRows = localStorage.getItem("checkbox_rows");
if ( alreadySavedRows ) {alreadySavedRows = JSON.parse(alreadySavedRows);}
console.log("saveChecks", rows.length);
if ( alreadySavedRows && alreadySavedRows.length ) {saveObj = alreadySavedRows;}
var replacePreviousRow = function(row_obj) {
var i;
for ( i = 0; i < saveObj.length; i++ ) {
if ( saveObj[i].row_id == row_obj.row_id ) {
// console.log("replaced previous", row_obj);
saveObj[i] = row_obj;return true;
}
}
return false;
}
$.each(rows, function( key, val ) {
var
checks = $(val).find("input[type='checkbox']"),
rowObj = {"row_id": $(val).attr("id"), "checkboxes": []};
;
rowObj.label = $(val).find(".label").text();
$.each(checks, function( key, check ) {
check= $(check);
rowObj.checkboxes.push({
check_id: check.attr("id"),
checked: check.prop('checked'),
value: check.attr("value")
});
});
// console.log("rowObj before", rowObj);
if ( !replacePreviousRow(rowObj ) ) { saveObj.push(rowObj);}
});
//console.log("saveObj", saveObj);
localStorage.setItem( "checkbox_rows", JSON.stringify(saveObj) );
}
var container = $("#container");
var loadChecks = function() {
var rows = localStorage.getItem("checkbox_rows"), i, j, row, check, rowElem, checkElem;
if ( !rows ) {return false;}
rows = JSON.parse(rows);
if ( !rows || !rows.length ) {return false;}
//console.log("rows:", rows);
for ( i = 0; i < rows.length; i++ ) {
row = rows[i];
//remove any previously existing rows
$("#" + row.row_id).remove();
rowElem = $("<div class='row'></div>");
rowElem.attr("id", row.row_id);
container.append(rowElem);
rowElem = $("#" + row.row_id );
rowElem.append("<span class='label'>"+row.label+"</span>");
for ( j = 0; j < row.checkboxes.length; j++ ) {
check = row.checkboxes[j];
checkElem = $("<input type='checkbox' name='test'/>");
checkElem.attr("id", check.check_id);
rowElem.append(checkElem);
checkElem = $("#" + check.check_id);
checkElem.attr("id", check.check_id);
checkElem.attr("value", check.value);
checkElem.prop("checked", check.checked);
}
}
}
window.addNewRow = function() {
var rowElem = $("<div class='row'></div>"), i, row_id, checkElem;
row_id = Math.round(1000*Math.random());
rowElem.attr("id", "row_" + row_id );
rowElem.append("<span class='label'>Row id:" + row_id +"</span>");
for (i = 0; i < Math.ceil( Math.random() * 10 ); i++ ) {
checkElem = $("<input type='checkbox' name='test' />");
checkElem.attr("id", "check_" + row_id + "_" + i );
checkElem.val(i);
rowElem.append(checkElem);
}
container.append(rowElem);
setTimeout(saveChecks, 100);
}
$().ready(function() {
console.log("ready");
setTimeout( loadChecks, 30);
$("body").on("click", ".row", function(evt) {
var row = $(evt.currentTarget), notChecked = row.find("input:not(:checked)").length, id;
console.log("evt",notChecked);
if ( !notChecked ) {
id = Math.ceil( 1000 * Math.random() );
row.append("<input type='checkbox' name='test' id='check_"+id+"' value='1' />");
}
saveChecks();
});
});

Related

What is making my page content load and suddenly disappear?

I'm adjusting a form in a website that has several parts. The goal is when we load the page, the initial input appears and the other inputs just appear after the one before has an adequate value.
On the first page everything seems ok (I added a few more inputs to the original), when I pass on to the second page the first input seems to appear and suddenly disappear, not allowing the user to fill out the value and thus leaving the page blank.
I can't understand what's making the loading problem. Below is the code.
passo3.ejs
<div class="row">
<div class="col-sm-12">
<div class="jumbotron">
<!-- <h1><%= __('calculadora.title') %></h1> -->
<h2><%= __('calculadora.subtitle_3_revestimentos') %></h2>
</div>
</div>
<div class="alert alert-dark" style="display:none;"></div>
<div class="alert alert-info" style="display:none;"></div>
<div class="alert alert-warning" style="display:none;"></div>
<div class="alert alert-danger" style="display:none;"></div>
<div class="progress">
<div class="progress-bar progress-bar-dark" role="progressbar" aria-valuenow="4" aria-valuemin="0" aria-valuemax="100" style="width: <%= progressBar %>%"></div>
</div>
<div class="form-group col-sm-12 form-inline"></div>
<div class="form-group col-sm-1 form-inline col-margin"></div>
<div class="form-group col-sm-5 form-inline form-option-div">
<!-- image depends on option in step 1-->
<div class="btn-image-div-absolute d-flex align-items-end">
<img src="/img/calculadora_p3/fachada_<%= lang %>.png" class="btn-image-absolute rounded mx-auto image_overlay image_base">
<img src="/img/calculadora_p3/fachada_ac.png" class="btn-image-absolute rounded mx-auto image_overlay ac" style="display:none;">
<img src="/img/calculadora_p3/fachada_af.png" class="btn-image-absolute rounded mx-auto image_overlay af" style="display:none;">
</div>
</div>
<div class="form-group col-sm-5 form-option-div">
<h3 class="form-subtitle"><%= __('calculadora.cobertura') %></h3>
<!-- 10 -->
<% var _Q = {
tabindex: 1,
number: "10",
name: "rev_tipo",
hiddenOnStart: false,
errorInput: false,
additionalClasses: "form-control",
units: ""
}; %>
<% include ./_question_typeB.ejs %>
<!-- 10A -->
<% _Q = {
tabindex: 2,
number: "10A",
name: "rev_outro",
hiddenOnStart: true,
errorInput: true,
additionalClasses: "valid_number",
units: "[kg/m<sup>2</sup>]"
}; %>
<% include ./_question_typeA.ejs %>
<!-- 11 -->
<% _Q = {
tabindex: 3,
number: "11",
name: "afmc",
hiddenOnStart: true,
errorInput: true,
additionalClasses: "valid_selectize_number",
units: "a<sub>c</sub> [m]"
}; %>
<% include ./_question_typeB.ejs %>
<div class="part2" style="display:none;">
<h3 class="form-subtitle"><%= __('calculadora.fachada') %></h3>
<!-- [9] 12 (20) -->
<% _Q = {
tabindex: 4,
number: "12",
name: "ori_rev_fachada",
hiddenOnStart: false,
errorInput: false,
additionalClasses: "form-control",
units: ""
}; %>
<% include ./_question_typeB.ejs %>
<!-- [10] 9 (31) -->
<% _Q = {
tabindex: 5,
number: "13",
name: "n_fachadas_abertas",
hiddenOnStart: true,
errorInput: false,
additionalClasses: "form-control",
units: ""
}; %>
<% include ./_question_typeB.ejs %>
<!-- [11] 10 (32) -->
<% _Q = {
tabindex: 6,
number: "14",
name: "n_empenas_abertas",
hiddenOnStart: true,
errorInput: false,
additionalClasses: "form-control",
units: ""
}; %>
<% include ./_question_typeB.ejs %>
<!-- [12] 11 (9) -->
<% _Q = {
tabindex: 7,
number: "15",
name: "rev_fachada",
hiddenOnStart: true,
errorInput: false,
additionalClasses: "form-control",
units: ""
}; %>
<% include ./_question_typeB.ejs %>
<!-- 13 (10) -->
<% _Q = {
tabindex: 8,
number: "16",
name: "afmf",
hiddenOnStart: true,
errorInput: true,
additionalClasses: "valid_selectize_number",
units: "a<sub>f</sub> [m]"
}; %>
<% include ./_question_typeB.ejs %>
</div> <!-- part 2 -->
<div class="btn_submit_div" style="display:none;">
<button tabindex="10" type="button" class="btn_submit btn btn-dark btn-md"><%= __('calculadora.seguinte') %></button>
</div>
</div><!-- form group -->
</div><!-- row -->
<div style="height: 70px; width:100%">
</div>
<input type="hidden" name="step" value="<%= step %>">
<input type="hidden" name="arq" value="<%= calcData.arq %>">
<input type="hidden" name="vao" value="<%= calcData.vao %>">
<input type="hidden" name="h1" value="<%= calcData.h1 %>">
<input type="hidden" name="hc" value="<%= calcData.hc %>">
<div class="calculadora_inputs">
<% if( typeof report != "undefined" ){ %>
<form id="form_calculadora" name="form_calculadora" action="/calculadora" method="GET">
<input id="reportId" type="hidden" class="" name="reportId" value="<%= report._id %>">
<input id="nextStep" type="hidden" class="" name="nextStep" value="<%= +report.step +1 %>">
<% } %>
<input type="hidden" name="v" value="<%= calcData.v %>"><!-- calculated on server with step 2 inputs, needs to be here to be included in query string inputs -->
<input type="hidden" class="sync_rev_tipo required" name="rev_tipo">
<input type="hidden" class="sync_rev_outro required" name="rev_outro">
<input type="hidden" class="sync_afmc required" name="afmc">
<input type="hidden" class="sync_n_fachadas_abertas required" name="n_fachadas_abertas">
<input type="hidden" class="sync_n_empenas_abertas required" name="n_empenas_abertas">
<input type="hidden" class="sync_rev_fachada required" name="rev_fachada">
<input type="hidden" class="sync_ori_rev_fachada required" name="ori_rev_fachada">
<input type="hidden" class="sync_afmf required" name="afmf">
<% if( typeof report != "undefined" ){ %>
</form>
<% } %>
</div>
</div>
<script>resetCalculatorText = "<%= __('resetCalculatorText') %>";</script>
<script src="/js/calculadora_passo<%= step %>.js"></script>
_question_typeB.ejs
<%
var _visible = '', _errorPop = '', _errorPopClass='', _additionalClasses='', _selectOptions=[];
if( _Q.hiddenOnStart ) {
_visible=`style="display:none"`;
}
if( _Q.errorInput ){
let _content = __(`calculadora.q${_Q.number}.errorText`);
_errorPop=`data-toggle="popover" data-trigger="manual" data-placement="left" data-content="${_content}" data-html="true" data-container=".calculator-input-group.step${_Q.number}"`;
_errorPopClass = 'error-popover';
}
if( _Q.additionalClasses ){
_additionalClasses = _Q.additionalClasses;
}
if( __(`calculadora.q${_Q.number}.selectOptions`) ){
_selectOptions = __(`calculadora.q${_Q.number}.selectOptions`);
}
%>
<h4 class="input_label step<%= _Q.number %>" <%- _visible %>><%= __(`calculadora.q${_Q.number}.inputLabel`) %></h4>
<div class="input-group calculator-input-group step<%= _Q.number %>" <%- _visible %>>
<% console.log(_Q.units) %>
<% if( _Q.units ){ %>
<a class="<%= _errorPopClass %>"" <%- _errorPop %> >
<div class="input-group-prepend">
<span class="input-group-text calculator-input-prepend"><%- _Q.units %></span>
</div>
</a>
<% } %>
<select data-tab="<%= _Q.tabindex %>" class="sync_<%= _Q.name %> middle calculator-input <%= _errorPopClass %> <%- _additionalClasses %>" placeholder="<%= __(`calculadora.q${_Q.number}.inputPlaceholder`) %>" title="<%= __(`calculadora.q${_Q.number}.inputTitle`) %>" aria-label="<%= __(`calculadora.q${_Q.number}.inputTitle`) %>">
<% console.log(_selectOptions.length) %>
<% if( _selectOptions.length ){ %>
<option selected disabled><%- __(`calculadora.escolhaUmaOpcao`) %></option>
<% _selectOptions.forEach(function( eachOption){ %>
<option value="<%= eachOption.val %>"><%- eachOption.title %></option>
<% }) %>
<% } %>
</select>
<div class="input-group-append">
<span class="input-group-text calculator-input-append">
<a tabindex="99" class="btn btn-sm btn-link btn-block" data-html="true" data-toggle="popover" data-container="body" data-placement="left" title="<%= __(`calculadora.q${_Q.number}.helperTitle`) %>" data-content="<%= __(`calculadora.q${_Q.number}.helperContent`) %>"><i class="far fa-question-circle fa-lg"></i></a>
</span>
</div>
</div>
calculadora_passo3.js
//store the instance of the selectize components
var $selectize_8;
var selectizeControl_8;
var $selectize_13;
var selectizeControl_13;
$(document).ready(function() {
//initialization
function _init(){
//add a property to help icon on Afmc so it can be added dynamicaly to help popover when clicked
//after this add the event to the help button to get the aria-described with the id of the popover and manipulate the content
//replacing ${1} by data-par1 value. Because this can be used anywhere i'm adding this event to main calculadoraFrontEnd.js file
let afmc = (+$('[name="v"]').val() ).toFixed(2);
let afmf = +$('[name="h1"]').val()-0.5;
console.log(afmc);
console.log(afmf);
$('.step11 .input-group-append .btn-link').attr('data-par1', afmc );
//same for afmf on step 16
$('.step16 .input-group-append .btn-link').attr('data-par1', afmf );
scrollTo($('header'));
}
//populate select box
function populateSelect_8(){
//destroy select if already exists
if( selectizeControl_8){
selectizeControl_8.destroy();
}
//initiate the selectize component and store it's instance
$selectize_8 = $('select.sync_afmc').selectize( {
options: calcularAfastamentoMadreCobertura(),
valueField: 'val',
labelField: 'title',
searchField: 'title',
sortField: function(item1, item2) {
return item1.value - item2.value;
},
createOnBlur: true,
create: true,
openOnFocus: true,
onChange: function(input){
//prevent clear method (input becomes null) to trigger "not a number" again
if(!input) return;
let length_v = $('[name="v"]').val();//calcularComprimentoViga();
//ignore +2 place decimals
let ratio = Math.round((length_v / input)*100)/100;
//check if the input exists in the original options calculation function
let originalOptions = calcularAfastamentoMadreCobertura();
let originalOption = false;
if (originalOptions.filter(function(option) { return option.val === input; }).length > 0) {
originalOption= true;
}
if( !$.isNumeric(input) || (Math.floor(ratio) != ratio && !originalOption ) ) {
//showMessage("Error - Not valid number", "alert-danger");
showMessage( $(this.$wrapper[0]) );
//clear last added value
selectizeControl_8.clear();
//remove last added value from list
selectizeControl_8.removeOption(input);
//reopen dropdown
selectizeControl_8.open();
}else{
//clear error message
clearMessage( $(this.$wrapper[0]) );
}
},
onInitialize: function(){
$(this.$wrapper[0]).find(":input").attr('tabindex', $(this.$wrapper[0]).parent().find('.selectized').data('tab') ) ;
},
onFocus: function(){
showOnlyTheRightImage("ac");
},
render: {
item: function(item, escape) {
return '<div>' +
(item.title ? '<span class="selectize_title">' + escape(item.title) + '</span>' : '') +
'</div>';
},
option: function(item, escape) {
return '<div>' +
'<span class="selectize_title"><strong>' + (item.title ? escape(item.title) : escape(item.val)) + '</strong>' +
(item.subtitle ? '<span class="selectize_subtitle"> ' + escape(item.subtitle) + '</span>' : '') + '</span>'
'</div>';
},
}
});//options
//store object instnace so we can handle events
selectizeControl_8 = $selectize_8[0].selectize;
}//function
//populate select box
function populateSelect_13(){
let af_array = [];
//destroy select if already exists
if( selectizeControl_13){
selectizeControl_13.destroy();
}
//initiate the selectize component and store it's instance
$selectize_13 = $('select.sync_afmf').selectize( {
options: calcularAfastamentoMadresFachada(),
valueField: 'val',
labelField: 'title',
searchField: 'title',
sortField: function(item1, item2) {
return item1.value - item2.value;
},
createOnBlur: true,
create: true,
openOnFocus: true,
onChange: function(input){
//prevent clear method (input becomes null) to trigger "not a number" again
if(!input) return
//h from form inputs
let length_h = parseFloat( $('[name="h1"]').val() );
//ignore +2 place decimals
let ratio = Math.round((length_h / input)*100)/100;
//check if the input exists in the original options calculation function
let originalOptions = calcularAfastamentoMadresFachada();
let originalOption = false;
if (originalOptions.filter(function(option) { return option.val === input; }).length > 0) {
originalOption= true;
}
if( !$.isNumeric(input) || (Math.floor(ratio) != ratio && !originalOption ) ) {
showMessage( $(this.$wrapper[0]) );
//clear last added value
selectizeControl_13.clear();
//remove last added value from list
selectizeControl_13.removeOption(input);
//reopen dropdown
selectizeControl_13.open();
}else{
//clear error message
clearMessage( $(this.$wrapper[0]) );
}
},
onInitialize: function(){
$(this.$wrapper[0]).find(":input").attr('tabindex', $(this.$wrapper[0]).parent().find('.selectized').data('tab') ) ;
},
onFocus: function(){
showOnlyTheRightImage("af");
},
render: {
item: function(item, escape) {
return '<div>' +
(item.title ? '<span class="selectize_title">' + escape(item.title) + '</span>' : '') +
'</div>';
},
option: function(item, escape) {
return '<div>' +
'<span class="selectize_title"><strong>' + (item.title ? escape(item.title) : escape(item.val)) + '</strong>' +
(item.subtitle ? '<span class="selectize_subtitle"> ' + escape(item.subtitle) + '</span>' : '') + '</span>'
'</div>';
},
}
});//options
//store object instnace so we can handle events
selectizeControl_13 = $selectize_13[0].selectize;
}//function
//allow only numbers and decimal point
$('.group_option_inputs_div').keypress('div.valid_selectize_number', function(e) {
//only allow number and dot characters
if ( (e.which < 48 || e.which > 57) && e.which !== 46) {
e.preventDefault();
}
//dont allow paste
}).on('paste', function(e) {
e.preventDefault();
});
$('.calculator-input').on('focus', function(){
//hide all except base image
$('.image_overlay').not('.image_base').hide();
});
//FLOW -------------------------------------------------------
// Step 10 only to show 10A
$('[name="rev_tipo"]').on('input', function(){
//if valid activate next input
if( $(this).val() == '6' ){
$('.step10A').show();
}else{
$('.step10A').hide();
//also clear rev_outro input (only for option 6 - outro)
$('.sync_rev_outro').val('').trigger("change");
}
});
// Step 10, 10A
$('[name="rev_tipo"], [name="rev_outro"]').on('input', function(){
let tipo = $('[name="rev_tipo"]').val();
let outro = $('[name="rev_outro"]').val();
let valid = true;
//nothing selected or "other" without specifing what "other" is
if( tipo == '' || (tipo == '6' && outro == '') ){
valid = false;
}
//if valid activate next input
if( !valid ){
$('.step10, .step11, .step12, .step13, .step14, .step15, .step16').hide();
$('.btn_submit_div').hide();
}else{
$('.step10').show().trigger("input");
populateSelect_8();
//scrollTo( $('.step8') );
}
});
// step 8
$('[name="afmc"]').on('input', function(){
if($(this).val() == ''){
$('.step11, .step12, .step13, .step14, .step15, .step16').hide();
$('.btn_submit_div').hide();
}else{
//show parte 2 of form
$('.part2').show();
$('.step11').show().trigger("input");
//scrollTo( $('.step9') );
}
});
// step [9] 12 (10)
$('[name="ori_rev_fachada"]').on('input', function(){
$('.step12, .step13, .step14, .step15, .step16').hide();
$('.btn_submit_div').hide();
if( $(this).val() != ''){
if( $(this).val() == '0' || $(this).val() == '1' ){
$('.step12').show().trigger("input");
}else{
$('.sync_rev_fachada').val('');
$('.sync_n_empenas_abertas').val('');
$('.sync_n_fachadas_abertas').val('');
//also clear afmf input (only for option 0 - vertical)
$('.sync_afmf').val('');
$('.btn_submit_div').show();
//scrollTo( $('.btn_submit_div') );
}
}
});
// step [10] 9 (31)
$('[name="n_fachadas_abertas"]').on('input', function(){
$('.step13, .step14, .step15, .step16').hide();
$('.btn_submit_div').hide();
if($(this).val() != ''){
$('.step13').show().trigger("input");
//scrollTo( $('.step10') );
}
});
// step [11] 10 (32)
$('[name="n_empenas_abertas"]').on('input', function(){
$('.step14, .step15, .step16').hide();
$('.btn_submit_div').hide();
if( $(this).val() != ''){
$('.step14').show().trigger("input");
}
});
// step [12] 11 (9)
$('[name="rev_fachada"]').on('input', function(){
if( $(this).val() == ''){
$('.step15, .step16').hide();
$('.btn_submit_div').hide();
}else{
//if orientação do revestimento = horizontal, afmf will not be required
if( $('.sync_ori_rev_fachada').val() == '1' ){
$('.sync_afmf').val('');
$('.step15').hide();
$('.btn_submit_div').show();
//scrollTo( $('.btn_submit_div') );
}else{
populateSelect_13();
$('.step15').show().trigger("input");
$('.btn_submit_div').hide();
}
//scrollTo( $('.step12') );
}
});
// step 13 (10)
$('[name="afmf"]').on('input', function(){
if( $(this).val() == ''){
$('.btn_submit_div').hide();
}else{
$('.btn_submit_div').show();
//scrollTo( $('.btn_submit_div') );
}
});
//------------------------------------------------------------
function calcularAfastamentoMadreCobertura(){
let rev = $('[name="rev_tipo"]').val(); //defined in this form
let arq = $('[name="arq"]').val();
let vao = $('[name="vao"]').val();
let h = $('[name="h"]').val();
let hc = $('[name="hc"]').val();
let ret = [];
let A = 1.0; //caso para arq = 2 e 3
let B = 3.0; //caso o revestimento da cobertura seja qq tipo de sandwich
if(arq == "1"){
A = 0.5;
}else if(arq == "4"){
A = 2.0;
}
if(rev == "0"){//Chapa Simples - Bac Acier
B = 2.0;
}else if(rev == "1" || rev == "6" ){//fotovoltaico e outro
B = 1.6;
}
//suggest more values
let variation = [0, 1, 2];
//this will be the suggested options available to the user in the select box
let suggested = [];
//calculate options and add them to suggested array
for(let i=0; i<variation.length; i++){
let distanciaViga = Math.sqrt( (vao * A)**2 + (hc - h)**2 ) - 0.5;
let afmc = distanciaViga / ( Math.ceil( (distanciaViga / B) + variation[i] ) );
let result = parseFloat( afmc ).toFixed(2);
suggested.push({val:result, title:result });
}
return suggested;
}
function calcularAfastamentoMadresFachada(){
//tipo de revestimento da fachada ( 0=chapa simples, 1=painael sandwich, 2=outro)
let rev_fachada = $('[name="rev_fachada"]').val();
//altura dos pilares
let h = $('[name="h"]').val();
//look for values close to this (don't know why this specifically)
let ret = [];
let constant = 3; //other cases then "chapa simples"
if( rev_fachada === '0') constant = 2;
let calc = parseFloat( (h - 0.5) / Math.ceil( (h - 0.5)/constant ) ).toFixed(2);
ret.push({val:calc , title:calc})
return ret;
}
//hide all overlay images except the one with the specific class to the question on focus
function showOnlyTheRightImage(specificClass){
$('.image_overlay').not('.image_base').hide();
$('.image_overlay.'+specificClass).show();
}
//initialize stuff
setTimeout(function() {
_init();
}, 10);//only enough for this to be last
});//document ready
Thanks for your help

Rails: Show and hide a div

I have a rails app and I'm looping through some db values:
<ul>
<% #categories.each do |category| %>
<li onclick="showHide(event)"> <%= category.name %>
<% unless category.children.empty? %>
<ul class="categories" style="display:none;">
<% category.children.each do |subcategory| %>
<li><%= link_to "#{subcategory.name}", search_path(:search => subcategory.id) %></li>
<% end %>
</ul>
<% end %>
</li>
<% end %>
</ul>
And with the following javascript I'm able to show and hide the div when I click on it:
function showHide(e) {
var categoryList = e.currentTarget.querySelector(".categories");
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
This does work, but I need to implement two more things to this.
1. When I click on one category and another one is open, I want to close the other one.
2. Even after I refresh the page, I want to figure out a way to remember the last target(the last div that was open).
Any ideas on how to implement both of the above?
Update 1
Ok I followed #Panomosh advise I got the first one to work. And on the second one when the cookie doesn't exist I create it and then it gives me this error in the browser console:
TypeError: undefined is not an object (evaluating 'categoryList.currentTarget.querySelector')
Any ideas why?
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function showHide(e) {
var divsToHide = document.getElementsByClassName("categories");
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.display = "none"; // depending on what you're doing
}
var myCookie = getCookie(".Cl");
if (myCookie == null) {
var categoryList = e.currentTarget.querySelector(".categories");
setCookie(".Cl", categoryList)
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
else {
var categoryList = getCookie(".Cl");
categoryList.currentTarget.querySelector(".categories");
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
}
function setCookie(c_name, value) {
var now = new Date();
var time = now.getTime();
time += 300 * 1000;
now.setTime(time);
var c_value = escape(value) + ((time == null) ? "" : "; expires=" + now.toUTCString());
document.cookie = c_name + "=" + c_value;
}

Javascript drop down menu and validate calendar picker

Ok I have a drop down menu that is dynamically generated by .jsp and populated with data fetched from database.2 dropdown list and 2 datepicker
The problem that I am having is with a JS validation, am not so good with JavaScript but for the purposes of my mini project I have to work with it anyway....
The problem is that with JS I am checking if a user has selected two drop-down fields and two date pickers so the form can be submitted and the list of the searching should be shows below the button else display a warning message indicating that the drop-downs and date pickers have not been filled.
Where should I do the validation of those 4 fields? How to use the'EXECUTE' to call the class from 'SelectOperation.java'(as per attached).
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.hibernate.Session;
import entityBeans.AccessLevel;
import entityBeans.Business;
import entityBeans.CustomerBranch;
import entityBeans.Menu;
import entityBeans.TransactionLog;
import entityBeans.User;
import cmnUtilities.CmnConstants;
public class SelectOperation {
Session session = ConnectionMySQL.getInstance().getConnection();
private static SelectOperation selectData = new SelectOperation();
private SelectOperation()
{
}
public User Select_login_User(String user_id)
{
User loginUser = null;
try
{
loginUser = (User)session.get(User.class,user_id.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return loginUser;
}
public User Chech_User_existence(String user_id)
{
User CheckUser = null;
try
{
CheckUser = (User)session.get(User.class,user_id.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return CheckUser;
}
public List<List<Menu>> Select_User_Menu(int Access_id)
{
List<Menu> UserMenu = null;
List<List<Menu>> Menus = new ArrayList<List<Menu>>();
AccessLevel acl = null ;
try
{
if(session.isOpen())
{
// acl = (AccessLevel)session.get(AccessLevel.class,Access_id.trim());
// StringBuffer AccessLevel = formatedMenuIds(acl.getMenuId());
// System.out.println(AccessLevel);
//UserMenu = (List<Menu>)session.createQuery("from Menu where menuId in ("+menuIds+")").list();
UserMenu = (List<Menu>)session.createQuery("from Menu where menuAccLevel >='"+Access_id+"'").list();
List<Menu> MainModule = new ArrayList<Menu>();
List<Menu> SubModule = new ArrayList<Menu>();
for(Menu seperateMenu : UserMenu)
{
if((seperateMenu.getMenuId().length()) == CmnConstants.MAIN_MENU)
{
MainModule.add(seperateMenu);
}
if((seperateMenu.getMenuId().length()) == CmnConstants.SUB_MENU)
{
SubModule.add(seperateMenu);
}
}
for(Menu disp1 : MainModule)
{
List<Menu> finaly = new ArrayList<Menu>();
finaly.add(disp1);
for(Menu disp2 : SubModule)
{
if(disp2.getMenuId().startsWith(disp1.getMenuId()))
{
finaly.add(disp2);
}
}
Menus.add(finaly);
}
System.out.println(Menus);
}
else
{
System.out.println("session closed");
}
}
catch(Exception exception)
{
exception.printStackTrace();
}
return Menus;
}
//METHOD RETURNS ALL ACCESS LEVEL CODE AND IT'S DESCRIPTION
public List<AccessLevel> getAllAccessLevel()
{
List<AccessLevel> accessList = null;
try
{
accessList = (List<AccessLevel>)session.createQuery("from AccessLevel").list();
System.out.println(accessList);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return accessList;
}
//METHOD TO SELECT ALL BRANCH IDS
public List<CustomerBranch> getAllCustomerBranch()
{
List<CustomerBranch> branchList = null;
try
{
branchList = (List<CustomerBranch>)session.createQuery("from CustomerBranch").list();
System.out.println(branchList);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return branchList;
}
//METHOD TO SELECT ALL TRANSACTION_LOG DETAILS
public List<TransactionLog> getAllTransactionLog()
{
List<TransactionLog> TxnList = null;
try
{
TxnList = (List<TransactionLog>)session.createQuery("from TransactionLog").list();
System.out.println(TxnList);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return TxnList;
}
//METHOD TO SELECT ALL BUSINESS
public List<Business> getAllBusiness()
{
List<Business> BusinessList = null;
try
{
BusinessList = (List<Business>)session.createQuery("from Business").list();
System.out.println(BusinessList);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return BusinessList;
}
public Business SelectBusiness_Id(String business_id)
{
Business CheckBusiness_id = null;
try
{
CheckBusiness_id = (Business)session.get(Business.class,business_id.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return CheckBusiness_id;
}
public CustomerBranch SelectBranch_Id(String branch_id)
{
CustomerBranch CheckBranch_id = null;
try
{
CheckBranch_id = (CustomerBranch)session.get(CustomerBranch.class,branch_id.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return CheckBranch_id;
}
public TransactionLog FromDateSel(String txn_date)
{
TransactionLog transDateFrom = null;
try
{
transDateFrom = (TransactionLog)session.get(TransactionLog.class,txn_date.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return transDateFrom;
}
public TransactionLog ToDateSel(String txn_date)
{
TransactionLog transDateTo = null;
try
{
transDateTo = (TransactionLog)session.get(TransactionLog.class,txn_date.trim());
}
catch(Exception exception)
{
exception.printStackTrace();
}
return transDateTo;
}
// Will returns all menu ids
/*public StringBuffer formatedMenuIds(String text)
{
String[] val = text.split(",");
StringBuffer sb = new StringBuffer();
for(String cc :val)
{
sb.append("'"+cc+"'"+",");
}
if(sb.toString().endsWith(","))
{
sb.delete(sb.length()-1, sb.length());
}
return sb;
}*/
public static SelectOperation getInstance()
{
return selectData;
}
}
I think i just need so more javascript to do this i just dont know how. Thanks for your help in advance.
<% #page import = "allDatabaseOperations.SelectOperation" %>
<% #page import = "java.util.List" %>
<% #page import = "entityBeans.TransactionLog" %>
<% #page import = "entityBeans.Business" %>
<% #page import = "entityBeans.CustomerBranch" %>
<% #page language = "java"
contentType = "text/html; charset=ISO-8859-1"
pageEncoding = "ISO-8859-1" %>
< !DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< link rel = "stylesheet"
href = "../styles/style.css"
type = "text/css" / >
<%
List < TransactionLog > Allbranches = SelectOperation.getInstance().getAllTransactionLog();
List < Business > Businesslevel = SelectOperation.getInstance().getAllBusiness();
List < CustomerBranch > CustBranch = SelectOperation.getInstance().getAllCustomerBranch(); %>
< link rel = "stylesheet"
href = "//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" >
< script src = "//code.jquery.com/jquery-1.10.2.js" > < /script>
<script src="/ / code.jquery.com / ui / 1.11.4 / jquery - ui.js "></script>
<link rel="
stylesheet " href=" / WebContent / styles / style.css ">
<script>
$(function() {
$( "#
fromdate " ).datepicker({
showOn: "
button ",
buttonImage: ".. / .. / images / calendar.png ",
buttonImageOnly: true,
buttonText: "
Select date "
});
});
$(function() {
$( "#
todate " ).datepicker({
showOn: "
button ",
buttonImage: ".. / .. / images / calendar.png ",
buttonImageOnly: true,
buttonText: "
Select date "
});
});
</script>
</head>
<body>
<form>
<table align="
center " style="
background - color: #F5D0A9;
padding: 70px;
border - top: 1px;
">
<tr>
<%-- added by Maihani on 181115(Wed) --%>
<td>
Business Id :-
</td>
<%--<td> <input type="
text " name="
BusinessId " size = "
46 "/> --%>
<td> <select name="
Business ">
<%for(Business business : Businesslevel) {%>
<option value=" <%= business.getBusinessId() %> "><%=business.getBusinessName()%></option>
<%}
%>
</select><%-- </td>--%>
</td>
</tr>
<td>
Branch Id :
</td>
<td>
<select name="
CustomerBranch ">
<%for(CustomerBranch custBranch : CustBranch) {%>
<option value=" <%= custBranch.getBranchId() %> "><%=custBranch.getBranchName()%></option>
<%}
%>
</select>
</td>
</tr>
<tr>
<td>
From Date :
</td>
<td>
<%-- <input type="
text " name="
BrachId " size = "
46 "/> --%>
<input type="
text " id="
fromdate ">
</td>
</tr>
<tr>
<td>
To Date :
</td>
<td>
<%--<input type="
text " name="
BrachId " size = "
46 "/> --%>
<input type="
text " id="
todate ">
</td>
</tr>
<tr>
<td>
</td>
<td align="
center "><input type="
submit " value="
Search Transaction "/></td>
</tr>
<tr >
<td colspan="
2 ">
<table align="
center ">
<tr bgcolor="
#333333">
<td><font color= "#FFFFFF" > User ID < /font></td >
< td > < font color = "#FFFFFF" > Branch ID < /font></td >
< td > < font color = "#FFFFFF" > Transaction Code < /font></td >
< td > < font color = "#FFFFFF" > Transaction Date < /font></td >
< td > < font color = "#FFFFFF" > Transaction Time < /font></td >
< /tr>
<%for(TransactionLog txn : Allbranches){%>
<tr bgcolor="#F2F2F2">
<td><%=txn.getUserId()%></td >
< td > <%= txn.getBranchId() %> < /td>
<td><%=txn.getTxnCode() %></td >
< td > <%= txn.getTxnDate() %> < /td>
<td><%=txn.getTxnTime() %></td >
< /tr>
<%} %>
</table >
< /td>
<td></td >
< /tr>
</table >
< /form>
</body >
< /html>
On the submit button, you can call a JavaScript function that in turn validates the values of your 4 input types and based on the validation result, you can continue with the form submit or show error message
<input type="submit" onclick="validateForm()" value="Search Transaction" />
<script>
function validateForm(){
var ip1 = $("#firstdropdownId").val();
var ip2 = $("#otherdropdownId").val();
var date1 = $("#firstdateId").val();
var date2 = $("#otherdateId").val();
if(ip1 == null || ip1.length.trim() == 0 || ip2 == null || ip2.length.trim() == 0 || idt1 == null || dt1.length.trim() == 0 || dt2 == null || dt2.length.trim() == 0){
$("#errorMessageDiv").show();
return false;
}
else{
$("#errorMessageDiv").hide();
return true;
}
}
</script>
Or if you want to validate from java end, you can make an ajax call by passing the parameters as the input values, which will return the validate status of your form.

Why does my form not submit what I want it to?

I'm trying to submit a javscript generated value.
The script is:
var save = function () {
var left = document.getElementById("left"); //Get a select box
var result = document.exchange; //get the form
result.value = ""; //set it's value to ""
for (i = 0; i < right.length; i++) {
result.value = result.value + "," + left.options[i].value; //set it's value to the values of the select box, divided by commas.
}
result.submit(); //submit the form
}
But my form only submits this:
{
"utf8" = > "✓",
"authenticity_token" = > "9gf3upm65ugEhsNvdcaykjdlg7xZbOyTiWJs79SnY3A=",
"timespan_id" = > {
"name" = > ["",
""]
},
"subgroup_id" = > "369141985"
}
The form is generated by my Rails. It looks like this:
<%= form_tag(subgroup_change_timespans_path(#subgroup), {
id: 'exchange',
name: 'exchange'
}) do %> <% timespans_array = #subgroup.timespans.all.map { | timespan | [timespan.name, timespan.id]
} %> <%= select(: timespan_id, : name, options_for_select(timespans_array), {}, {: multiple = > true,
: style = > "width: 300px; background-color: #9FE",
: width = > "300",
: size = > 20,
: id = > "left"
}) %> <%= link_to "<<", {
anchor: "",
remote: true
}, {
id: "toleft",
w_command: "add_timespan",
w_auth: form_authenticity_token,
w_controller: "subgroups",
w_id: #subgroup.id.to_s
} %> <%= link_to ">>", {
anchor: "",
remote: true
}, {
id: "toright",
w_command: "rem_timespan",
w_auth: form_authenticity_token,
w_controller: "subgroups",
w_id: #subgroup.id.to_s
} %> <% timespans_array = Timespan.all.map { | timespan | [timespan.name, timespan.id]
} %> <%= select(: timespan_id, : name, options_for_select(timespans_array), {}, {: multiple = > true,
: style = > "width: 300px; background-color: #F99",
: width = > "300",
: size = > 20,
: id = > "right"
}) %> <%= link_to "save", {
anchor: "",
remote: true
}, {
id: "save"
} %> <% end %>
But as I told you:
It just submits the names of two hidden fields:
<input name="timespan_id[name][]" type="hidden" value="" />
<input name="timespan_id[name][]" type="hidden" value="" />
I think, there is something wrong with these two. But I don't get what.
Do you have any Ideas?
#Малъ Скрылевъ: It has to be this way.
The form should look like this:
I found a Solution for my Problem:
I had to put the select boxes outside of the form, which removed the this parameter:
"timespan_id" = > {
"name" = > ["",
""]
Then I added a hidden_field_tag called 'string' inside the form.
Then at last, I changed my save function to:
var save=function()
{
var left = document.getElementById("left");
var result;
result="";
for(i=0;i<left.length;i++)
{
result = result+","+left.options[i].value;
}
var string=document.getElementById("string");
alert(result);
string.value=result;
document.exchange.submit();
}

Backbone pagination 10 at a time

Im building an pagination in backbone. The problem is that the amount of pages has grown and are now that many that it ruins the layout of the site. So i want to implement a functionality where i can render lets say the first 10 pages and then with a next/prev button control which page numbers should be shown. But always only show 10 pages like so:
< 1 2 3 4 5 6 7 8 9 10 >
< 2 3 4 5 6 7 8 9 10 11 >
So now i append this to my pagination (its all pages)
updateTotal: function () {
var self = this;
self.totalModel.fetch({
success:function(model,response) {
var total = response.data; //all iems
var p = total/self.perPage;
var r = total-Math.round(p)
self.pagination = _.template($("#pagination_template").html(), {
pages:Math.ceil(p)
});
self.render();
}
});
},
This is how i print it out in html (underscore.js)
<script type="text/template" id="pagination_template">
<section class="pagination">
<ul>
<% for (var i = 0; i < pages; i++) { %>
<li>
<a href="#" data-offset="<%= i*9 %>" data-page="<%= i+1 %>">
<%= i+1 %>
</a>
</li>
<% } %>
</ul>
<div class="paging prev">◄</div>
<div class="paging next">►</div>
</section>
</script>
I have a variable the represents the current page and i know the total amount of pages. But i dont know how to implement this that i describes as my problem.
Anyone knows how to do this and can come with an example? Would be very appreciated!
You can do it like this :
updateTotal: function () {
var self = this;
self.totalModel.fetch({
success:function(model,response) {
var total = response.data; //all iems
var p = total/self.perPage;
var r = total-Math.round(p);
var c = ... // current page
self.pagination = _.template($("#pagination_template").html(), {
pages:Math.ceil(p),
current: c
});
self.render();
}
});
},
And the html
<script type="text/template" id="pagination_template">
<section class="pagination">
<ul>
<%
var renderPage;
for (var i = 1; i <= pages; i++) {
renderPage = false;
if (pages < 10) {
renderPage = true;
} else {
if (current <= 5) {
if (i < 10) {
renderPage = true;
}
} else if (current <= pages - 5) {
if ((current - 5) < i || (current + 5) > i) {
renderPage = true;
}
} else {
if ((pages - 9) < i) {
renderPage = true;
}
}
};
if (renderPage) { %>
<li>
<a href="#" data-offset="<%= i*9 %>" data-page="<%= i %>">
<%= i %>
</a>
</li>
<% }
} %>
</ul>
<div class="paging prev">◄</div>
<div class="paging next">►</div>
</section>
</script>
That will print the current page and the 4 pages before and after.

Categories

Resources