jQuery - Load content from another page - only once - javascript

I have this small script, which, when clicked on, will show the content from a page where I do a PHP query. My problem is, that if the user click multiply times, it will just load the content from the PHP page multiply times as well...
This is my jQuery code:
$('.notifications-load').on('click',function() {
$('#notifications-holder').load("/?i=notifications");
});
And my HTML:
<i class="fa fa-bell notifications-load"><span class="notification">5</span></i>
<div id="notifications-holder"></div>
This is the PHP page (?i=notifications):
$n=$dbh->prepare("SELECT * FROM users_notifications WHERE userid=0 OR userid=:userid");
$n->bindParam(":userid",$userdata['id']);
$n->execute();
$data=$n->fetchAll();
foreach ($data as $value) {
echo $value['text'];
}
If a user clicks example 3 times on .notifications-load , then the content from /?i=notifications will load 3 times into the #notifications-holder - how can I prevent this?

Believe it or not, one character of difference will fix it:
$('.notifications-load').one('click',function() {
// Here -------------------^
$('#notifications-holder').load("/?i=notifications");
});
jQuery's one function hooks up a handler that it automatically unhooks the first time it's called.
If you have an aversion to using one (as some do, it's really easy to misread it as on), you have a couple of options:
You can create an alias for it:
$.fn.onOnce = $.fn.one;
You can unhook the handler explicitly:
$('.notifications-load').on('click.load',function() {
$('#notifications-holder').load("/?i=notifications");
$('.notifications-load').off('click.load');
});

Besides using $.one you can check to see if $('#notifications-holder') already has a value. Something like:
$('.notifications-load').on('click',function() {
var notification = $('#notifications-holder');
if (!notification.html().trim().length) {
notification.load("/?i=notifications");
}
});

Related

Local Storage may be conflicting with Toggle Slow

I'm trying to have .child_box class to open and close slow but seems Local Storage is not respecting it. Either it wont open or it wont close. Without Local Storage, it works fine. Stumped.
The js:
$("document").ready(function () {
$(".manualclose").click(function () {
$(".child_box").toggle();
});
ls = localStorage.getItem('on')
if(ls) {
$(".child_box").show("slow")
}
$(".open_child").click(function () {
localStorage.setItem('on',true)
toggled = $(".child_box").toggle();
if(toggled.is(":hidden")) {
localStorage.clear();
}
});
$(".manualclose").click(function() {
localStorage.clear();
$(".child_box").hide("slow")
});
});
The button:
<div class="open_child" title="', $txt['sub_boards2'], '">
<i class="fas fa-plus-circle"></i>
</div>
localStorage isn't conflicting with toggle(). The problem is down to the way the browser schedules a reflow whilst executing JavaScript.
In this event handler
$(".open_child").click(function(){
localStorage.setItem('on',true)
toggled = $(".child_box").toggle(500);
if(toggled.is(":hidden")){
localStorage.clear();
}
});
your code toggles the .child-box element. It immediately goes to see if that element is now hidden.
The browser is running the animation that is caused by .toggle() and carries on executing the JavaScript. It checks whether the element is hidden, which it isn't because the animation hasn't completed yet, and so doesn't clear the localStorage. Only later when the animation completes would the element appear as 'hidden'.
You need to do things in a different order:
$(".open_child").click(function(){
let hidden =$(".child_box").is(":hidden");
if (hidden) {
$(".child_box").show(500);
localStorage.setItem('on',true)
} else {
$(".child_box").hide(500);
localStorage.removeItem('on');
}
});
This version checks the hidden status first, then shows or hides the element as required, and updates localStorage to match.
There is an alternative approach: use the complete function available to the jQuery .toggle() method to update localStorage. You'd still need to check to see what .toggle() has just done, so you don't gain much.
FWIW, I never use .toggle() precisely because I don't know what action it's performing.
A couple of other thoughts:
You're not declaring the variable you use, so they're being placed in the global context. This is a bad idea. Declare them in the functions they're used in with let.
localStorage stores strings, not other data type. JavaScript has coerced the data for you so you've got away with it, but good practice suggests that you should be more rigorous.
Using localStorage.clear() precludes the use of localStorage for any other purpose. Use localStorage.removeItem() instead.
I don't think it's localStorage. what i noticed:
a) you don't declare the variable ls.
b) why are you using a div as a button?
c) you don't use parse and stringify to get and set values in the localStorage.
d) you put a title in a DIV container
f) the title you set looks like PHP. it is missing the < ?php echo $text ... ;? > Tags

jQuery form input field present even before document.ready function is called

I am facing a weird issue. I am relatively new to JavaScript jQuery.
When I refresh the page the address input field doesn't get cleared, while zip code and email fields do get cleared.
I tried $('#input_address').get(0).value='';
which clears the field. But I don't want it to happen when the user comes back from page 2 to page 1. Only on refresh should the fields be cleared.
The email and zip code works perfectly in both scenarios: refresh page and page2 to page1 navigation.
$(document).ready(function() {
console.log("doc ready function");
// $('#input_address').get(0).value='';
// togglePlaceholder($('#input_email').get(0));
// togglePlaceholder($('#input_zip').get(0));
togglePlaceholder($('#input_address').get(0));
$('input, select, textarea').each(
function() {
var val = $(this).val().trim();
if (val.length) {
$(this).addClass('sample');
}
});
$('input, select, textarea').blur(function() {
if ($(this).val())
$(this).addClass('sample');
else
$(this).removeClass('sample');
});
$('input, select, textarea').focus(function() {
console.log("focused");
if ($(this).val() == '') {
$(this).removeClass('invalid');
$(this).addClass('sample');
}
});
})
function togglePlaceholder(inputElement) {
var inputAttr = inputElement.getAttribute("placeholder");
inputElement.placeholder = "";
inputElement.onblur = function() {
this.placeholder = "";
}
inputElement.onfocus = function() {
this.placeholder = inputAttr;
}
}
.sample ~ label {
font-size: 1em;
top: -10px;
left: 0;
font-size: 1em;
color: #F47B20;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="input-field col s6 col-xs-12">
<input type="text" onblur="togglePlaceholder(this);" onfocus="togglePlaceholder(this);" placeholder="123 Example Street" id="input_address" />
<label for="input_address">Street Address</label>
</div>
So... you have two problems.
(1) Auto-completion is what refills the widgets automatically,
(2) You need to know what button was clicked to react accordingly.
Auto-Completion
In regard to the auto-completion, it most certainly happens right after the first set of scripts ran within the jQuery ready() function.
There are two ways to remove auto-completion, but really, I do not recommend either one, although I would imagine that you'll need to if your requirements are set in stones...
(a) Ask for the input widget to not even autocomplete
<input ... autocomplete="off" .../>
(b) Run your script with a timer so it happens after the auto-completion. Instead of initializing in the ready() function, you initialize in a sub-function that runs after a timer times out.
$(document).ready(function() {
setTimeout(function(){
// ...put your initialization here...
// the autocompletion data should have been taken care of at this point
}, 0);
});
Note that you can use a number large than 0 for the timeout delay, but in most cases 0 will work just fine to run the sub-function after releasing the current thread once and thus given the system time to work on the auto-completion and then call your function. With 0 it should be so fast that you should not even see the <input .../> tag flash.
Side note: you may also want to place the inner function in an actual function as in:
function init_stuff()
{
// ...your initialization code goes here...
}
$(document).ready(function() {
setTimeout(init_stuff, 0);
});
If you expect your initialization to continue to grow, this can be a lot cleaner long term.
Which button gets clicked
The next problem is to know whether that code should run or not. So you need an extra if() statement for that purpose.
There are several hacks on this stackoverflow page in that regard. However, I'm not exactly sure how you really know in the newly loaded page, that you had a Refresh or a Back button click.
From the code I see there, the loading of the page's content would 100% happen in AJAX and therefore you perfectly know which button was clicked, you just reimplemented the functionality. You'll have to search stackoverflow some more to find out how to do that. I strongly suggest that you write tests with one piece of functionality at a time to determine what is going on.
Note that will make having the initialization function separate quite useful since after reloading the page, you will be responsible to call that function (when you want the reset to happen) or not! In other words, if the Back button was clicked, load the HTML of the previous page (i.e. Page 1 in your example) and display it. Done. When clicking the Refresh button, load the HTML of the current page and call the reset function (it could also be that the Refresh is the default and you do not want to handle that button since it will anyway clear as expected.)
For a beginner, that's going to be an interesting piece of work!

Change javascript variable in seperate element

I run a WoW guild forum based on php (phpbb), javascript and html. Ever since long, Wowhead allows links to be posted to their item/spell IDs etc. The basic code to the Wowhead JS and it's variables is:
<script src="//static.wowhead.com/widgets/power.js"></script>
<script>var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": true }</script>
There is an extension that puts this code in the footer of every page via a HTML file. Every Wowhead link posted will be converted in a link with a tooltip explaining what it links to. The '"renamelink": true' portion of the wowhead_tooltips variable makes it as such that any link of an item or spell is renamed to the exact name of what it is linked to.
The problem: when I generate custom URLs using a Wowhead link, ie:
Teleport
instead of displaying 'Teleport' with a tooltip of Blink, it will rename the entire URL to Blink with an icon, as described in the wowhead_tooltips variable.
What I want to achieve is:
Any direct URL to Wowhead should be converted into a renamed spell/item.
Any custom URL to Wowhead should be retain it's custom text, but retrieve the tooltip.
This should both be possible on a single page.
The best solution I have come up with is to add an 'if' function to var wowhead_tooltips based on class, then add the class to URLs:
<script>if ($('a').hasClass("wowrename")) { var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": false } }</script>
<a class="wowrename" href="http://www.wowhead.com/spell=1953">Teleport</a>
This works, however, the problem with this solution is that once the script recognizes one URL with the class "wowrename" on the page it will stop renaming all links, meaning that custom URLs and direct URLs can't be mixed on a single page.
Any other solution I've tried, using IDs, defining different variables etc either don't work or come up with the same restriction.
Hence the question, is it possible to change Javascript variables (in this case "var wowhead_tooltips { "renamelinks": false}" per element (URL), based on id, class or anything else?
Direct link that gets renamed with tooltip and iccn.
Teleport
Custom link with tooltip and original text.
I've stored the original link text as a data attribute so we can restore it after it's been changed.
<a class="wowrename" href="http://www.wowhead.com/spell=1953" data-value="Teleport">Teleport</a>
Keep checking for when static.wowhead.com/widgets/power.js changes the last link text. Once changed, restore using the data-value value, remove the styling added that creates the icon and stop the timer.
$(function () {
//timmer
checkChanged = setInterval(function () {
// check for when the last link text has changed
var lastItem = $("a.wowrenameoff").last();
if (lastItem.text() !== lastItem.data('value')) {
$("a.wowrenameoff").each(function () {
//change value
$(this).text($(this).data('value'));
//remove icon
$(this).attr('style', '');
//stop timer
clearInterval(checkChanged);
});
}
i++;
}, 100);
});
This does cause the link icon to flicker on then off, but it is repeated after a page refresh.
JSFiddle demo
This is simple solution. It's not the best way.
var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": true }
$('a').hover(function() {
if ($(this).hasClass('wowrename') {
wowhead_tooltips.renamelinks = true;
}
else {
wowhead_tooltips.renamelinks = false;
}
});
I don't know how exactly wowhead API works, but if wowhead_tooltips variable is loaded exactly in the moment when the user points the link with the mouse (without any timeout) - this can fail or randomly work/not work.
The reason can be that the javascript don't know which function to execute first.
I hope this will work. If it's not - comment I will think for another way.
You have to loop on all the links, like this:
$("a.wowrename").each(function() {
// some code
});

Need workaround for document.getElementById in order to cycle through multiple ID possibilities. Classes not working

I have 30 links in my HTML document, all of which, when clicked, trigger one specific div to change it's id using a js function.
Here are three of the 30 links followed by the single div with the id that changes.
Link 1
Link 2
Link 3
<div id="contain"></div>
Here is the div id change function (working, but not to my liking):
function changediv_1()
{
if (document.getElementById("contain")) {
document.getElementById("contain").setAttribute("id", "contain_1");
}
}
HERE IS THE PROBLEM: When I click Link 1 it changes the div id from "contain" to "contain_1", no problem there. Now the div name is "contain_1", so if I try to click Link 2 after clicking link 1 it won't work, because the div id is now "contain_1" and each function can only call for 1 id.
I need the above function to check for multiple divs (ie: #contain, #contain_1, #contain_2).
ideally like this:
function changediv_2()
{
if (document.getElementById("**contain, contain_1, contain_2, ...**")) {
document.getElementById("**contain, contain_1, contain_2, ...**").setAttribute("id", "contain_x");
}
}
I researched and tried applying .getElementByClass and it did not work - function seemed to only work with an id. There has to be a way around me posting the function 900 (no exaggeration) times to support each situation. Thank you so much for patience and reading my freaking novel of a post.
Try this use data and use on.click instead of inline javascript function
HTML
Link 1
Link 2
Link 3
<div id="contain" class="containDiv"></div>
jQuery
$(function () {
$('a').on('click', function () {
var contain = "contain_" + $(this).data('contain');
$('.containDiv').attr('id', contain);
//contain == contain_(1,2,3)
/*
Rest of your code to read from php and put into contain?
*/
});
});

jQuery, how to keep a div active even using setInterval?

I am working on a comments system and I have made it nice with jQuery, I have a problem. I made it fetch the DB stuff every 2000 miliseconds (2 seconds). And here is the problem, when a user clicks "report comment" another div with a message will show, but after the 2 seconds it disappears, and I'm assuming it's because the setInterval is refreshing the content.
But here is what I've done.
NOTE: I put this part of the code within the while() function in PHP so it loops with all the other comments, and I've assigned them with a uniqueID.
<script type="test/javascript">
$("#<?= $lc['uniqueid']; ?>").click(function() {
$("#report<?= $lc['uniqueid']; ?>").fadeIn();
});
</script>
And here is the script where it refreshes the content ext, (it's on the bottom of my webpage by the way)
setInterval(function() {
$.get('serverinfo.php?showcomments=<?= $id; ?>', function(data) {
$('#showcomments').html(data);
});
}, 2000);
So if anyone would know how to ignore the div that shows up when a user clicks report to be removed, I'd appreciate it! thank you.
A possible solution is conditional update of your content. ie, when user clicks "report comment" add a line
$('#showcomments').addClass("comment-active");
Then make your update conditional:
setInterval(function () {
$.get('serverinfo.php?showcomments=<?= $id; ?>', function (data) {
if (!$('#showcomments').hasClass("comment-active")) {
$('#showcomments').html(data);
}
});
}, 2000);
And to add, of course, delete the class when the report comment is closed.
$('#showcomments').removeClass("comment-active");

Categories