Loading data at end of scroll in jquery mobile - jquery-mobile

Am using dataprovider object to show the list with 25 records at a time and instead of pagination, i want to show next page at end of scroll using the following code.
But is there any better way instead of window.location.href
if not, is there any option to show the loading message till the page loads.
$(document).ready(function()
{
$('#content').bind('scroll', function ()
{
totalDivHeight = eval($('#content')[0].scrollHeight) - eval($('#content').height());
scrollPosition =eval($('#content').scrollTop())+25;// + eval($('#content').height());
if (scrollPosition >= totalDivHeight)
{
nextPageID = eval("<?= $nextPageID; ?>");
prevPageID = eval("<?= $prevPageID; ?>");
totalPages = eval("<?= $totalPages; ?>");
if (nextPageID < totalPages)
window.location.href='<?php echo $url;?>'+'&Store_page='+nextPageID;
}
});
});
Edit: i tried ajax function instead of window.location.href but i dont know how to send the pagenumber variable to the provider?

You are probably looking to lazy load content and attach to the end of the table and you do that via ajax.
You should not reinvent the wheel others already have done this, just one of the implementations is here:
http://dcarrith.github.com/jquery.mobile.lazyloader/

Related

How to stop jQuery Mobile calling $.mobile.loading('hide') during changePage?

I'm trying to stop jQuery Mobile hiding the loading spinner when changePage is called.
The program flow goes like this, starting with clicking a link, which has its click event defined like this:
$('body').delegate('.library-link', 'click', function() {
$.mobile.loading( 'show' );
$.mobile.changePage($('#page-library'));
return false;
});
Upon clicking the link, the pagebeforeshow event is fired, which triggers a function to populate the page from the local storage, or else make an ajax call to get the data.
$(document).on('pagebeforeshow', '#page-library', function(event){
ui.populate_data();
});
In ui.populate_data() we get the data from local storage or make an ajax call.
ui.populate_data = function() {
if (localdata) {
// populate some ui on the page
$.mobile.loading( 'hide' );
} else {
// make an ajax call
}
};
If the data is there, we load the data into the container and hide the loading spinner. If not it makes the ajax call, which on complete saves the data in local storage, and calls ui.populate_data()
The problem is, after the pagebeforeshow event is finished, changePage is calling $.mobile.loading( 'hide' ), even though the data might not be there yet. I can't find any way to prevent changePage from hiding the spinner, other than by temporarily redefining $.mobile.loading, which feels pretty wrong:
$('body').delegate('.library-link', 'click', function() {
$.mobile.loading( 'show' );
loading_fn = $.mobile.loading;
$.mobile.loading = function() { return; };
$.mobile.changePage($('#page-library'), {showLoadMsg: false});
return false;
});
and before hiding the spinner in my ui function:
ui.populate_data = function() {
if (localdata) {
// populate some ui on the page
if (typeof loading_fn === 'function') {
$.mobile.loading = loading_fn;
}
$.mobile.loading( 'hide' );
} else {
// make an ajax call
}
};
Surely there must be a way to get complete control over the showing and hiding of the loading widget, but I can't find it. I tried passing {showLoadMsg: false} to changePage, but as suggested by the docs it only does things when loading pages over ajax, which I'm not doing.
Maybe it's too much for many, but I found a solution other than the written in the comments (which didn't work for me).
I use the jquery mobile router and in the 'show' event of a page, I do $.mobile.loading("show");, so when the page appears it does with the loading spinner showing.
Though to hide the spinner, I had to use $('.ui-loader').hide();, which is weird, I know...
I use Jquery Mobile Router for a lot more, but it solved this issue.
(Maybe just listening to the proper event and triggering the spinner would also work, as this is what JQMR does...)
I'm using JQM 1.4.2...

Drag and Drop with Angular JS and JQuery

Couple of days ago I found this interesting post at http://www.smartjava.org/content/drag-and-drop-angularjs-using-jquery-ui and applied it into my website. However when I progressively using it there is a bug I identified, basically you can not move an item directly from one div to another's bottom, it has to go through the parts above and progress to the bottom. Anyone can suggest where does it goes wrong? The example is at http://www.smartjava.org/examples/dnd/double.html
Troubling me for days already.....
I did this a bit differently. Instead of attaching a jquery ui element inside the directive's controller, I instead did it inside the directive's link function. I came up with my solution, based on a blog post by Ben Farrell.
Note, that this is a Rails app, and I am using the acts_as_list gem to calculate positioning.
app.directive('sortable', function() {
return {
restrict: 'A',
link: function(scope, elt, attrs) {
// the card that will be moved
scope.movedCard = {};
return elt.sortable({
connectWith: ".deck",
revert: true,
items: '.card',
stop: function(evt, ui) {
return scope.$apply(function() {
// the deck the card is being moved to
// deck-id is an element attribute I defined
scope.movedCard.toDeck = parseInt(ui.item[0].parentElement.attributes['deck-id'].value);
// the id of the card being moved
// the card id is an attribute I definied
scope.movedCard.id = parseInt(ui.item[0].attributes['card-id'].value);
// edge case that handles a card being added to the end of the list
if (ui.item[0].nextElementSibling !== null) {
scope.movedCard.pos = parseInt(ui.item[0].nextElementSibling.attributes['card-pos'].value - 1);
} else {
// the card is being added to the very end of the list
scope.movedCard.pos = parseInt(ui.item[0].previousElementSibling.attributes['card-pos'].value + 1);
}
// broadcast to child scopes the movedCard event
return scope.$broadcast('movedCardEvent', scope.movedCard);
});
}
});
}
};
});
Important points
I utilize card attributes to store a card's id, deck, and position, in order to allow the jQuery sortable widget to grab onto.
After the stop event is called, I immediately execute a scope.$apply function to get back into, what Misko Hevery call,s the angular execution context.
I have a working example of this in action, up in a GitHub Repo of mine.

jQuery UI Accordion - does refresh method overwrites initialisation settings?

Currently I am working on a project for which I use the jQuery UI Accordion.
Therefore I initialise the accordion on an element by doing
<div id="accordion"></div>
$('#accordion').accordion({
collapsible: true,
active: false,
heightStyle: "content"
});
After init the accordion I append some data coming from an AJAX request. (depends on user interaction)
In a simplified jsfiddle - which does exact the same thing as the ajax call - you can see how this looks like.
So far it seems to be working quite well but there is one problem I face.
In my initialisation I say that I want all panels to be closed but after calling refresh on the accordion everything of those settings seems to be gone and one panel opens.
Note that I implemented jQuery UI v1.10.2 in my fiddle. Update notes say
The refresh method will now recognize panels that have been added or removed. This brings accordion in line with tabs and other widgets that parse the markup to find changes.
Well it does but why has it to "overwrite" the settings I defined for this accordion?
I also thought about the possibility that it might be wrong to create the accordion on an empty <div> so I tested it with a given entry and added some elements afterwards.
But the jsfiddle shows exactly the same results.
In a recent SO thread I found someone who basically does the same thing as I do but in his jsfiddle he faces the same "issue".
He adds a new panel and the first panel opens after the refresh.
My current solution for this issue is to destroy the accordion and recreate it each time there's new content for it.
But this seems quite rough to me and I thought the refresh method solves the need to destroy the accordion each time new content gets applied.
See the last jsfiddle
$(document).ready(function () {
//variable to show "new" content gets appended correctly
var foo = 1;
$('#clickMe').on('click', function () {
var data = '';
for (var i = 0; i < 3; i++) {
data += '<h3>title' + foo + '</h3><div>content</div>';
foo++;
}
if ($('#accordion').hasClass('ui-accordion')) {
$('#accordion').accordion('destroy');
}
$('#accordion').empty().append(data).accordion({
collapsible: true,
active: false,
heightStyle: "content"
});
});
});
Unfortunately it is not an option for me to change the content of the given 3 entries because the amount of panels varies.
So my questions are the one in the title and if this behaviour is wanted like that or if anybody faces the same problem?
For the explanation of this behaviour, have a look in the refresh() method of the jquery-ui accordion widget, the problem you are facing is at line 10 :
refresh: function() {
var options = this.options;
this._processPanels();
// was collapsed or no panel
if ((options.active === false && options.collapsible === true) || !this.headers.length) {
options.active = false;
this.active = $();
// active false only when collapsible is true
} if (options.active === false) {
this._activate(0); // <-- YOUR PROBLEM IS HERE
// was active, but active panel is gone
} else if (this.active.length && !$.contains(this.element[0], this.active[0])) {
// all remaining panel are disabled
if (this.headers.length === this.headers.find(".ui-state-disabled").length) {
options.active = false;
this.active = $();
// activate previous panel
} else {
this._activate(Math.max(0, options.active - 1));
}
// was active, active panel still exists
} else {
// make sure active index is correct
options.active = this.headers.index(this.active);
}
this._destroyIcons();
this._refresh();
}

JQuery .on() making only every other element appended clickable

I've just recently been studying JQuery to use on a personal website. Something I wanted to add to the website was a blog preview feature, which uses AJAX and JSON to retrieve the title and preview text of a blog post. When a visitor clicks the blog tab, JQuery retrieves the information and is displaying the titles the way I want it to. The titles are supposed to be clickable, so that when you click a title the preview text is shown. For the most part I have this working by using JQuery's .on() function, however for whatever reason only every other title is clickable. Here is the code:
$(document).ready(function() {
function handleSelect(event, tab) {
if (tab.index == 1) {
$("#blogContent").empty();
$.getJSON("/TimWeb/blogPreview", function(data) {
$.each(data, function(i) {
$("#blogContent").append("<h3 class=head>" +
data[i].blogTitle + "</h3>" +
"<p>" + data[i].blogBody + "</p>");
$("#blogContent .head").on("click", function() {
$(this).next().toggle();
}).next().hide();
});
});
}
}
var tabOpts = {
select:handleSelect
};
$(".tabs").tabs(tabOpts);
});
For a more visual description of the problem, if I have eight blog posts that are being previewed, the title for each will be rendered appropriately, with the content hidden. If I try clicking the first, third, fifth, or seventh title, nothing happens. If I click the second, fourth, sixth, or eighth titles, the post preview will appear. If I click it again, it will be hidden, as I expect it to be.
In case it causes any confusion, blogContent is the id of the div referenced by the jQuery tab for the blog section. I would greatly appreciate any advice or wisdom you could lend me!
You don't need to attach the event to each individual h3.
.on() can be used to attach a function to an event for everything, both now and in the future, that match a selector (jQuery 1.7+).
Try taking the .on() out of the each loop (and the function), hide the p tag via style="display:none;" and place this after the function:
$(document).on("click", "#blogContent .head", function(){ $(this).next().toggle(); });
Something like this:
function handleSelect(event, tab) {
if (tab.index == 1) {
$("#blogContent").empty();
$.getJSON("/TimWeb/blogPreview", function(data) {
$.each(data, function(i) {
$("#blogContent").append("<h3 class=head>" +
data[i].blogTitle + "</h3>" +
"<p style='display:none;'>" + data[i].blogBody + "</p>");
});
});
}
}
// This only needs to be executed once.
$(document).on("click", "#blogContent .head", function(){ $(this).next().toggle(); });
I would suggest moving your on statement outside of the each statement. Per jQuery:
If new HTML is being injected into the page, select the elements and
attach event handlers after the new HTML is placed into the page. Or,
use delegated events to attach an event handler, as described next.
http://api.jquery.com/on/
So something like this:
function handleSelect(event, tab) {
if (tab.index == 1) {
$("#blogContent").empty();
$.getJSON("/TimWeb/blogPreview", function(data) {
$.each(data, function(i) {
$("#blogContent").append("<h3 class=head>" +
data[i].blogTitle + "</h3>" +
"<p>" + data[i].blogBody + "</p>");
$("#blogContent .head").next().hide();
});
$("#blogContent .head").on("click", function() {
$(this).next().toggle();
});
});
}
}
If this is something that happens multiple times you would be better served using the delegated approach outlined by Jay and setting the event on they body outside of all functions (excepting document.ready).

jquery tabs back button

This post talks about the problem that jQuery tabs is still having with the back button. What the customer needs is fairly simple - when they press back, they want to go back to what they were just looking at. But jQuery tabs loads the first tab, not the one that was selected when the user left the page.
I've read the accompanying link and it says "It is planned and Klaus is working on it whenever he finds the time."
Has anyone solved the back button problem with jQuery UI tabs?
Using the solution to the history problem easement posted, a dirty fix for the back button problem would be to periodically check the location.hash to see if it has changed, and if it has, fire the click event of the appropriate link.
For example, using the zachstronaut.com updated jQuery Tabs Demo, you could add this to the $(document).ready callback, and it would effectively enable the back button to switch tabs, with no more than a 500ms delay:
j_last_known_hash = location.hash;
window.setInterval(function() {
if(j_last_known_hash != location.hash) {
$('#tabs ul li a[href="'+ location.hash +'"]').click();
j_last_known_hash = location.hash;
}
}, 500);
Have you tired updating the browsers location as you switch tabs?
http://www.zachstronaut.com/posts/2009/06/08/jquery-ui-tabs-fix.html
if you had a class on your tab container that was tabContainer, to update the url when user clicks a tab, you could do this:
$(".tabContainer").tabs({
select: function(event, ui) {
window.location.hash = ui.tab.hash;
}
});
then, instead of firing click, you could use the tabs select method if you have some getIndexForHash method that can return the right tab number for the selected hash value:
var j_last_known_hash = location.hash;
window.setInterval(function() {
var newHash = location.hash;
if(j_last_known_hash != newHash) {
var index = getIndexForHash(newHash);
$('.tabContainer').tabs("select",index);
j_last_known_hash = newHash;
}
}, 100);
window.onhashchange = function () {
const $index = $('a[href="' + location.hash + '"]').parent().index();
$('.tabContainer').tabs('option', 'active', $index);
}

Resources