Reputation: 53
I am using a JQuery cookie library to hide/show elements and then remember the status when the page is reloaded. The working code looks for elements with id #num0 and toggles the next element, and it looks like this:
if(Cookies('divShown0') == 'true') { //defaults to hidden
$('#num0').next().show(); // Show if cookie there and 'true'
}
$('#num0').click(function() {
$(this).next().toggle();
if(Cookies('divShown0') == 'true') {
Cookies.set('divShown0', 'false'); // Remember it was hidden
}
else {
Cookies.set('divShown0', 'true'); // Remember it was shown
}
});
I have multiple of these, each identified by a different #num and stored as a different divShown number. So far I have just added a new code block with new numbers, but obviously this takes up a lot of space. I put the first if() statement into a for() loop, no problem. The second part I broke into a function, toggleShown(num), so I can call $('#num0').click(toggleShown(0));
, but this is not working. I suspect that something about the $(this) element isn't properly identifying the next element, but I really don't know.
function toggleShown(num)
{
$(this).next().toggle();
if(Cookies('divShown' + num) == 'true') {
Cookies.set('divShown' + num, 'false'); // Remember it was hidden
}
else {
Cookies.set('divShown' + num, 'true');
}
}
I don't really do Javascript or JQuery, mostly RoR but I am trying to hack this together. Any thoughts on what I am screwing up?
Upvotes: 1
Views: 61
Reputation: 1074435
The second part I broke into a function, toggleShown(num), so I can call
$('#num0').click(toggleShown(0));
, but this is not working.
You can do
$("#num0").click(toggleShown);
...for just one of them, or
$("[id^=num]").click(toggleShown);
...for all of them at once. (^=
means "starts with", so that would be "all elements with an id
attribute starting with num
"). If you need to weed out ones with other id
s (like number
):
$("[id^=num]").filter(function() {
return this.id.match(/^num\d+$/);
}).click(toggleShown);
Either way, you then keep using this
within toggleShown
, and get the index number from the end of this.id
:
function toggleShown() {
var divName = "divShown" + /\d+$/.exec(this.id)[0];
$(this).next().toggle();
if (Cookies(divName) == 'true') {
Cookies.set(divName, 'false'); // Remember it was hidden
} else {
Cookies.set(divName, 'true');
}
}
Live Example:
$("[id^=num]").click(toggleShown);
function toggleShown() {
var divName = "divShown" + /\d+$/.exec(this.id)[0];
$("#" + divName).toggleClass("on");
}
.on {
color: blue;
}
<div>Click any of the "num"s, and its corresponding "divShown" toggles between blue and normal text</div>
<div id="num0">num0</div>
<div id="num1">num1</div>
<div id="num2">num2</div>
<div id="num3">num3</div>
<hr>
<div id="divShown0">divShown0</div>
<div id="divShown1">divShown1</div>
<div id="divShown2">divShown2</div>
<div id="divShown3">divShown3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Alternately, you can use Function#bind
or jQuery.proxy
to bind the index to toggleShown
, and then use e.currentTarget
for this
:
$("#num0").click(toggleShown.bind(null, "0"));
then:
function toggleShown(num, e) {
$(e.currentTarget).next().toggle();
if (Cookies('divShown' + num) == 'true') {
Cookies.set('divShown' + num, 'false'); // Remember it was hidden
} else {
Cookies.set('divShown' + num, 'true');
}
}
Upvotes: 0
Reputation: 6323
If you are going to have multiple similar div
s, instead of just IDs, you could assign a class to all of them and let jQuery add click listeners to all of them at once.
You can then either read the div ID from the ID itself, or you could give each a data
attribute.
HTML:
<button class="toggle" data-id="1">First</button>
<button class="toggle" data-id="2">Second</button>
<button class="toggle" data-id="3">Third</button>
<div id="div1">First</div>
<div id="div2">Second</div>
<div id="div3">Third</div>
Javascript:
$('.toggle').click(function(){
var id = $(this).data('id');
hideOrShow(id);
})
function hideOrShow(id){
$('#div'+id).toggle();
}
Upvotes: 0
Reputation: 4443
You need to add a handler for each DOM element anyway, so you can use something like this:
function addHandler(num) {
$('#num' + num).click(function() {
$(this).next().toggle();
var cookieName = 'divShown' + num;
if (Cookies(cookieName) == 'true') {
Cookies.set(cookieName, 'false'); // Remember it was hidden
}
else {
Cookies.set(cookieName, 'true'); // Remember it was shown
}
});
}
for (var num = 0; num < numDivs; ++num) {
addHandler(num);
}
Upvotes: 1
Reputation: 3739
You can set the this
argument of a function by calling the function through Function.prototype.call(). The first parameter passed will be assigned as this
inside the function.
Upvotes: 0
Reputation: 3763
You hunch is correct! $(this)
inside of your function does not hold the reference to the original element, because you are in a new function with a new scope.
All you should have to do is change:
$(this).next().toggle();
to
$("#num" + num).next().toggle();
Upvotes: 1