I'm trying to modify Gaya Design's Tabbed Content (Available Here) to have the current tab persist when the page is reloaded, yet have it change when a new tab is clicked. I've already changed it a little to be able to change default tab by using a PHP GET variable. The current condition of the page I'm working on can be viewed here.
So here's my likely scenario. If you've clicked on the link above, you'll see I'm working on a simple PHP shopping cart. Now when a user clicks an add link, it has to reload the page, and when it does that it resets the tab. So, I'm thinking this should easily be solved with a cookie that updates whenever a new tab is clicked....I'm just not too sure how to go about this. Any thoughts, suggestions, or advice will be greatly appreciated.
Here's my current JS:
var TabbedContent = {
init: function() {
$(".category").click(function() {
var background = $(this).parent().find(".selected");
$(background).stop().animate({
left: $(this).position()['left']
}, {
duration: 350
});
TabbedContent.slideContent($(this));
});
},
slideContent: function(obj) {
var margin = $(obj).parent().parent().find(".sliderContainer").width();
margin = margin * ($(obj).prevAll().size() - 1);
margin = margin * -1;
$(obj).parent().parent().find(".displayContent").stop().animate({
marginLeft: margin + "px"
}, {
duration: 1
});
},
gotab: function( obj ) {
var background = $(obj).parent().find(".selected");
$(background).stop().animate({
left: $(obj).position()['left']
}, {
duration: 1
});
TabbedContent.slideContent( $(obj) );
}
}
$(document).ready(function() {
TabbedContent.init();
});
Here's how a tab is initialized when it is linked to:
<?php
// Load a specific tab if required
if(isset($_GET['tab'])) {
// Array storing possible tab IDs
$tabChoices = array('productsTab', 'specsTab', 'brochuresTab', 'bannersTab', 'kitsTab', 'displaysTab');
$tab = '';
if(in_array($_GET['tab'], $tabChoices)) $tab = $_GET['tab'];
// Default to productsTab if not in array list
else $tab = 'productsTab';
// JS to actually do the switch
echo '<script>$(document).ready(function() {TabbedContent.gotab($("#' . $tab . '"))});</script>';
}
?>
You're painting yourself into a corner by inline scripting a solution. You should always only have one $(document).ready... call in your entire product, in order to avoid order dependent explosions in code, and have a clear point of entry.
That said, you are almost there. Instead of calling a function, assign a value.
echo "<script>var selectedTab=$tab;</script>"
Then during your initialization function, make use of that value. My example is in global scope. There may be a race condition if you try to assign it to a namespace. In that case, try putting that script at the bottom of the page.
One more suggestion, have one and only one function handle all of your animations calls for that object.
Instead of using get/post params you could use hash; creating links like this in the tabs:
<a class="tab_item" href="#one_go" id="one">
And then put this in the javascript:
var gototab = document.location.hash.replace('_go',"")
if(gototab){
$(gototab).each(function(){
var pos = $(this).prevAll(".tab_item").length,
left = pos * $(this).outerWidth(),
margin = pos * $(this).parent().parent().find(".slide_content").width() * -1;
$(this).parent().find('.moving_bg').css('left',left)
$(this).parent().parent().find(".tabslider").css('margin-left',margin)
})
}
Related
I'm trying to implement SEO friendly infinite scrolling in accordance with google's recommendations as seen here (http://scrollsample.appspot.com/items?page=7). I have a jquery function that sends a request to a php file, (which requests the data from the db) anytime someone scrolls to the bottom of the page, now everything is working fine except that when the user scrolls to the bottom of the page, the request function gets fired more than once. So duplicate entries of the data gets loaded into the page, now i know this isn't from my php file because i opened the page directly in my browser and everything was fine. Checkout the bug here http://devx.dx.am/haze/categor.php?artemis=foo&&page=1
I have already tried the solutions here (jQuery .load() callback function fires multiple times) and here ($(window).load() is executing 2 times?) and a few others as well.
$(window).bind('scroll', function() { //#cagorwrap is the div that should contain the data retrieved
if($(window).scrollTop() >= $('#cagorwrap').offset().top + $('#cagorwrap').outerHeight() - window.innerHeight) { //344.6
var queryParameters = {}, queryString = location.search.substring(1),
re = /([^&=]+)=([^&]*)/g, m;
while (m = re.exec(queryString)) {
queryParameters[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
var url2 = "modules/paginate.php?numpages=set";
// #rc is a hidden div too
$("#rc").load(url2, function() {
var rc = $(this).html();
if (queryParameters['page'] < rc) {
queryParameters['page']++;
console.log(rc);
var stateObj = queryParameters['page'];
let cagh = $('#cagorwrap').height() + 344.6 - 75;
$("#cagorwrap").height(cagh);
history.pushState(null, null, "categor.php?artemis=cat&&page="+stateObj);
var url = "modules/paginate.php?artemis=cats&&page="+stateObj;
$("#obtainer").load(url, function () {
$("#cagorwrap").append($(this).html());
}); //#obtainer is a hidden div that receives the data at first before it is appended to #cagorwrap
} else{
//unbind scroll here
}
});
}
});
well if all else fails and you absolutely need a solution, you can add a
counter=1; on the start
and only fire the request function in the case below
counter++;
if (counter%2==0){//fire request}
It's not clean, but if you're loosing too much time with this and want to return to the problem later on...
I need a dynamic form which is supposed to work like this:
When user press "ADD" button, appear a new ..<.div> DOM to select a package.
Depending on the package, the row must change color (by adding/removing some classes).
But I can't get it working. Here is my HTML:
<button onclick='addDay();'>
<div class='content'>
</div>
My Javascript:
//FUNCTION 1: LOAD AJAX CONTENT
function addDay()
{
baseUrl = $('input#helper-base-url').val();
//Set caching to false
$.ajaxSetup ({
cache: true
});
//Set loading image and input, show loading bar
var ajaxLoad = "<div class='loading'><img src='"+baseUrl+"assets/images/loading.gif' alt='Loading...' /></div>";
var jsonUrl = baseUrl+"car/add_day/"+count;
$("div#loading").html(ajaxLoad);
$("div#content").hide();
$.getJSON(
jsonUrl,
{},
function(json)
{
temp = "";
if(json.success==true)
{
temp = json.content;
}
//Display the result
$("div#content").show();
$("div#content").html($("div#content").html()+temp);
$("div#loading").hide();
});
}
//FUNCTION 2: MODIFY AJAX CONTENT
$("#content").on("change", "select.switch", function (e) {
e.preventDefault();
//Get which row is to be changed in background's color
id = this.id;
id = id.substr(6);
//Add class "package1" which change row's background color
row = "row"+id;
row.addClass('package1');
});
My PHP
function add_day($count)
{
$temp = "<div class='row".$count."'>
<select id='switch".$count."' class='switch'>
<option value='1'>Package 1</option>
<option value='2'>Package 2</option>
</select>
</div>";
$result = array(
'success' => true,
'content' => $temp,
);
$json = json_encode($result);
echo $json;
}
PS. The form is not as simple as this but to make the problem solving easier, I remove the details. But I can't seem to change the class on the fly. Do we have a solution or a good work around here?
Edit 1:
Sorry I didn't make myself clear before. I had no problem with getting the id or variable (it was okay, when I alert it the right value comes out - but after I add the class, no color changes is seen). I run it:
a. On button click, load Ajax content.
b. Ajax content (which results contains a ) loaded successfully.
c. FAIL: On change, add class "package1" to the div row. (So, I had no problem with getting the right id or class name. When I alert the variables it gives the right result, BUT the color doesn't change. I can't check whether class is successfully added or not.)
$("#content").on("change", "select.switch", function (e) {
e.preventDefault();
$('.row' + $(this).attr('id').replace('switch', '')).addClass('package1');
});
Assuming that everything else is ok
//Get which row is to be changed in background's color
id = this.id;
id = id.substr(6);
//Add class "package1" which change row's background color
row = "row"+id;
row.addClass('package1');
This is the problem. To get the attibute id you have to do
var id = $(this).attr('id').substr(6);
You have to use $(this) and not this by the way to use all of jQuery functionalities.
Same below
$(row).addClass('package1');
So, full code:
//Get which row is to be changed in background's color
var id = $(this).attr('id').substr(6);
//Add class "package1" which change row's background color
$('.row'+id).addClass('package1');
Changing the class to id solved the problem (using #row0 instead of .row0). Sorry and thank you for your time :)
I have a PHP notification system, and the amount of notifications is put into a DIV using jQuery. The only problem is that when there are 0 notifications, the empty DIV still shows up. This is the jQuery I am currently using:
$(document).ready(function() {
$.get('/codes/php/nf.php', function(a) {
$('#nfbadge').html(a);
$('#nfbadge:empty').remove();
})
});
setInterval(function() {
$.get('http://localhost/codes/php/nf.php', function(a) {
$('#nfbadge').html(a);
$('#nfbadge:empty').remove();
})
}, 8000);
The only problem is that if at document load there is 0 notifications and a notification is added, the badge will not show up, so basically if the element is removed it won't come back unless the page is reloaded, but I made the notification system so that the page wouldn't have to be reloaded. How can I fix this?
.remove() takes the element out of the DOM as well as the content. This is why it doesn't come back unless you reload. Use .fadeOut() or .hide() instead
You should probably do something more like this:
var elm = $('#nfbadge'),
T = setInterval(getCodes, 8000);
function getCodes() {
$.get('/codes/php/nf.php', function(a) {
elm.html(a);
if (elm.is(':empty') && elm.is(':visible')) {
elm.hide();
}else{
elm.show();
}
});
}
Will need some more work on your part, but should get you on the right track!
If you have control over the PHP, you shouldn't be using jQuery to be removing DIVs, it's a waste of resources and load time, even if it's just a few lines of code.
In your PHP template you should include the #nfbadge div in a conditional statement, something like:
if($notifications) {
echo '<div id="nfbadge">';
//notification stuff
echo '</div>';
}
Then with your jQuery code you could do something like the following:
var $nfbadge = $('#nfbadge');
if($nfbadge) {$nfbadge.html(a)}
Why don't you just make the div hidden?
http://www.randomsnippets.com/2008/02/12/how-to-hide-and-show-your-div/
I'm working with jqueries address change event and am hitting a roadblock when a user copies and pastes a URL in the browser. I need to fist load a portion of the page that contains a form. I could do this after every pagination call but it seems really ineffecient.
Here is my current code block:
$.address.change(function(e) {
var urlAux = e.value.split('=');
var page = urlAux[0];
var start = urlAux[1];
if (page == "/visits") {
$.address.title("Profile Views");
if (start) {
$('#start').val(start);
// ***** If a user has copied and pasted this URL with a start value then I first need to load visits.php in the main div tag. Is it possible to see if this is loaded or not?
$.post("visits_results.php", $("#profile_form_id").serialize(),
function(data) {
$('#search_results').html(data);
location.href = "#visits=" + start;
});
}
else {
var args = localStorage.getItem("visits");
$('#main').load("visits.php?" + args, function () { });
}
}
My attempted work around was this:
var args = localStorage.getItem("visits");
$('#main').load("visits.php?" + args, function () {
$('#start').val(start);
$.post("visits_results.php", $("#profile_form_id").serialize(),
function(data) {
$('#search_results').html(data);
location.href = "#visits=" + start;
});
});
There must be a better way...this is realoading the same portion of the page (visits.php) with every pagination event. Is there a better way to load URLs and not have them trigger an address change?
Using paul's work around from his comments, but instead of Regex'ing html content in the visits.php form this solution will look for data() attached to #mainID.
Paul's work around notes:
After a bit more hacking I came up with this solution that seems to do
the trick. I'm not sure how good it is but it seems to do the trick. I
now get the main div id and do a regex match on a unique string in the
form. If I don't see it I load the form and then load the results. Not
sure if this is good practice or not but it seems to solve my issue.
Methodology to use .data() instead of a regex search of visits.php's html:
/*check if we're missing visits.php by looking for data() flag*/
if( !($("#main").data()["hasVisitsPhp"]) ){
var args = localStorage.getItem("visits");
$('#main').load("visits.php?" + args, function () {
$('#start').val(start);
$.post("visits_results.php", $("#profile_form_id").serialize(),
function(data) {
/* we've loaded visits.php, set the data flag on #main*/
$('#main').data("hasVisitsPhp","loaded");
$('#search_results').html(data);
location.href = "#visits=" + start;
});
});
}
try window.location.hash instead. Changing the whole href can/will trigger a whole-page reload, while changing just the hash by itself should at most cause the page to scroll.
Honestly, I'm not even sure the best way to go about this, but essentially, I have a function in an include file that takes a $type parameter and then will retrieve/print results from my db based on the $type passed into it... What I'm trying to do is have a series of links on a page that, when you click on a certain link, will run the function and display the results accordingly...
So, on the initial load of the page, there is a table that displays everything (and I'm simplifying the table greatly...)
<table>
<tr><th>Item</th><th>Type</th></tr>
<tr><td>Milk</td><td>Dairy</td></tr>
<tr><td>Yogurt</td><td>Dairy</td></tr>
<tr><td>Chicken</td><td>Meat</td></tr>
<tr><td>Zucchini</td><td>Vegetable</td></tr>
<tr><td>Cucumber</td><td>Vegetable</td></tr>
</table>
And, then, in a sidebar, I have a series of links:
Dairy
Meat
Vegetable
I'd like to filter the initial table (and back and forth, etc.) based on the link that is clicked, so that if the user clicks "Vegetable", the function from my include file will run and filter the table to show only "Vegetable" types...
The first idea that comes to mind is to add a class attribute to the <tr> tags and id attribs to the <a> tags so that you can easily filter that way:
<tr class="dairy"><td>Milk</td><td>Dairy</td></tr>
<tr class="meat"><td>Chicken</td><td>Meat</td></tr>
Dairy
Meat
Then in your JavaScript (I'm using jQuery here):
$('a').click(function(evt){
var myId = $(this).attr('id');
$('tr').each(function(idx, el){
if ($(el).hasClass(myId))
{
$(el).show();
}
else
{
$(el).hide();
}
});
});
This has the added benefit of allowing you to localize the text without having to change your code.
Ok I created a proper answer. You can do it the way Darrel proposed it. This is just an extension for the paging thing to avoid cookies:
$('a').click(function(evt){
var myId = $(this).attr('id');
// append a idndicator to the current url
var location = "" + document.location + "";
location = location.split('#',1);
document.location = location + '#' + $(this).attr('id');
//append to next and previous links
$('#nextlink').attr({
'href': $('#nextlink').attr('href') + '#' + $(this).attr('id')
});
$('#previouslink').attr({
'href': $('#previouslink').attr('href') + '#' + $(this).attr('id')
});
$('tr').each(function(idx, el){
if ($(el).hasClass(myId))
{
$(el).show();
}
else
{
$(el).hide();
}
});
});
Some code that is executed after page load:
var filter = window.location.hash ? '[id=' + window.location.hash.substring(1, window.location.hash.length) + ']' : false;
if(filter)
$('a').filter(filter).click();
This simulates/executes a click on page load on the link with the specific id.
But in general, if you have a large database, you should filter it directly with SQL in the backend. This would make the displayed table more consistent. For example if page 1 may only have 3 rows of class 'dairy' and on page 2 10 of class 'dairy'.
If youre printing out the whole tabel up front there is no need to go back to the server you can simple hide all teh rows of a given type. For example with jQuery:
$('#sidebar a').click(function(){
// grab the text content of the a tag conver to lowercase
var type = $(this).text().toLowerCase();
/* filter all the td's in the table looking for our specified type then hid the
* row that they are in
*/
$('#my_data_table td').contents().filter(function(){
return this.nodeType == 3 && this.toLowerCase() == type;
}).parent('tr').hide();
return false;
});
Really though the suggestion abotu adding a class to the TR is better because filtering on text content can get tricky if there is content youre not expecting for some reason (hence my conversion to all lower case to help with this).