Change the output automatically without refreshing - javascript

I have this code, it basically changes the word 'article' to 'articles' if the value is '0' or more than '1'. But the word only changes when the page is refreshed. Is it possible to automaticaly re-run the code at the same moment the value (quantity) changes?
<span id="quantity" class="simpleCart_quantity"></span> gets it's value from an external file, it is always a number (like 0, 1, 2, 3, etc.)
<span id="quantity" class="simpleCart_quantity"></span>
<span id="quantityText"></span>
<script type="text/javascript">
$(window).load(function()
{
var quantity = document.getElementById("quantity"),
quantityText = document.getElementById("quantityText");
if (parseInt(quantity.innerHTML, 10) === 1) {
quantityText.innerHTML = "article";
} else {
quantityText.innerHTML = "articles";
}
});
</script>
Thanks in advance!

Yes it's possible.
The direct and dirty way is to poll the server for changes at an interval. make a timer function that calls an ajax function that checks to see if the article count has changed.
something like:
setInterval(function(){
$.ajax({
url:"checkchanges.php",
dataType:"json",
type:'GET',
.success(function(data){
if (data.articlecount>1){ //pseudocode, it depends on how you get your data
$("#quantity").innerHTML="articles";
}
})
});
},3000);
Another method is to use a framework like meteor that wires the checking up for you.

Related

Update div only if a certain conditions holds true

I am writing a simple webserver with micropython.
I want to switch on a relay for a certain duration (given in input by the user from the HTML form).
When the relay is off, I display a div with the input form for the duration and the activation button.
When the relay is on, the same div is replaced with a countdown; when the relay is on I want to refresh the div every second so that the countdown is updated. When the relay is off, I don't want the div to update because otherwise, if you try to input the duration, every second the input number in the box is cleared.
My div is updated by the following script:
<script>
$(document).ready(function () {
setInterval(function () {
$("#div_name").load(window.location.href + " #heatingDiv");
}, 1000);
});
</script>
The div is:
<div id="div_name">
<h1>Title</h1>
insert_content
</div>
The keyword "insert_content" is replaced with the HTML code inside the micropython program (accordingly to the relay state) before the HTML response is sent.
With the previous code everything works fine except for the fact that the div is updated every second even when the relay is off, making it impossible to input the duration in the form.
What I'd like to do is passing an argument to the script similarly as when one uses onClick to call it (I can modify "state" within micropython before sending the response):
<div id="div_name(state)">
<h1>Title</h1>
insert_content
</div>
and the script should look like:
<script>
$(document).ready(function () {
setInterval(function (var state) {
if(state){
$("#div_name").load(window.location.href + " #heatingDiv");
}
}, 1000);
});
</script>
Of course this does not work because id=div_name is not a function call: it is just to give an idea of what I'd like to achieve.
How can I do that?
Why not use a data attribute:
const $div = $("#div_name");
const state = $div.data('state');
if (state) {
setInterval(function() {
$div.load(window.location.href + " #heatingDiv");
}, 1000);
}
// if you are wanting to do the interval to check if the state changes, you could change it around
setInterval(function() {
const state = $div.data('state');
if (state) {
$div.load(window.location.href + " #heatingDiv");
}
}, 1000);
<div id="div_name" data-state="state">
<h1>Title</h1>
insert_content
</div>
Perhaps if you are only wanting to run the load when the state changes, you may be better of with a MutationObserver watching the data attribute instead of a timeout

How to append dynamic data

Basically i have a REST api which return a JSON . In this JSON , it return the last viewed topic. For example
{ lastview : ABC }
So i want to insert this to my page
<div class = 'lastview'>Last viewed topic: </div>
$.getJSON("json link", function(data){
$('<a/>',{
text: data.lastview
}).appendTo('.lastview');
But since this data may change after another topic is viewed. What i mean is if user go to another topic name XYZ , the JSON change lastview from ABC to XYZ but the one in web will not ( still ABC ) because it only execute the function one time when the page loads.
So is there anyway to dynamically check the JSON and return correctly when the content changes ( What i mean is when the lastview topic change to XYZ , the one in div will automatically change to XYZ too)
Thanks
The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.
1000 ms = 1 second.
The function is only executed once. If you need to repeat execution, use the setInterval() method.
setInterval({
$.getJSON("json link", function(data){
$('<a/>',
{
text: data.lastview
}).appendTo('.lastview');
}, 1000);
This is a sample of keep requesting and update every 500ms
setInterval(function() {
// Fake ajax
data = { lastview: "Page " + Math.floor(Math.random() * 3) };
// Just for demo
$("#lastview").empty();
$("#lastview").append(
$("<a></a>").text(data.lastview)
);
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Last viewed topic: <span id="lastview"></span></div>

Node / Express - Append information to list when user hits bottom of page using Snoocore (Reddit API wrapper)

I am working on a private application of a food sub reddit, what I'm retrieving some images witha limit of 20 images per view and when the user reach the bottom of the page it loads more information and appends it, like ajax; I'm doing the request server side and using Snoocore which is an API wrapper for Reddit. Snoocore actually provides a method to fetch information of the next page. From Snoocore's documentation:
// Instead of an HTTP verb, use a Snoocore helper `.listing`
// It will return a "slice" for a listing that has various
// helpers attached to it.
reddit('/r/askreddit/hot').listing().then(function(slice) {
// This is the front page of /r/askreddit
// `slice.children` contains the contents of the page.
console.log(slice.children);
// Get a promise for the next slice in this
// listing (the next page!)
return slice.next();
}).then(function(slice) {
// This is the second page of /r/askreddit
console.log(slice.children);
});
And this is my code:
reddit('/r/food/hot').listing({limit: 10}).then(result => {
for (var x in result.children){
if (result.children[x].data.link_flair_text === '[Homemade]' || result.children[x].data.link_flair_text === '[homemade]') {
if (result.children[x].data.domain !== 'imgur.com') {
if (result.children[x].data.post_hint !== "rich:video") {
titles.push({
'title': he.decode(result.children[x].data.title),
'imgurl': he.decode(result.children[x].data.url),
'user': result.children[x].data.author,
'submission': result.children[x].data.permalink
});
}
}
}
}
console.log(result.children[4].data);
res.render('index', {
'titleArr': titles
});
});
on my Pug template I have:
extends layout
block content
div#wrap
each i in titleArr
figure.figure
img.img-fluid.img-rounded(src= i.imgurl)
figcaption.figure-caption.text-center
p.text-muted #[i #{i.title}]
p
| #[i ―by ]
a(href="http://reddit.com" + i.submission, target="_blank")
| #[i /u/#{i.user}]
listing({limit: 10}) here is important because, well, it limits the post retrieved; actually I'm retrieving only 10, by default it retrieves 25; anyway, I'm looking for a way, how i said that when the user reach bottom of the page it loads more post; do I have to do this via client side? Or can I do this via server side in some way? Tell me if I need to explain my issue more in depth.
What you are looking for is "infinite scrolling", you basically want to do another request when your user reaches the bottom of the page that has been rendered.
This is going to require you to fire an ajax request when your browser scroll reaches the bottom of the page. If you were to use jQuery, your code would look something like this:
$(document).ready(function() {
var win = $(window);
var parts = location.pathname.split("/");
// assuming a url like domain.com/reddit/10 where 10
// is the total number of posts you're showing
var pageNumber = parts[3]; //this gives you access to the `10`
// then add 10 to the current page number and
pageNumber += 10
// use that for your ajax request
var url = "http://domain.com/reddit/"+pageNumber;
// Each time the user scrolls
win.scroll(function() {
// End of the document reached?
if ($(document).height() - win.height() == win.scrollTop()) {
$('#loading').show();
$.ajax({
url: url,
dataType: 'json',
success: function(json) {
// do something with your json of your posts
// then hide the loading gif or image.
$('#loading').hide();
}
});
}
});
});
This will fire the ajax request whenever your user reaches the bottom of the page, and paginate correctly. This is only the browser side, though.
You will need to edit your server endpoint slightly as well.
For example, you need to increase your limit dynamically
//you could use the req.params method from express to accomplish this
reddit('/r/food/hot').listing({limit: req.params.limit}).then(result => {
for (var x in result.children){
if (result.children[x].data.link_flair_text === '[Homemade]' || result.children[x].data.link_flair_text === '[homemade]') {
if (result.children[x].data.domain !== 'imgur.com') {
if (result.children[x].data.post_hint !== "rich:video") {
titles.push({
'title': he.decode(result.children[x].data.title),
'imgurl': he.decode(result.children[x].data.url),
'user': result.children[x].data.author,
'submission': result.children[x].data.permalink
});
}
}
}
}
console.log(result.children[4].data);
res.render('index', {
'titleArr': titles
});
});
Accessing the req.params.limit variable should work. You will need to edit your endpoint definition as well. I'm not sure how you have your server's routing setup right now, but this would be one way you could do it:
app.get('/reddit/posts/:limit', function(req, res) {
console.log('limit is: ', req.params.limit);
})
The idea here is that you want to increase the number of items you're fetching with each jQuery request. this is a pretty quick and dirty way of doing so, and I'm making some assumptions about how you're handling the server and what you're using, but this should get you 90% of the way there. Hope this helps!

How do you refresh an HTML5 datalist using JavaScript?

I'm loading options into an HTML5 datalist element dynamically. However, the browser attempts to show the datalist before the options have loaded. This results in the list not being shown or sometimes a partial list being shown. Is there any way to refresh the list via JavaScript once the options have loaded?
HTML
<input type="text" id="ingredient" list="ingredients">
<datalist id="ingredients"></datalist>
JavaScript
$("#ingredient").on("keyup", function(event) {
var value = $(this).val();
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").empty();
for (var i in ingredients) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
// Trigger a refresh of the rendered datalist
}
});
});
Note: In Chrome and Opera, the entire list is only shown if the user clicks on the input after entering text. However, I'd like the entire list to appear as the user types. Firefox is not a problem, as it appears to refresh the list automatically when the options are updated.
UPDATE
I'm not sure this question has a satisfactory answer, as I believe this is simply a shortcoming of certain browsers. If a datalist is updated, the browser should refresh the list, but some browsers (including Chrome and Opera) simply do not do this. Hacks?
Quite a long time after question but I found a workaround for IE and Chrome (not tested on Opera and already OK for Firefox).
The solution is to focus the input at the end of success (or done) function like this :
$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
url: "/api/ingredients",
data: { search: value.length > 0 ? value + "*" : "" },
success: function(ingredients) {
$("#ingredients").empty();
for (var i in ingredients) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
// Trigger a refresh of the rendered datalist
// Workaround using focus()
_this.focus();
}
});
It works on Firefox, Chrome and IE 11+ (perhaps 10).
I had the same problem when updating datalist.
The new values would not show until new input event.
I tried every suggested solutions but nothing using Firefox and
updating datalist via AJAX.
However, I solved the problem (for simplicity, I'll use your example):
<input type="text" id="ingredient" list="ingredients" **autocomplete="off"**>
<datalist id="ingredients"></datalist>
$("#ingredient").on("**input**", function(event) { ....}
Autocomplete and input is the couple that solve my problems and it works with Chrome too.
You can probably eliminate the problem if you don't make AJAX request on every key stroke. You can try throttle technique using set/cleatTimeout to issue request after 500ms after the last char typed:
$("#ingredient").on("keyup", function(event) {
clearTimeout($(this).data('timeout'));
$(this).data('timeout', setTimeout($.proxy(function() {
var value = $(this).val();
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").empty();
for (var i = 0; i < ingredients.length; i++) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
}
});
}, this), 500));
});
Yoyo gave the correct solution, but here's a better way to structure your inserts into the DOM.
$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
url: "/api/ingredients",
data: { search: value.length > 0 ? value + "*" : "" },
success: function(ingredients) {
var options = ingredients.map(function(ingredient) {
var option = document.createElement('option');
option.value = ingredient.name;
return option;
});
$("#ingredients")
.empty()
.append(options);
// Trigger a refresh of the rendered datalist
// Workaround using focus()
_this.focus();
}
});
Less DOM manipulation
With this refinement, I'm only inserting into the DOM a single time per each successful callback. This cuts down on the browser needing to re-render, and will help improve any "blips" in the view.
Functional Programming and Less Idiomatic jQuery
Here we are using the Array.prototype.map to clean up some of the jQuery and make things a bit less idiomatic. You can see from the ECMA Chart that this function will work in all browsers you are targeting.
Not Hacky
This by no means is hacky. IE appears to be the only browser that doesn't automatically refresh the input to display the new list options. focus() is just a way to ensure the input is refocused which forces a refresh of the view.
This solution works very well in all of the browsers that my company has to support internally, IE10+ Chrome and Firefox.
Place your #ingredients element is inside #container and try this code:
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").remove();
var item = $('<datalist id="ingredients"></datalist>');
for (var i in ingredients) {
item.append("<option>"+ ingredients[i].name +"</option>");
}
item.appendTo('#container');
}
});
even better without #container and using jQuery replaceWith():
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
var item = $('<datalist id="ingredients"></datalist>');
for (var i in ingredients) {
item.append("<option>"+ ingredients[i].name +"</option>");
}
$("#ingredients").replaceWith(item);
}
});
Your issue is that the AJAX is asynchronous.
You'd actually have to have a callback for the AJAX which you call onSuccess which would then update the datalist. Of course, then you might not have great performance/still have a "skipping" behavior, where your datalist options are lagging behind.
If your list of items from the AJAX isn't too large, you should:
1. load the ENTIRE list into memory array with the first query, then...
1. use a filtering function that is applied to the array each time you have a keyUp event.
I found a solution tested only on GNOME Web (WebKit) that consist on set the 'list' attribute of the input element to empty string and, inmediately after, set it again with the id of the datalist element. Here is the example, supose that your input element is stored in a variable named input_element:
var datalist = document.getElementById(input_element.list.id);
// at this point input_element.list.id is equals to datalist.id
// ... update datalist element here
// And now the trick:
input_element.setAttribute('list','')
input_element.setAttribute('list',datalist.id)

Can't get sessionStorage to work correctly

I have multiple buttons that when they are clicked an image is loaded and the image is supposed to stay there based even when the page refreshes. When I use this the button with the highest setItem value always shows even if I click on other button. How do I fix this?
here is one of the scripts:
<script type="text/javascript">
var isImage1 = sessionStorage.getItem('2');
function showImage1() {
sessionStorage.setItem('isImage1', '2');
$("#loadingImage1").show();
$("#loadingImage").hide();
$("#loadingImage2").hide();
$("#loadingImage3").hide();
$("#loadingImage4").hide();
$("#loadingImage5").hide();
$("#loadingImage6").hide();
}
if(isImage1 == 2) showImage1();
</script>
and here is one of my buttons:
<input name="EPL/MECH DESIGN - TECHS" style="white-space:normal"
onclick="moveText(this.name);showImage1();form1.submit()"
style="width: 275px" type="button" value="7SBD EPL/Mech. Design Techs" />
Update: I have updated this line
var isImage1 = sessionStorage.getItem('2');
to
var isImage1 = sessionStorage.getItem('isIamge1');
but my issue still exists, that the isImage with the largest value stays even when i click the other buttons, so help is still needed.
In your session storage, you are setting the value of the 'isImage1' Item to '2'
sessionStorage.setItem('isImage1', '2');
But in your code to retrieve the value you are actually retrieving the item '2'
var isImage1 = sessionStorage.getItem('2');
You need to change your sessionStorage.getItem to reference 'isImage1'
var isImage1 = sessionStorage.getItem('isImage1');
Then you should get the value you are expecting.
There are loads of good jsfiddles on session storage. you may get some ideas from this one:
http://jsfiddle.net/gabrieleromanato/XLRAH/
Incidently; this is a very small value you are storing, why not store it in a cookie instead?
EDIT:
based on the fact that you have multiple functions exactly like this one, you are better off following Ken's solution, the only thing I would add is a wildcard to turn off the other images:
function showImage(imgNum) {
sessionStorage.setItem('Image',imgNum);
$("[id^=loadingImage]").hide();
$("#loadingImage" + imgNum).show();
}
showImage(sessionStorage.getItem('Image'));
The code in the buttons would then be showImage(1) instead of showImage1();
_Pez
By re-factoring the code a little you can do something like this:
/// setup some vars including max number of images
var maxImages = 6, i = 1, v;
/// now loop through and get the items for each image
for(; i =< maxImages; i++) {
v = sessionStorage.getItem('isImage' + i);
/// if in storage, call show image with the number to show
if (v !== null) showImage(i);
}
/// show image based on number
function showImage(num) {
sessionStorage.setItem('isImage' + num, '1');
$("#loadingImage" + num).show();
}
Also note that sessionStorage only deals with strings. So in order to check a specific number you need to convert it to one first parseInt(value, 10);.
But in this case the 1 that we set can be anything - it's just to store some value so sessionStorage doesn't return null.
In the button code you can change it to do this:
<input name="EPL/MECH DESIGN - TECHS" style="white-space:normal"
onclick="moveText(this.name);showImage(1);form1.submit()"
style="width: 275px" type="button" value="7SBD EPL/Mech. Design Techs" />

Categories

Resources