Rails: Show and hide a div - javascript

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;
}

Related

Call to Java Script function in ASP page not returning anything

<script type="text/javascript">
function EdgeCheck(){
var edge1;
var edge2;
var sBrowser;
edge1 = window.navigator.userAgent.indexOf("Edge") > -1;
edge2 = window.navigator.userAgent.indexOf("Edg") > -1;
if ((edge1) || (edge2)){
sBrowser = 'You are using Edge Browser';
//alert(sBrowser);
}
return sBrowser;
}
</script>
<% response.write("<b><font size='6' color='#008080'>" + '<script>EdgeCheck();</script>' + "</font></b>") %>

Display only three numbers of the total pagination numbers in Javascript

I'm trying to add some pagination numbers in Javascript. I already achieved the pagination, I also can show all the pagination numbers but I would like to show only three numbers from all the numbers. Let my show you what I achieved until now:
var values = [{name : "a"}, {name : "b"}, {name : "c"}, {name : "d"}, {name : "e"}, {name : "f"}, {name : "g"}, {name : "h"}, {name : "i"}, {name : "j"}];
var current_page = 1;
var records_per_page = 6;
if (values.length <= 6) {
btn_prev.style.display = "none";
btn_next.style.display = "none";
}
function prevPage() {
if (current_page > 1) {
current_page--;
changePage(current_page);
}
}
function nextPage() {
if (current_page < numPages()) {
current_page++;
changePage(current_page);
}
}
function changePage(page) {
var btn_next = document.getElementById("btn_next");
var btn_prev = document.getElementById("btn_prev");
var listing_table = document.getElementById("poi-cat-id");
var page_span = document.getElementById("page");
var pageNum = document.getElementById("pageNum");
// Validate page
if (page < 1) page = 1;
if (page > numPages()) page = numPages();
listing_table.innerHTML = "";
var href = getRootWebSitePath();
for (var i = (page - 1) * records_per_page; i < (page * records_per_page) && i < values.length; i++) {
var nametoslug1 = values[i].name;
var slug1 = convertToSlug(nametoslug1);
listing_table.innerHTML += '<div class="event-desc"><p>' + values[i].name + '</p></div>';
}
if (page == 1) {
btn_prev.style.color = "#404141";
} else {
btn_prev.style.visibility = "visible";
btn_prev.style.color = "#0c518a";
}
if (page == numPages()) {
btn_next.style.color = "#404141";
} else {
btn_next.style.visibility = "visible";
btn_next.style.color = "#0c518a";
}
male();
maen();
}
//this is where I add all the numbers of the pagination
var totnum = numPages();
for (var i = 0; i < numPages() + 2; i++) {
// We do not want page 0. You could have started with i = 1 too.
$('#page-num-container').append('' + (i + 1) + '');
}
======EDIT=====
function newPage(){
$('.pageClick').on('click', function (e) {
e.preventDefault();
changePage($(this).index() + 1);
});
} //when I click the number the pages won't change
function numPages() {
return Math.ceil(values.length / records_per_page);
}
window.onload = function () {
changePage(1);
};
and this is my html :
<div>
<ul class="content-full" id="poi-cat-id"></ul>
<div class="pagination-poi-arrows">
<div class="prev">
<img src="~/img/left-arrow-pagination.svg" />
</div>
<div class="page-num-container" id="page-num-container">
</div>
<div class="nex">
<img src="~/img/right-arrow-pagination.svg" />
</div>
</div>
<div class="pagination-poi-arrows" id="pager"></div>
</div>
Can anybody help would be highly appreciated since I've been stuck with this for a while.
If you want to show the adjacent page numbers, then you have to start iterating at i=current_page until i=current_page + 2.
However, it seems that in your code, you start counting at 1 with your pages. I advise you to start at 0.
Now, back to your code. You need to replace the loop with the following (if you're counting from 1):
function updatePagination(page) {
for (var i = page - 1; i < page + 1; i++) {
$('#page-num-container').append('<a href="javascript:pagesNr()"
class="pageClick">' + (i + 1) + '</a>');
}
}
// you need to clear the element before you update it
function clearPagination() {
$('#page-num-container').empty();
}
You would call both of these methods at the end of the changePage() method.

How to use LocalStorage to make checkboxes persist?

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

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.

javascript append appearing twice

Here's my problem I have this javascript
if (exchRate != "") {
function roundthecon() {
var value = Math.round(exchRate*Math.pow(10,2)) / Math.pow(10,2);
$('.tablenotes > p > strong ').append(value);
}
function addCommas(nStr) {
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
// When the document is loaded..
$(document).ready(function(){
// Grab an array of the table cells
$('.evenprop table tr td:not(.title)').each(function(){
// Calculate the pound price
var v_euro = $(this).html();
if (v_euro != "N/A") {
var v_euro = v_euro.replace(/,/g,'');
var v_euro = v_euro.replace(/\u20AC/g, '');
var v_euro = v_euro.replace(/£/g, '');
var v_pound = Math.round(v_euro / exchRate);
v_pound = addCommas(v_pound);
// Create a new span element for the pound
// Insert it at the end of the table cell
if (exchRate == <%= Session("xch_dollar") %>) {
$(this).prepend("$");
}
if (exchRate == <%= Session("xch_ntl") %>) {
$(this).prepend("X");
}
if (exchRate == <%= Session("xch_euro") %>) {
$(this).append("€");
}
var o_span = $('<span/>').html(' <span style="font-weight:normal;" id="exchRate">(£' + v_pound + ')</span>');
$(this).append(o_span);
}
});
});
}
And this is my html in the page
<div class="tablenotes">
<p><span class="tariffnote">Weekly price in Euros.</span> £ in brackets are approximate sterling equivalent based on <strong>£1 =
<script type="text/javascript">roundthecon()</script><noscript><%= Session("xch_euro") %></noscript>€</strong> </p>
</div>
And the exchRate = 1.1986 for some reason my code is showing this.
<div class="tablenotes">
<p><span class="tariffnote">Weekly price in Euros.</span> £ in brackets are approximate sterling equivalent based on <strong>£1 =
1.2<noscript>1.1986</noscript>€1.2</strong> </p>
</div>
It is rounding the exchRate as it should but it is placing it in twice
Anyone got any ideas?
Thanks
Jamie
I got around the issue by doing this
$(document).ready(function(){
var value = Math.round(exchRate*Math.pow(10,2)) / Math.pow(10,2);
$('.tablenotes > p > strong ').html("£1 = " + value + "€");
});
It replaces the whole html rather than appending

Categories

Resources