I am using this code:
$(function () {
// For each .bbq widget, keep a data object containing a mapping of
// url-to-container for caching purposes.
$('.bbq').each(function () {
$(this).data('bbq', {
cache: {
// If url is '' (no fragment), display this div's content.
'': $(this).find('.bbq-default')
}
});
});
// For all links inside a .bbq widget, push the appropriate state onto the
// history when clicked.
$('.bbq a[href^=#]').live('click', function (e) {
var state = {},
// Get the id of this .bbq widget.
id = $(this).closest('.bbq').attr('id'),
// Get the url from the link's href attribute, stripping any leading #.
url = $(this).attr('href').replace(/^#/, '');
// Set the state!
state[id] = url;
$.bbq.pushState(state);
// And finally, prevent the default link click behavior by returning false.
return false;
});
// Bind an event to window.onhashchange that, when the history state changes,
// iterates over all .bbq widgets, getting their appropriate url from the
// current state. If that .bbq widget's url has changed, display either our
// cached content or fetch new content to be displayed.
$(window).bind('hashchange', function (e) {
// Iterate over all .bbq widgets.
$('.bbq').each(function () {
var that = $(this),
// Get the stored data for this .bbq widget.
data = that.data('bbq'),
// Get the url for this .bbq widget from the hash, based on the
// appropriate id property. In jQuery 1.4, you should use e.getState()
// instead of $.bbq.getState().
url = $.bbq.getState(that.attr('id')) || '';
// If the url hasn't changed, do nothing and skip to the next .bbq widget.
if (data.url === url) { return; }
// Store the url for the next time around.
data.url = url;
// Remove .bbq-current class from any previously "current" link(s).
that.find('a.bbq-current').removeClass('bbq-current');
// Hide any visible ajax content.
that.find('.bbq-content').children(':visible').hide();
// Add .bbq-current class to "current" nav link(s), only if url isn't empty.
url && that.find('a[href="#' + url + '"]').addClass('bbq-current');
if (data.cache[url]) {
// Since the widget is already in the cache, it doesn't need to be
// created, so instead of creating it again, let's just show it!
data.cache[url].show();
} else {
// Show "loading" content while AJAX content loads.
that.find('.bbq-loading').show();
// Create container for this url's content and store a reference to it in
// the cache.
data.cache[url] = $('<div class="bbq-item"/>')
// Append the content container to the parent container.
.appendTo(that.find('.bbq-content'))
// Load external content via AJAX. Note that in order to keep this
// example streamlined, only the content in .infobox is shown. You'll
// want to change this based on your needs.
.load(url, function () {
// Content loaded, hide "loading" content.
that.find('.bbq-loading').hide();
});
}
});
})
// Since the event is only triggered when the hash changes, we need to trigger
// the event now, to handle the hash the page may have loaded with.
$(window).trigger('hashchange');
});
from here: http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/
It is caching the dynamically loaded content. I want to expire this cache after every 10 seconds. I am not so pro at JQuery. How can I achieve this? Please help!
UPDATE
I tried this code:
<script type="text/javascript" src="jquery.timer.js"></script>
<script type="text/javascript">
var timer = $.timer(function () {
$('.bbq').removeData('.bbq-content');
});
timer.set({ time: 5000, autostart: true });
</script>
The code is reaching $('.bbq').removeData('.bbq-content'); line every 5 seconds, but its not clearing the cache. Unable to show updated results. Please help!
You don't need to clear cached data every 10 seconds; you just need to check whether the cached data is older than 10 seconds before showing it.
First, we need a place to save timestamps for each piece of cached data. Replace the first chunk of code with this:
$('.bbq').each(function () {
$(this).data('bbq', {
cache: {
// If url is '' (no fragment), display this div's content.
'': $(this).find('.bbq-default')
},
cacheTimes: {} // <-- this line is new (plus the comma above)
});
});
Then, when a hashchange event occurs, we need the current time:
// Bind an event to window.onhashchange that, when the history state changes,
// iterates over all .bbq widgets, getting their appropriate url from the
// current state. If that .bbq widget's url has changed, display either our
// cached content or fetch new content to be displayed.
$(window).bind('hashchange', function (e) {
var now = (new Date()).getTime(); // <-- this line is new
// Iterate over all .bbq widgets.
$('.bbq').each(function () {
And for each widget, we check if enough time has elapsed to invalidate the cache:
// Get the url for this .bbq widget from the hash, based on the
// appropriate id property. In jQuery 1.4, you should use e.getState()
// instead of $.bbq.getState().
url = $.bbq.getState(that.attr('id')) || '';
// this chunk is new
if (url !== '' && now - (data.cacheTimes[url] || 0) > 10000) { // 10 seconds
data.url = null;
if (data.cache[url]) {
data.cache[url].remove();
data.cache[url] = null;
}
}
// If the url hasn't changed, do nothing and skip to the next .bbq widget.
if (data.url === url) { return; }
When fetching data, we remember the current time:
// Show "loading" content while AJAX content loads.
that.find('.bbq-loading').show();
data.cacheTimes[url] = now; // <-- this line is new
// Create container for this url's content and store a reference to it in
// the cache.
data.cache[url] = $('<div class="bbq-item"/>')
Related
I have a dijit tree that when a node is clicked it loads an html page in the center content page. One of the html pages is a login page and I'd like to check a cookie to see if they have already logged on, so I can set the page appropriately if the page gets re-loaded. Is there a way to check for a cookie on page load, or perhaps a better method than this? Thanks
my code for the tree is:
TOCSet: function (TOCStore) {
var myModel = new ObjectStoreModel({
store: TOCStore,
query: { root: true }
});
// Create the Tree.
var tree = new Tree({
model: myModel,
onClick: function (item, node, evt) {
// Get the URL from the item, and navigate to it
evt.preventDefault();
var href = item.url;
registry.byId('Content').set('href', href); //set the page on node clicks
}
});
tree.placeAt("TOC");
tree.startup();
ready(function () {
registry.byId("Content").set("href", "Login.htm");//set the login page at start
});
}
I set the cookie using "dojo/cookie" after successful login
function SetLoginCookie(lia) {
cookie("LoggedInAs", lia);
}
and then used "dojo/ready" to check for the cookie when the page reloads
ready(function () {
var lia = cookie("LoggedInAs");
alert(lia + " is logged in");
});
I have list of item IDs on page load:
var itemIds = [1, 5, 10, 11];
IDs are rendered into list and shown to user. I have function which loads detailed information about item, it returns Promise/A.
function loadInfo(id) { ... }
Loading of info for all items is initiated on page load:
val infos = {};
$.each(itemIds, function(i, id) { infos[id] = loadInfo(id); }
Now the problem itself.
When user clicks on item ID:
if item info is loaded, info must be shown
if item info is not yet loaded, it must be shown when it is loaded
Looks easy:
$('li').click(function() {
var id = $(this).data('item-id');
infos[id].then(function(info) { $('#info').text(info); });
});
But if user cliked on another item before current one is loaded, then I have to cancel handler on current item promise and schedule on new one.
How to properly do it?
I have several working solutions (like maintaining currentItemId variable and checking it in promise handler), but they are ugly. Should I look to reactive programming libraries instead?
Kriomant,
I guess there's a number of ways you could code this. Here's one :
var INFOS = (function(){
var infoCache = {},
promises = {},
fetching = null;
var load = function(id) {
if(!promises[id]) {
promises[id] = $ajax({
//ajax options here
}).done(function(info){
infoCache[id] = info;
delete promises[id];
});
}
return promises[id];
}
var display = function(id, $container) {
if(fetching) {
//cancel display (but not loading) of anything latent.
fetching.reject();
}
if(infoCache[id]) {
//info is already cached, so simply display it.
$container.text(infoCache[id]);
}
else {
fetching = $.Deferred().done(function() {
$container.text(infoCache[id]);
});
load(id).done(fetching.resolve);
}
}
return {
load: load,
display: display
};
})();
As you will see, all the complexity is bundled in the namespace INFOS, which exposes two methods; load and display.
Here's how to call the methods :
$(function() {
itemIds = ["p7", "p8", "p9"];
//preload
$.each(itemIds, function(i, id) { INFOS.load(id); });
//load into cache on first click, then display from cache.
$('li').on('click', function() {
var id = $(this).data('item-id');
INFOS.display(id, $('#info'));
});
});
DEMO (with simulated ajax)
The tricks here are :
to cache the infos, indexed by id
to cache active jqXHR promises, indexed by id
to display info from cache if previously loaded ...
... otherwise, each time info is requested, create a Deferred associated with display of the info, that can be resolved/rejected independently of the corresponding jqXHR.
I have this bxslider code.
$(function(){
$('#slider1').bxSlider({
infiniteLoop: false,
hideControlOnEnd: true
});
});
and ihave this ajax code:
$(function () {
$.get('/Scripts/PagedList/PagedList.Mvc.Template.html', function (pagerTemplate) { // get template for pager
// create our pager control object
var pagedList = $.pagedList(
$.template(null, pagerTemplate), // convert into compiled template
function(pageNumber){
return '/home/ajax/#' + pageNumber; // give the pager control the url for loading this page
},
{ pagesToDisplay: 10 } // optional page render options
);
function showNamesAndPagerControl(p) {
$.getJSON("/home/ajaxpage", { page: p ? p : 1 }, function (data) { // default to page 1
$("#namesList")
.attr("start", data.pager.FirstItemOnPage) // update the <li> numbers
.html($("#namesTemplate").tmpl(data.names)); // show the names for this page
$("#namesPager").html(pagedList.render(data.pager)); // update the pager control
}).error(function () {
// if we hit an error (such as a 404), try loading the first page
if (p !== 1) // don't do this if we just tried to load the first page
showNamesAndPagerControl(1);
});
}
// get current url hash (ex: "#3" for page 3)
var hash = window.location.hash;
if (hash)
hash = hash.slice(1); // chop off the leading "#"
// load whatever the currently requested page is
showNamesAndPagerControl(hash);
$(".PagedList-pager a").live("click", function (ev) {
ev.preventDefault(); // don't let the page actually navigate
var pageNumber = $(this).data('page'); // load the pagenumber from the link's data-pager attribute
showNamesAndPagerControl(pageNumber);
window.location.hash = pageNumber; // update the url hash
});
});
});
I want to integrate this ajax to bxslider.
how can i do it?
To use this with ajax is depending on how your data comes back from your server. If it's coming back and has already been formatted on the server side, then you should be able to just do:
$.getJSON({
success:function(data){
$(data).appendTo($('wherever'));
$(data).find('#yourItem').bxSlider();
}
}
If it's not formatted server side, then you just have to format it in your javascript and then apply bxSlider() to it. I feel like maybe I'm not quite getting your question?
If you're still having problems feel free to clarify a little more if you're struggling with the ajax portion of it, or applying the bxslider more.
Today I'm using the built-in cookies of the jsTree in order to preserve user navigations in the tree.
on node click in the tree the user is redirected to the corresponding page in my site and the clicked node is selected/highlighted thanks to the jsTree cookies integration.
Now, I would like to to select/highlight nodes in the tree also based on a navigation among the web site, i.e., a link in the site might also be a node in the tree, for example, a grid of rows that also appears in the tree.
The question is how can I do this 'manually' node selection/highlighting and I also think that I should know from where the user arrived to the page, from the tree or from some other link in the site.
Thanks,
I already built a complete approach for this using jsTree, hashchange event and actual real SEO-able URLs so this would fit into your idea quite simply and you could toss your cookies but not in a bad way. This also works with bookmarking and arriving from a URL as it looks through the nodes then matches the links to select the node. This is best with AJAX though as it should be when possible.
I'm commenting this for you so you can understand it. The working example is here www.kitgui.com/docs that shows all the content.
$(function () {
// used to remove double reload since hash and click are intertwined
var cancelHashChange = false,
// method sets the selector based off of URL input
setSelector = function (path) {
var startIndex = path.indexOf('/docs');
if (startIndex > -1) {
path = path.substr(startIndex);
}
path = path.replace('/docs', '').replace('/', '');
if ($.trim(path) === '') { path = 'overview'; }
return '.' + path;
};
// sets theme without the folders, plain jane
$('.doc-nav').jstree({
"themes": {
"theme": "classic",
"dots": true,
"icons": false
}
}).bind("loaded.jstree", function (event, data) {
// when loaded sets initial state based off of priority hash first OR url
if (window.location.hash) { // if hash defined then set tree state
$.jstree._focused().select_node(selector);
$(setSelector(window.location.hash.substr(1)) + ' a:first').trigger('click');
} else { // otherwise base state off of URL
$.jstree._focused().select_node(setSelector(window.location.pathname));
}
});
// all links within the content area if referring to tree will affect tree
// and jump to content instead of refreshing page
$('.doc-nav a').live('click', function (ev) {
var $ph = $('<div />'), href = $(this).attr('href');
ev.preventDefault();
cancelHashChange = true;
// sets state of hash
window.location = '#' + $(this).attr('href');
$('.doc-content').fadeOut('fast');
// jQuery magic load method gets remote content (John Resig is the man!!!)
$ph.load($(this).attr('href') + ' .doc-content', function () {
cancelHashChange = false;
$('.doc-content').fadeOut('fast', function () {
$('.doc-content').html($ph.find('.doc-content').html()).fadeIn('fast');
});
});
});
// if doc content is clicked and has referring tree content,
// affect state of tree and change tree content instead of doing link
$('.doc-content a').live('click', function (ev) {
ev.preventDefault();
if ($(this).attr('href').indexOf('docs/') > -1) {
$.jstree._focused().select_node(setSelector($(this).attr('href')));
$(setSelector($(this).attr('href')) + ' a:first').trigger('click', false);
}
});
// if back/forward are used, maintain state of tree as if it was being clicked
// refers to previously defined click event to avoid double-duty
// but requires ensuring no double loading
window.onhashchange = function () {
if (cancelHashChange) { cancelHashChange = false; return; }
$.jstree._focused().select_node(setSelector(window.location.hash.substr(1)));
$(setSelector(window.location.hash.substr(1)) + ' a:first').trigger('click', false);
};
$('#top-doc-link').closest('li').addClass('active');
});
Feel free to ask me if you have more questions.
There are menu button ("clients"), tree panel with clients list (sorted by name) and viewer with selected client details. There is also selectionchange action..
My task - on button click switch to client view and select and load details for first client every time button has been clicked. My problem - store is not loaded, how waiting until ext js will autoload data to the store?
my controller code:
me.control({
'#nav-client': {
click: me.onNavClientClick
},
...
'clientlist': {
// load: me.selectClient,
selectionchange: me.showClient
}
});
onNavClientClick: function(view, records) {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...
Two main questions:
is it good solution in my case? (to select first client in tree panel)
var first = me.getClientsStore().first();
// i use another store to get first record because of i dont know how to get first record (on root level) in TreeStore
...
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
i know this code works ok in case of "load: me.selectClient," (but only once),
if i place this code on button click - i see error
Uncaught TypeError: Cannot read property 'id' of undefined
because of me.getClientsListStore() is not loaded.. so how to check loading status of this store and wait some until this store will be completely autoloaded?..
Thank you!
You can listen the store 'load' event. Like this:
...
onNavClientClick: function(view, records) {
var me = this;
// if the store isn't loaded, call load method and defer the 'client view' creation
if (me.getClientsStore.getCount() <= 0) {
me.getClientsStore.on('load', me.onClientsStoreLoad, me, { single : true});
me.getClientsStore.load();
}
else {
me.onClientsStoreLoad();
}
},
onClientsStoreLoad : function () {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...