Counting variable in JS that has been parsed from php - javascript

I got a variable that represents required number of items and counting of dropped items inside droppable area. You can view example here. So what I want is to pass a variable to javascript and then calculate the difference.
I put my variable into div:
<div id="numbr" >10</div>
And here is the js code which counts dropped items and displays the total:
var n = $(this).closest("div.proc").find(".dropClass").length -1;
$(this).closest("div.proc").find("div.dropped").text("Items Dropped: " + n + ".");
My goal is to find differences between <div class="numbr"> and n, and then display it. How can I achieve this in js?
It is just an example.In my system, the number is a php variable received from user's input. There could be more than 2 boxes: it depends on user's input.

Try the following in both the drop event and the click event:
var proc = $(this).closest("div.proc");
proc.find('.dif').text('Difference ' +(proc.find('.numbr').text() - n));
demo: https://jsfiddle.net/d1ddsj8m/2/
var itm = [];
$("#savebutton").click(function() {
LISTOBJ.saveList();
});
$("#myAccordion").accordion({
heightStyle: "content",
active: false,
collapsible: true
});
$("#myAccordion li").draggable({
appendTo: "body",
helper: "clone",
start: function(ev, ui) {
ui.helper.width($(this).width());
}
});
$(".projLeader ol").droppable({
tolerance: 'pointer',
hoverClass: 'highlight',
drop: function(ev, ui) {
var zz = ui.draggable.text()
var xyz = itm.includes(zz);
if (xyz === false) {
var item = ui.draggable;
if (!ui.draggable.closest('.placeholder').length) item = item.clone().draggable(); // if item was dragged from the source list - clone it
//this.innerHTML = ''; // clean the placeholder
item.addClass('dropClass').appendTo(this);
// append item to placeholder
//add to array
itm.push(zz);
var n = $(this).closest("div.proc").find(".dropClass").length;
$(this).closest("div.proc").find(".dropped").text("Items Dropped: " + n + ".");
$(this).closest("div.proc").find('.dif').text('Difference ' + ($(this).closest("div.proc").find('.numbr').text() - n));
} else {
alert('Name is Already Exist');
}
}
});
$(".projLeader").on('click', '.closer', function() {
var item = $(this).closest('.item');
var element = $("#myAccordion ul li").filter(function() {
return $(this).text() == item.text();
});
itm.splice(item);
var n = $(this).closest("div.proc").find(".dropClass").length - 1;
$(this).closest("div.proc").find("div.dropped").text("Items Dropped: " + n + ".");
$(this).closest("div.proc").find('.dif').text('Difference ' + ($(this).closest("div.proc").find('.numbr').text() - n));
item.fadeTo(200, 0, function() {
item.remove();
})
});
var LISTOBJ = {
saveList: function() {
var listCSV = "";
$(".projLeader li").each(function() {
if (listCSV === "") {
listCSV = $(this).text();
} else {
listCSV += ", " + $(this).text();
}
$("#output").text(listCSV);
$(".hiddenListInput").val(listCSV);
});
}
}
body {
font-family: verdana;
font-size: 12px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
margin-bottom: 10px;
}
ol {
list-style-type: none;
}
.item {
height: 20px;
width: 180px;
margin: 5px;
padding: 5px;
border: 1px solid gray;
background-color: #cd8;
position: relative;
}
.item .closer {
position: absolute;
right: 5px;
top: 2px;
font: bold 14px arial;
color: #666;
padding: 1px 3px;
line-height: 1;
cursor: pointer;
display: none;
}
.item .closer:hover {
color: #000;
}
.placeholder {
height: 30px;
width: 195px;
margin: 5px;
background: #eee;
border: 1px dashed #999;
}
.placeholder .item {
margin: 0;
}
ol .item .closer {
display: block;
}
.highlight {
border: 1px solid red;
background: #fff;
}
.highlight .item {
opacity: 0.3;
}
.ui-draggable-dragging {
z-index: 99;
opacity: 1 !important;
}
.dropClass {
background-color: lightblue;
padding-left: 10px;
width: 180px;
border: 1px solid black;
border-radius: 8px;
margin-bottom: 5px;
}
.dropped {
display: inline;
}
.dif {
display: inline;
}
.numbr {
display: inline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.12.0/jquery-ui.min.js" integrity="sha256-eGE6blurk5sHj+rmkfsGYeKyZx3M4bG+ZlFyA7Kns7E=" crossorigin="anonymous"></script>
<h1 class="ui-widget-header">Products</h1>
<div id="myAccordion">
<h3>T-Shirts</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>Lolcat Shirt</li>
<li class="item"><span class="closer">x</span>Cheezeburger Shirt</li>
<li class="item"><span class="closer">x</span>Buckit Shirt</li>
</ul>
</div>
<h3>Bags</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>Zebra Striped</li>
<li class="item"><span class="closer">x</span>Black Leather</li>
<li class="item"><span class="closer">x</span>Alligator Leather</li>
</ul>
</div>
<h3>Gadgets</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>iPhone</li>
<li class="item"><span class="closer">x</span>iPod</li>
<li class="item"><span class="closer">x</span>iPad</li>
</ul>
</div>
</div>
<div class='proc'><pre>
<br /></pre>
<div class="projLeader">
<label>Box1. Required number:
<div class="numbr">10</div>.
<div class="dropped"></div>
<div class="dif">Difference:</div>
</label>
<div class="ui-widget-content">
<ol>
<li class="placeholder" name="projLeader"></li>
<input type="hidden" name="projLeader" class="hiddenListInput1" />
</ol>
</div>
</div>
</div>
<div class='proc'><pre>
<br /></pre>
<div class="projLeader">
<label>Box2. Required number:
<div class="numbr">5</div>.
<div class="dropped"></div>
<div class="dif">Difference:</div>
</label>
<div class="ui-widget-content">
<ol>
<li class="placeholder" name="projLeader"></li>
<input type="hidden" name="projLeader" class="hiddenListInput1" />
</ol>
</div>
</div>
</div>
<br/>
<input type="submit" id="savebutton" class="button" value="Save" onclick="userSubmitted = true;" />
<div id="output"></div>

It looks like you are using jQuery, which makes it really easy to manipulate the DOM dynamically.
Here is what I would do. First, add a difference div which will hold the difference of n and numbr:
<div id="numbr">10</div>
<div id="difference"></div>
And in your JS, calculate the difference and add it to the div:
var n = $(this).closest("div.proc").find(".dropClass").length - 1;
var difference = parseInt($('#numbr').text(), 10) - n;
if (difference >= 0) {
$('#difference').text('Difference ' + difference);
}

Do you mean that you can use a PHP variable in javascript. If that's the case, this is probably what you are looking for:
<?php
$myVariable = 200;
?>
<script type="text/javascript">
$(document).ready(function () {
var myvar = <?= $myVariable; ?>;
$(document).on('change', '.numbr', function () {
var number = parseInt($(this).text(), 10);
var difference = myvar - number;
$('.somediv').text($difference);
});
});
</script>
<div class="numbr">20</div>

To get the dropClass content, use the text() method. length will give you the number of nodes for the given selector, it's not what you want here.
You can get the numbr and dropClass content with the text() method.
Try this(added some html for the snippet to work):
inner = $('#innerproc').closest("div.proc");
numbr = $('#numbr').text();
n = inner.find(".dropClass").text();
inner.find("div.dropped").text("Items Dropped: " + (n - numbr) + ".");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="numbr">10</div>
<div class="proc">
<div id="innerproc"></div>
<div class="dropClass">21</div>
<div class="dropped"></div>
</div>

Related

how to fix onClick button for append functions?

Here I work on a project where I want to implement open and close buttons but I am not able to do
currently, it's a close button for both, I need to add separate open and close buttons so that when the user clicks on open then it's open and when someones click on close then it should close properly also when I click continuously close then buttons freezes for sometime
Here is the demo of my JSFiddle Demo
please check the js Fiddle demo where buttons doesn't work properly
Here is the code
function createItem(item) {
var elemId = item.data("id");
var clonedItem = item.clone();
var newItem = $(`<div data-id="${elemId}"></div>`);
newItem.append(clonedItem);
newItem.appendTo('.item-append');
}
function countSaveItems() {
$('.count').html($(".item-append div.item-save[data-id]").length);
}
$('.item-all .item-save').click(function() {
$(this).toggleClass('productad')
window.localStorage.setItem('test_' + this.dataset.id, $(this).hasClass('productad'));
});
$('.item-all .item-save').each(function() {
var id = 'test_' + $(this).data("id");
$(this).append(`<button class='close'>Close</button>`);
if (localStorage.getItem(id) && localStorage.getItem(id) == "true") {
$(this).addClass('productad');
createItem($(this));
countSaveItems();
}
});
$(".item-all .item-save").click(function() {
var elemId = $(this).data("id");
var existing = $(`.item-append div[data-id="${elemId}"]`);
if (existing.length > 0) {
existing.remove();
} else {
createItem($(this));
}
countSaveItems();
});
$(".item-append").on("click", ".close", function() {
var id = $(this).parent().data("id");
localStorage.removeItem(`test_${id}`);
$(`.item-save[data-id='${id}']`).removeClass('productad');
$(this).parent().remove();
countSaveItems();
});
.item-save {
position: relative;
display: block;
font-size: 14px;
margin: 5px;
padding: 5px;
background: #a5a5a5;
float: left;
text-align: center;
cursor: pointer;
}
.productad {
background: red;
color: #eee
}
.count {
display: block;
background: #cbcbcb;
float: left;
font-size: 15px;
padding: 5px 18px;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='item-all'>
<div class='item-save' data-id='123'>
Save1
</div>
<div class='item-save' data-id='124'>
Save2
</div>
<div class='item-save' data-id='125'>
Save3
</div>
<div class='item-save' data-id='126'>
save4
</div>
</div>
<div class='item-append'>
</div>
<div class='count'>0</div>
Any Kind of help or suggestion is highly appreciated
To do the effect you need to add the open button into the HTML because that will be static, then switch between "Open" and "Close" when the user clicks into the "Open" or close the item, also needs to fix the local storage instead of removing in the close button just switch the value to false and validate based on that value. check the following code to see if that is what you are looking for:
function createItem(item){
var elemId = item.data("id");
var clonedItem = item.clone();
var newItem = $(`<div data-id="${elemId}"></div>`);
newItem.append(clonedItem);
clonedItem.children('.open').remove();
clonedItem.append(`<button class='close'>Close</button>`);
newItem.appendTo('.item-append');
}
function countSaveItems(){
$('.count').html($(".item-append div.item-save[data-id]").length);
}
$('.item-all .item-save').click(function() {
var id = $(this).data("id");
var lsId = `test_${id}`;
$(this).toggleClass('productad');
if (!$(this).hasClass('productad')){
window.localStorage.setItem(lsId, false);
$(this).children(".open").html("Open");
createItem($(this));
}else{
window.localStorage.setItem(lsId, true);
$(this).children(".open").html("Close");
$(`.item-append div[data-id='${id}']`).remove();
}
countSaveItems();
});
$('.item-all .item-save').each(function() {
var id = 'test_' + $(this).data("id");
if (localStorage.getItem(id) && localStorage.getItem(id) == "true") {
$(this).addClass('productad');
createItem($(this));
}
countSaveItems();
});
$(".item-all .item-save").click(function() {
var elemId = $(this).data("id");
var existing = $(`.item-append div[data-id="${elemId}"]`);
if (existing.length > 0){
existing.remove();
}else{
createItem($(this));
}
countSaveItems();
});
$(".item-append").on("click", ".close", function() {
var id = $(this).parent().data("id");
window.localStorage.setItem(`test_${id}`, false);
$(`.item-save[data-id='${id}']`).removeClass('productad');
$(`.item-save[data-id='${id}']`).children(".open").html("Open");
$(this).parent().parent().remove();
countSaveItems();
});
.item-save {
position: relative;
display: block;
font-size: 14px;
margin: 5px;
padding: 5px;
background: #a5a5a5;
float: left;
text-align: center;
cursor: pointer;
}
.productad {
background: red;
color: #eee
}
.count {
display: block;
background: #cbcbcb;
float: left;
font-size: 15px;
padding: 5px 18px;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='item-all'>
<div class='item-save' data-id='123'>
Save1 <button class='open'>Open</button>
</div>
<div class='item-save' data-id='124'>
Save2 <button class='open'>Open</button>
</div>
<div class='item-save' data-id='125'>
Save3 <button class='open'>Open</button>
</div>
<div class='item-save' data-id='126'>
Save4 <button class='open'>Open</button>
</div>
</div>
<div class='item-append'></div>
<div class='count'>0</div>

.click only if div contains 2 specific divs

I have a an on.click, but I want it to only run if #battle contains #obiWanPicked and #darthMaul. For whatever reason it seems to be ignoring the if statement and running the click, no matter what.
Most of my html content is dynamically created in JavaScript, thats why I start using .on instead of .click lower down when I'm manipulating objects dynamically created.
if ($("#battle").has("#obiWanPicked") && $("#battle").has("#darthMaul")) {
$("#battle").on("click", "#attack", function () {
if(darthMaulStats.healthPoints <= 0){
$("#darthMaul").remove();
alert("You win!");
}
darthMaulStats.healthPoints = darthMaulStats.healthPoints - obiWanStats.attackPower;
obiWanStats.attackPower = obiWanStats.attackPower + 15;
$("#darthMaul").text(darthMaulStats.healthPoints);
obiWanStats.healthPoints = obiWanStats.healthPoints - 5;
$("#obiWanPicked").text(obiWanStats.healthPoints);
console.log(obiWanStats);
$('#yourFighters').remove();
});
}
All of the above code
<div id="gameModule">
<div class="row">
<div class="col-2"></div>
<div class="col-8">
<div id="allFighters">Pick your Fighter!<br /></br>
<div id="obiWan">
<h2>120</h2>
</div>
<div id="darthMaul">
<h2>150</h2>
</div>
<div id="hanSolo">
<h2>100</h2>
</div>
<div id="maceWindu">
<h2>200</h2>
</div>
</div>
</div>
<div id="col-2"></div>
</div>
<div id="row">
<div id="yourFighters"></br>Your Pick<br></div>
</div>
<div id="row">
<div id="enemyFighters">Your Enemies: Click to fight<br></div>
</div>
<div id="row">
<div id="battle">Time to Battle!</br><br></div>
</div>
<div id="row">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="footer">
<br />
FOOTER
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script>
var allFighters = $('#allFighters');
var yourFighters = $('#yourFighters');
var enemyFighters = $('#enemyFighters');
var battle = $('#battle');
var obiWan = $('#obiWan');
var darthMaul = $('#darthMaul');
var darthMaulBattle = $('#darthMaulBattle');
var hanSolo = $('#hanSolo');
var maceWindu = $('#maceWindu');
var attack = $('#attack')
var obiWanStats = {
healthPoints: 120,
attackPower: 15,
counterAttackPower: 14,
};
var darthMaulStats = {
healthPoints: 150,
attackPower: 15,
counterAttackPower: 14,
};
var hanSoloStats = {
healthPoints: 100,
attackPower: 15,
counterAttackPower: 14,
};
var maceWinduStats = {
healthPoints: 200,
attackPower: 15,
counterAttackPower: 14,
};
console.log(maceWinduStats.healthPoints);
obiWan.click(function () {
allFighters.remove();
yourFighters.append("<div id='obiWan'>120</div><h1>");
enemyFighters.append("<div id='darthMaul'>150</div>");
enemyFighters.append("<div id='hanSolo'>100</div>");
enemyFighters.append("<div id='maceWindu'>200</div>");
battle.append("<div id='obiWanPicked'>" + obiWanStats.healthPoints + "</div> <p style='color: red; padding-left: 500px; padding-right: 500px; text-decoration: overline; '>VERSUS");
});
darthMaul.click(function () {
allFighters.remove();
yourFighters.append("<div id='darthMaul'>120</div>");
enemyFighters.append("<div id='obiWan'>150</div>");
enemyFighters.append("<div id='hanSolo'>100</div>");
enemyFighters.append("<div id='maceWindu'>200</div>");
battle.append("<div id='darthMaulPicked'>" + darthMaulStats.healthPoints + "</div> <p style='color: red; padding-left: 500px; padding-right: 500px; text-decoration: overline; '>VERSUS");
});
hanSolo.click(function () {
allFighters.remove();
yourFighters.append("<div id='hanSolo'>120</div>");
enemyFighters.append("<div id='darthMaul'>150</div>");
enemyFighters.append("<div id='obiWan'>100</div>");
enemyFighters.append("<div id='maceWindu'>200</div>");
battle.append("<div id='hanSoloPicked'>" + hanSoloStats.healthPoints + "</div> <p style='color: red; padding-left: 500px; padding-right: 500px; text-decoration: overline; '>VERSUS");
});
maceWindu.click(function () {
allFighters.remove();
yourFighters.append("<div id='maceWindu'>120</div>");
enemyFighters.append("<div id='darthMaul'>150</div>");
enemyFighters.append("<div id='hanSolo'>100</div>");
enemyFighters.append("<div id='obiWan'>200</div>");
battle.append("<div id='maceWinduPicked'>" + maceWindu.healthPoints + "</div> <p style='color: red; padding-left: 500px; padding-right: 500px; text-decoration: overline;'>VERSUS");
});
$("#enemyFighters").on("click", "#darthMaul", function () {
$(this).remove();
console.log("meme");
battle.append("<div id='darthMaul' style='float: none; margin-left: 50%; margin-top: -35px;'>" + darthMaulStats.healthPoints + "</div><div id='attack'>Attack!</div>");
});
$("#enemyFighters").on("click", "#hanSolo", function () {
$(this).remove();
console.log("meme");
battle.append("<div id='hanSolo' style='float: none; margin-left: 50%; margin-top: -35px;'>" + hanSoloStats.healthPoints + "</div><div id='attack'>Attack!</div>");
});
$("#enemyFighters").on("click", "#maceWindu", function () {
$(this).remove();
console.log("meme");
battle.append("<div id='maceWindu' style='float: none; margin-left: 50%; margin-top: -35px;'>" + maceWinduStats.healthPoints + "</div><div id='attack'>Attack!</div>");
});
$("#enemyFighters").on("click", "#obiWan", function () {
$(this).remove();
console.log("meme");
battle.append("<div id='obiWan' style='float: none; margin-left: 800px; margin-top: -35px;'>" + obiWanStats.healthPoints + "</div><div id='attack'>Attack!</div>");
});
Maybe you are trying to do something like this. Using find and testing the length should work.
/* Maybe you are trying to do something like this. Using find and testing the length should work. */
$("#battle").on("click", "#attack", function () {
if ($("#battle").find("#obiWanPicked").length > 0 && $("#battle").find("#darthMaul").length > 0){
console.log("You win!");
} else {
console.log("You Lose!");
}
});
/* Just for testing */
$("body").on("click", "#toggleObiwan", function(){
if($("#battle").find("#obiWanPicked").length > 0){
$("#obiWanPicked").remove();
} else {
$("#battle").append("<div id='obiWanPicked'>O</div>");
}
});
$("body").on("click", "#toggleDarthMaul", function(){
if($("#battle").find("#darthMaul").length > 0){
$("#darthMaul").remove();
} else {
$("#battle").append("<div id='darthMaul'>D</div>");
}
});
#battle {
width: 200px;
height: 100px;
background: green;
}
#obiWanPicked {
width: 20px;
height: 20px;
background: skyblue;
line-height: 20px;
margin: 5px;
}
#darthMaul {
width: 20px;
height: 20px;
background: red;
line-height: 20px;
margin: 5px;
}
button {
width: 100px;
font-size: 11px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<button id="toggleObiwan">TOGGLE OBIWAN</button>
<button id="toggleDarthMaul">TOGGLE DARTH MAUL</button>
<div id="battle">
<button id="attack">ATTACK</button>
<div id="obiWanPicked">O</div>
<div id="darthMaul">D</div>
</div>
Not sure here... I'm kind of replying quick. But I understand your question from this:
I want it to only run if #battle contains #obiWanPicked and #darthMaul
Now the click handler is registered on page load where (I suppose) the two ids to be checked for existance are there.
Move that condition in the click handler!
$("#battle").on("click", "#attack", function () {
if ($("#battle").has("#obiWanPicked").length && $("#battle").has("#darthMaul").length) {
if(darthMaulStats.healthPoints <= 0){
//...
So the condition will be checked on every click instead of only when the handler gets registered.
;)
showdev mentionned a good point... Add .length after has(), so the condition will evaluate on length instead of on an object.
A zero length evaluates to false. Any other lenght evaluates to true.

Display progress bar as scroll in multiple elements

I am trying to create a post page where user scroll to view the posts. There are multiple posts with a sidebar so I want to display a progress bar to indicate the article position.
The code I wrote for this is working good when I navigate to the first element but not for the elements after this.
Here is the code. I tried to set up a fiddle here I want to achieve something like this in the sidebar Reference link
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if (($this.offset().top - $(window).height() / 2 < $(window).scrollTop()) && ($this.offset().top + $this.height() - $(window).height() / 2 > $(window).scrollTop())) {
var s = $(window).scrollTop(),
d = $this.height(),
c = $this.offset().top;
var scrollPercent = (s / (d - c)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>
There's two issues with your code. The first one is that, logically, you would not be wanting to subtract $this.offset().top from $this.height() but rather from $(window).scrollTop() giving you:
var scrollPercent = ((s-c) / (d)) * 100;
The second one is that your logic to switch which article is the currently visible one is convoluted and wrong. The statement you posted switches active article "too early" and therefore returns something a long the lines of "the user read -30% of this article". It is a lot easier to just check for each item whether:
$this.offset().top - $(window).scrollTop() < 0
to determine if it is completely in the viewport.
These two changes give you the following snippet:
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if ($this.offset().top - $(window).scrollTop() < 0) {
var s = $(window).scrollTop()-13,
d = $this.outerHeight(),
c = $this.offset().top;
var scrollPercent = ((s-c) / (d)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>

Is it possible to filter already fetched data with jQuery

I am using the Laravel framework and fetching data. Now I am trying to filter the data with Ajax and jQuery. But a couple problem that I am facing...
UPDATED 4
When I start filter, there is this error looping:
"/var/www/html/laravel/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php",
"line": 255,
"trace": [
{
"file": "/var/www/html/laravel/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php",
"line": 242,
"function": "methodNotAllowed",
"class": "Illuminate\Routing\RouteCollection",
"type": "->"
},
is there that I am missing something about the controller? or routing? Thank you for help!
Laravel Controller:
public function search(Request $request)
{
$q = $request->q;
$sortbyprice = $request->sortbyprice;
$region = $request->region;
$rooms = $request->rooms;
$price = $request->price;
$max = $request->input('max');
$min = $request->input('min');
$paginationData = [
'q' => $q
];
$estates = \DB::table('allestates')
->where('lat', '!=', '')
->where('lng', '!=', '')
->where('price', '!=', '')
->when($q, function($query, $q) use ($paginationData) {
$paginationData['q'] = $q;
return $query->where(function($query) use ($q) {
$query->where("building_name", "LIKE", "%" . $q . "%")
->orWhere("address", "LIKE", "%" . $q . "%")
->orWhere("company_name", "LIKE", "%" . $q . "%")
->orWhere("region", "LIKE", "%" . $q . "%")
->orWhere("rooms", "LIKE", "%" . $q . "%");
});
})
->when($sortbyprice, function($query, $order) use ($paginationData) {
if(!in_array($order, ['asc','desc'])) {
$order = 'asc';
}
$paginationData['sortbyprice'] = $order;
return $query->orderBy('price', $order);
}, function($query) {
return $query->orderBy('price');
})
->when($region, function($query, $regionId) use ($paginationData) {
$paginationData['region'] = $regionId;
return $query->where('region', $regionId);
})
->when($rooms, function($query, $roomsId) use ($paginationData) {
$paginationData['rooms'] = $roomsId;
return $query->where('rooms', "LIKE", "%" . $roomsId . "%");
})
->when($max, function($query, $max) use ($min, $paginationData) {
$paginationData['min'] = $min;
$paginationData['max'] = $max;
return $query->whereBetween('price', [$min, $max]);
})
// ->toSql()
->paginate(100);
$paginationData = array_filter($paginationData);
return view("home", compact('estates', 'q','paginationData'));
}
var displayList = $('#display-wrapper ol');
var selectedOptions = {
sortbyprice: '',
rooms: '',
region: ''
};
$('html').click(function () {
console.log(selectedOptions);
});
$('a.region').on('click', function () {
var selectValue = $(this).data('value');
$('#region').text(selectValue);
selectedOptions.region = selectValue;
fetchDataFromServer(selectedOptions);
});
$('a.rooms').on('click', function () {
var selectValue = $(this).data('value');
$('#rooms').text(selectValue);
selectedOptions.rooms = selectValue;
fetchDataFromServer(selectedOptions);
});
$('a.sortbyprice').on('click', function () {
var selectValue = $(this).text();
selectedOptions.sortbyprice = selectValue;
fetchDataFromServer(selectedOptions);
});
function serialize(options) {
var arr = [];
for (var key in options) {
arr.push(key + '=' + options[key]);
}
return encodeURI(arr.join('&'));
}
function fetchDataFromServer(options) {
$.ajax({
type: 'POST',
url: '/home',
data: serialize(options),
success: function (response) {
if (response.error) {
console.error(response.error);
} else {
console.log(response);
updateDisplay(displayList);
}
},
error: function (html, status) {
console.log(html.responseText);
console.log(status);
}
});
}
function updateDisplay(node, data) {
var template = data.reduce(function (acc, item) {
return acc + '<li><p>Region: ' + item.region + '</p><p>Price: ' + item.price + '</p><p>Rooms: ' + item.rooms + '</p></li>';
}, '');
node.empty();
node.append(template);
}
#filter-wrapper {
margin-top: 15px
}
#filter-wrapper ul {
list-style: none;
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul a {
display: block;
color: #333;
text-decoration: none;
font-weight: 700;
font-size: 12px;
line-height: 32px;
padding: 0 15px;
font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}
#filter-wrapper ul li {
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul li.current-menu-item {
background: lightblue;
}
#filter-wrapper ul li:hover {
background: #f6f6f6
}
#filter-wrapper ul ul {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
padding: 0
}
#filter-wrapper ul ul li {
float: none;
width: 200px
}
#filter-wrapper ul ul a {
line-height: 120%;
padding: 10px 15px
}
#filter-wrapper ul ul ul {
top: 0;
left: 100%
}
#filter-wrapper ul li:hover>ul {
display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
<ul>
<li><a class="sortbyprice" href="javascript:" data-value="sortbyprice">Cheapest</a></li>
<li class="dropdown">
間取り
<ul class="init" name="rooms">
<li><a class="rooms" href="javascript:" data-value="1DK">1DK</a></li>
<li><a class="rooms" href="javascript:" data-value="2LDK">2LDK</a></li>
<li><a class="rooms" href="javascript:" data-value="3LDK">3LDK</a></li>
</ul>
</li>
<li class="dropdown">
エリア
<ul class="init" name="region">
<li><a class="region" href="javascript:" data-value="関西">関西</a></li>
<li><a class="region" href="javascript:" data-value="関東">関東</a></li>
<li><a class="region" href="javascript:" data-value="北海道">北海道</a></li>
</ul>
</li>
</ul>
</div>
<div id="display-wrapper">
<ol></ol>
</div>
Yes you can.
This is often done on the server, but if your data set is small enough it can work. If you set the filterable data points as data elements of your items you can just compare the selected value from the filter. jQuery's each function is one way to loop through the elements and you can then use the data function to access the appropriate data attribute.
$('#room-filter').on('change', function() {
const numRooms = $(this).val();
$('.card').each(function() {
if (numRooms && numRooms != $(this).data('rooms')) {
$(this).slideUp();
} else {
$(this).slideDown();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Rooms:
<select id="room-filter">
<option value="">Show All</option>
<option value="1">1 Room</option>
<option value="2">2 Rooms</option>
<option value="3">3 Rooms</option>
</select>
<div class="card text-left" data-rooms="1">
<div class="card-body d-flex" id="content-card">
<h2>Shack</h2>
<p class="main-text">1 room</p>
</div>
</div>
<div class="card text-left" data-rooms="1">
<div class="card-body d-flex" id="content-card">
<h2>Second Shack</h2>
<p class="main-text">1 room</p>
</div>
</div>
<div class="card text-left" data-rooms="3">
<div class="card-body d-flex" id="content-card">
<h2>Bungalo</h2>
<p class="main-text">3 rooms</p>
</div>
</div>
The main idea is to create a variable to store all the options selected by the user, and on each ajax request, you send the corresponding data to the server in order to get the filtered result.
I removed the hidden HTML form, and choose to use an object instead.
The ajax request in this code snippet is not working because there is no end-point '/home' for me to get the resources, but I think this will work on your machine.
As a side note, the id attribute should be unique, or else, the behavior might not be what you'd expected. And for the onclick handlers, if you have a lot of dropdowns, you should consider generating them with a loop instead of copy and pasting like I did, but for demo purposes, I will leave it as it is for now.
// a sample display
var displayList = $('#display-wrapper ol');
// create an object to store the selected options
var selectedOptions = {
sortbyprice: '',
rooms: '',
region: ''
};
// this event handler is for logging out the selectedOptions
// so that you can see what happens to the variable
// you should remove this in production
$('html').click(function () {
console.log(selectedOptions);
});
$('a.region').on('click', function () {
// I guess what you're trying to do here is to update the dropdown
// text into the selected value, e.g replace エリア with 関西
var selectValue = $(this).data('value');
$('#region').text(selectValue);
selectedOptions.region = selectValue;
fetchDataFromServer(selectedOptions);
});
$('a.rooms').on('click', function () {
var selectValue = $(this).data('value');
$('#rooms').text(selectValue);
selectedOptions.rooms = selectValue;
fetchDataFromServer(selectedOptions);
});
$('a.sortbyprice').on('click', function () {
// var selectValue = $(this).text();
// selectedOptions.sortbyprice = selectValue;
selectedOptions.sortbyprice = 'asc';
fetchDataFromServer(selectedOptions);
});
function fetchDataFromServer(options) {
$.ajax({
type: 'GET',
url: '/home',
data: options,
success: function (response) {
if (response.error) {
// sweetAlert("Oops...", response.data, "error");
console.error(response.error);
} else {
console.log(response);
// I assume the data structure of the response is something like
// var reponse = {
// data: [
// {
// price: 123,
// rooms: '1DK',
// region: '関西'
// },
// ......
// ]
// }
// This is an example function for updating the UI
// You can replace this function according to your needs
updateDisplay(displayList, response.data);
}
},
error: function (html, status) {
console.log(html.responseText);
console.log(status);
}
});
}
function updateDisplay(node, data) {
// build the html for the node(<ol> tag)
var template = data.reduce(function (acc, item) {
return acc + '<li><p>Region: ' + item.region + '</p><p>Price: ' + item.price + '</p><p>Rooms: ' + item.rooms + '</p></li>';
}, '');
// add the template to the node(<ol> tag)
node.empty();
node.append(template);
}
#filter-wrapper {
margin-top: 15px
}
/*
* I added this line for demo purpose
* Not sure whether you'll need this in your app
* Feel free to remove this
*/
#filter-wrapper::after {
content: '';
clear: both;
display: block;
}
#filter-wrapper ul {
list-style: none;
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul a {
display: block;
color: #333;
text-decoration: none;
font-weight: 700;
font-size: 12px;
line-height: 32px;
padding: 0 15px;
font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}
#filter-wrapper ul li {
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul li.current-menu-item {
background: lightblue;
}
#filter-wrapper ul li:hover {
background: #f6f6f6
}
#filter-wrapper ul ul {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
padding: 0
}
#filter-wrapper ul ul li {
float: none;
width: 200px
}
#filter-wrapper ul ul a {
line-height: 120%;
padding: 10px 15px
}
#filter-wrapper ul ul ul {
top: 0;
left: 100%
}
#filter-wrapper ul li:hover>ul {
display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
<ul>
<li><a class="sortbyprice" href="javascript:" data-value="sortbyprice">Cheapest</a></li>
<li class="dropdown">
間取り
<ul class="init" name="rooms">
<li><a class="rooms" href="javascript:" data-value="1DK">1DK</a></li>
<li><a class="rooms" href="javascript:" data-value="2LDK">2LDK</a></li>
<li><a class="rooms" href="javascript:" data-value="3LDK">3LDK</a></li>
</ul>
</li>
<li class="dropdown">
エリア
<ul class="init" name="region">
<li><a class="region" href="javascript:" data-value="関西">関西</a></li>
<li><a class="region" href="javascript:" data-value="関東">関東</a></li>
<li><a class="region" href="javascript:" data-value="北海道">北海道</a></li>
</ul>
</li>
</ul>
</div>
<div id="display-wrapper">
<ol></ol>
</div>

Onsubmit form creating new div with id and class

I'm building a tabbed content page. I was trying to build a form that would take a value from the form and create a new tab and also create a new div that would attach to the tab, that would be triggered by an on click function. I was having some trouble creating the div, it didn't seem to launch. When the value is entered, the tab is supposed to go active so the content would show up. I think I'm either doing something wrong with the new div or the on click function. I wasn't sure if those two code pieces should be combined, since they seemed to be in conflict. Thanks.
jQuery(document).ready(function() {
jQuery('.tabs .tab-links a').on('click', function(e) {
var currentAttrValue = jQuery(this).attr('href');
$('.tabs ' + currentAttrValue).show();
$('.tabs ' + currentAttrValue).animate({
opacity: 1,
paddingLeft: '30%'
}, 400);
$('.tabs ' + currentAttrValue).siblings().css({
opacity: 0,
paddingLeft: '0%'
});
$('.tabs ' + currentAttrValue).fadeIn(400).siblings().hide();
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
e.preventDefault();
});
});
$(function() {
var $textInput = $('input:text');
$('#examine').on('submit', function(e) {
e.preventDefault();
var newText = $textInput.val();
$('ul:last').append('<li>Searching...</li>');
$('#tab-content').append('<div id ="tab5' + '"class="tab active"><p>the quick brown fox</p></div>');
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
$textInput.val('');
});
});
.tab-links {
float: left;
}
.tab-links:after {
display: block;
clear: both;
content: '';
}
.tab-links li {
list-style-type: none;
background-color: #303030;
border-bottom: 3px solid #858585;
font-family: 'Jacques Francois', serif;
text-transform: uppercase;
letter-spacing: 0.09em;
margin-left: -25%;
}
.tab-links li a {
color: #f2f2f2;
display: block;
padding: 3px 10px 3px 10px;
text-decoration: none;
}
.tab-links a:hover {
background: #a7cce5;
text-decoration: none;
}
.tab-links li.active,
.tab-links li.hover {
background-color: #e5e5e5;
border-bottom: 3px solid #e5e5e5;
}
.tab-links li.active a,
.tab-links li a:hover {
color: #666;
background-color: #e5e5e5;
}
/*----- Content of Tabs -----*/
.tab-content {
background-color: #e5e5e5;
color: #666;
min-height: 150px;
overflow: auto;
}
#tab1 {
padding-left: 30%;
}
#tab2,
#tab3,
#tab4,
#tab5 {
display: none;
opacity: 0;
padding-left: 0%;
}
.tab-content p {
margin: 20px;
text-indent: -40%;
}
.tab-content.active {
display: block;
text-indent: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="sidebar">
<div id="explore">
<form id="examine">
<p>Search</p>
<input type="search" name="explore" placeholder="Search Items" />
<p>Choose Your Search Restrictions</p>
<input type="radio" name="location" required="required" value="Your School" />Inside
<input type="radio" name="location" required="required" value="Whole system" />Outside
<input type="submit" value="Search" />
</form>
</div>
<div class="tabs">
<ul class="tab-links">
<li class="active">Tab1
</li>
<li>Tab2
</li>
<li>Tab3
</li>
<li>Tab4
</li>
</ul>
<div class="tab-content">
<div id="tab1" class="tab active">
<p>Tab1 content</p>
</div>
<div id="tab2" class="tab">
<p>Tab2 content</p>
</div>
<div id="tab3" class="tab">
<p>Tab3 content</p>
</div>
<div id="tab4" class="tab">
<p>Tab4 content</p>
</div>
First off you do not need two document ready handlers.
For clarity, I have added the NEW index to the "Searching..." string so you may need to edit that.
Use the index to get the new ID and append that to the list.
cache the tab and not process DOM for the tab
I assume you have some need for $textInput.val(''); so I left it
put your click handler on the .tab-links so new ones will have it (not on a1)
consider using classes and indexes instead of new IDs for tab5 etc.
if you use classes you could then clone the last tab and put in new content into the clone, making it more maintainable if the markup changes
I put a trigger on the newly added tab to activate it - it SEEMED as if that was your desire?
Consider a BUTTON rather than <input type="submit"...
Revised code:
jQuery(document).ready(function() {
jQuery('.tabs').find('.tab-links').on('click', 'a', function(e) {
var currentAttrValue = jQuery(this).attr('href');
// cache instead of multiple
var thisTab = $(currentAttrValue);
thisTab.show().animate({
opacity: 1,
paddingLeft: '30%'
}, 400);
thisTab.siblings().css({
opacity: 0,
paddingLeft: '0%'
});
thisTab.fadeIn(400).siblings().hide();
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
e.preventDefault();
});
var $textInput = $('input:text');
$('#examine').on('submit', function(e) {
e.preventDefault();
var newText = $textInput.val();
var newIndex = $('.tab-links').find('li').length + 1;
$('.tab-content').append('<div id="tab' + newIndex + '" class="tab"><p>the quick brown fox ' + newIndex + '</p></div>');
$textInput.val('');
$('.tab-links').append('<li>Searching...' + newIndex + '</li>');
$('.tab-links').find('a').eq(newIndex - 1).trigger('click');
});
});f
EDIT: Per comment, update if already at max count:
This is not super efficient but you can get started with this.
jQuery(document).ready(function() {
jQuery('.tabs').find('.tab-links').on('click', 'a', function(e) {
var currentAttrValue = jQuery(this).attr('href');
// console.log(currentAttrValue);
var thisTab = $(currentAttrValue);
thisTab.show().animate({
opacity: 1,
paddingLeft: '30%'
}, 400);
thisTab.siblings().css({
opacity: 0,
paddingLeft: '0%'
});
thisTab.fadeIn(400).siblings().hide();
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
e.preventDefault();
});
var maxTabCount = 5;
var $textInput = $('input[type=search]');
$('#examine').on('submit', function(e) {
e.preventDefault();
var newText = $textInput.val();
var tabCount = $('.tab-links').find('li').length;
var newIndex = tabCount + 1;
var newText = $textInput.val() ? $textInput.val() : "Default Tab Text";
if (tabCount < maxTabCount) {
$('.tab-content').append('<div id="tab' + newIndex + '" class="tab"><p>the quick brown fox ' + newIndex + '</p></div>');
$('.tab-links').append('<li>Searching...' + newIndex + '</li>');
} else {
$('.tab-content').find('div.tab').last().find('p').html("New Search Content");
$('.tab-links').find('li').last().find('a').html(newText);// new tab text
}
$textInput.val('');
$('.tab-links').find('a').last().trigger('click');
});
});
You are using id for tab-content instead of class. Use the following line:
$('.tab-content').append('<div id ="tab5' + '"class="tab active">...</div>');
Replace this line jQuery('.tabs .tab-links a').on('click', function(e) with the following:
jQuery(document).on("click",".tabs .tab-links a",function() {

Categories