Add/Remove multiple classes on multiple elements simultaneously - javascript

What I'm trying to achieve is using a single element, by onclick, is add and remove 2 class names on 2 independent elements simultaneously.
Here is my element I'm using to trigger the js/jquery.
<div class="top-tool-buttons"></div>
Then once clicked turn these elements from this (menu_hide & lockscreen_on):
<div id="somename1" class="list-nav menu_hide"></div>
<div id="somename2" class="screen lockscreen_off"></div>
to this (menu_show & lockscreen_off):
<div id="somename3" class="list-nav menu_show"></div>
<div id="somename4" class="screen lockscreen_on"></div>
Jquery/JS
document.getElementById('#myElementId').addEventListener('click', function() {
.removeClass('menu_hide lockscreen_on').addClass('menu_show lockscreen_off');
}, false);
document.getElementById('#myElementId').addEventListener('click', function() {
.removeClass('menu_show lockscreen_off').addClass('menu_hide lockscreen_on');
}, false);
Open to better practices too as I'm trying to achieve unnoticeable page loading.

You are worrying too much about changing multiple attributes causing screen flickers etc. All these operations will complete in sequence before the page renders :)
You can simplify your code using jQuery though:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/7b75Q/
$('#myElementId').click(function(e) {
e.preventDefault();
// Toggle all 4 classes off or on
$('#somename1').toggleClass('menu_hide menu_show');
$('#somename2').toggleClass('lockscreen_on lockscreen_off');
});
As noted you must have unique ids for elements. Thanks for updating your example. Have adjusted answer to suit.

You don't need to create new elements to do this.
$('#myElementId').on('click',function() {
if($("showname1").hasClass("menu_hide")){
$("#showname1").removeClass("menu_hide").addClass("menu_show");
$("#showname2").removeClass("lockscreen_off").addClass("lockscreen_on");
} else {
$("#showname1").removeClass("menu_show").addClass("menu_hide");
$("#showname2").removeClass("lockscreen_on").addClass("lockscreen_off");
}
});

Related

Toggling between two divs using Polymer

I ran into a issue where using polymer I would like to toggle through two divs, the problem I have is, I want to use the polymer standard of toggling where they use: hidden?="{{toggleMe}}" as a attribute on the div and just bind it then make a function that would do the toggling or the show/hide that will look like this:
<div hidden?="{{divOne}}">TEST</div>
<div hidden?="{{divTwo}}">TEST2</div>
<a on-tap="{{change}}">Toggle</a>
<script>
Polymer('componentName',{
change: function(){
this.divOne = !this.divOne;
this.divTwo = !this.divTwo;
}
})
</script>
This above will show both and hide both together, I want the one displayed and the other hidden, So essentially switching between the two while starting with the one hidden and the other active, and then swapping states from there.
I tried this also with no luck as I can't do this or use the '!' on the left hand side:
!this.divOne = this.divOne;
this.divTwo = !this.divTwo;
Thanks for reading
this.divOne = !(this.divTwo = this.divOne);
I have found a fix to the question, i assigned true and false values to the bind hidden values before I used them (this assigns a true for hidden state and false for the separate values), Then when clicking on the toggle bind I just used the code of #Zikes to have the toggle work(thanks for that).
current working code
<div hidden?="{{divOne}}">TEST</div>
<div hidden?="{{divTwo}}">TEST2</div>
<a on-tap="{{change}}">Toggle</a>
<script>
Polymer('componentName',{
divOne: false,
divTwo:true,
change: function(){
this.divOne = !(this.divTwo = this.divOne);
}
})
</script>
Hope this can help clear someone in the future

Basic Jquery- Fade Out/Fade In

I am building a very basic guessing game using jquery and html. I have 6 checkboxes, and if the right sequence is triggered, a hidden div appears. In order to trigger the div, I need to select 1,2,and 3. If you select 1,2,and 4, you get a secret message (div2), and otherwise nothing happens.
I can do the trigger easily by doing nested clicks:
$("#1").click(function(){
$("#2").click(function(){
$("#3").click(function(){
$("#div1").fadeIn();
});
});
});
html:
<input type="checkbox" id="#1">
<input type="checkbox" id="#2">
<input type="checkbox" id="#3">
<input type="checkbox" id="#4">
<input type="checkbox" id="#5">
<input type="checkbox" id="#6">
<div id="div1" style="width:30px;height:30px;display:none;background-color:blue;"></div>
<div id="div2" style="width:30px;height:30px;display:none;background-color:yellow;"></div>
But I am having trouble making it disappear.
If any one of the three is not pressed, I would like for that div to disappear. So let's say you press 1,2,3, div1 appears, and if you deselect 3, that div1 disappears.
I think I can make the question easier to phrase by phrasing it like this: i want to tell jquery- if one, and two, and three, are not 'all' selected, fade out the div.
Rather than using nested clicks, which will get complicated and confusing, you'd be better off creating a generalised listener that will maintain a list of what has/hasn't been clicked. Not only is this easier to maintain, it is also more optimal than having many click handlers assigned.
Others out there who may wish to optimise further may say correctly that you could write this code to directly generate a checked array, rather than a checked object, the reason I have kept it as an object is to support the possibility of a string-based ident rather than just numerical.
updated code
Previous code was slightly buggy, this version now works correctly when you select more checkboxes than you should.
reasons why
why change to use classes more than ids
Whilst ids are very specific, and will be more optimal for the browser to select by, they generally cause confusion and make things laborious, especially in markup that you wish to duplicate (obviously because ids have to be unique). It is often far better to come up with a solution that can work on a general grouping class, than having to label each element with a sequence i.e. cb1, cb2, cb3. As you can see my markup does label the checkboxes sequentially but the code only worries about the grouping class .cb, leaving the sequential classes really only for css styling.
why add a container div
When working on html5 apps, container divs will help you out 9 times out of 10. If you have a collection of elements that will only ever reside in a close visual formation, you will do yourself a favour by wrapping them. This helps when dynamically generating more elements (you can append your new elements directly to the container), it can help with delegating event listeners, and when targeting the elements via jQuery and CSS.
why use change instead of click for checkboxes
change is the event specifically designed to trigger when a change of value occurs, click is designed to fire when a click occurs. You should use the event that best suits what you want. In this case you only wish to update when a checkbox has changed it's value, which can happen with or without a mouse. True, some browsers fire the click event when using keyboard events, but it is better to be clear.
why use data-ident
ids should be used for quick look-up purposes, classes should be used to classify and group, if you have any other information to add to an element you should use the data- prefix. This means you aren't limited by what characters id and class support, and changing data- values doesn't cause any real internal calculations to fired by the browser i.e. applied classes or element registration.
how this code could be improved
The problem with making code more accessible and readable means that it's easier to work out what the code means, and this is bad for a game that should try and hide the solutions away from it's user-base. If this is just a simple game then there isn't much to worry about, but if you are working with something a bit more serious you should try and find a way to obfuscate the solutions :)
working fiddle:
http://jsfiddle.net/RFK92/
code:
/// your list of what is checked
var checked = {};
var updateDivs = function(){
var ident, show, checklist = [];
/// create a useful string from what has been checked
for ( ident in checked ) {
if ( checked[ident] ) {
checklist.push(ident);
}
}
checklist = checklist.join(',');
if ( checklist == '1,2,3' ) {
show = $('#div1');
}
else if ( checklist == '1,2,4' ) {
/// show something else, or not...
}
/// by using a grouping class you can find all divs that could be affected
$('.only-one-div').not(show).fadeOut();
if ( show ) {
/// and single one out for reveal
show.fadeIn();
}
};
$('.cb').change(function(){
var cb = $(this), ident = cb.data('ident');
/// keep track of what is or not checked
checked[ident] = cb.prop('checked'); /// updated to use prop!
/// update your divs
updateDivs();
});
markup:
<div class="cbs">
<input type="checkbox" class="cb cb1" data-ident="1" />
<input type="checkbox" class="cb cb2" data-ident="2" />
<input type="checkbox" class="cb cb3" data-ident="3" />
<input type="checkbox" class="cb cb4" data-ident="4" />
<input type="checkbox" class="cb cb5" data-ident="5" />
<input type="checkbox" class="cb cb6" data-ident="6" />
</div>
<div id="div1" class="only-one-div">one</div>
<div id="div2" class="only-one-div">two</div>
css:
.only-one-div { display: none; }
I would have a look at binding and unbinding your clicks.
Basically, if they have clicked the first proper click then bind the second proper click.
Any incorrect clicks would have you unbind all the clicks and fadeOut the divs and rebind the first necessary click.
http://api.jquery.com/bind/
http://api.jquery.com/unbind/
http://jsfiddle.net/CEb9x/1/
$('input[type=checkbox]').on('change', function(){
if($('input:checked').length == 3){
if ($('.blue:checked').length == 3) { $("#div1").fadeIn(); $("#div2").fadeOut();}
else if ($('input[name="secret"]:checked').length == 3) { $("#div1").fadeOut(); $("#div2").fadeIn(); }
} else { $("#div1, #div2").fadeOut(); }
});
This should do:
$("#1").click(function(){
checkboxClicked();
});
$("#2").click(function(){
checkboxClicked();
});
$("#3").click(function(){
checkboxClicked();
});
$("#4").click(function(){
checkboxClicked();
});
$("#5").click(function(){
checkboxClicked();
});
$("#6").click(function(){
checkboxClicked();
});
...
...
function checkboxClicked() {
if ($('#1').is(':checked') && $('#2').is(':checked') && $('#3').is(':checked') {
$('#div1').show();
$('#div2').hide();
}
else {
$('#div1').hide();
}
if ($('#1').is(':checked') && $('#2').is(':checked') && $('#4').is(':checked') {
$('#div2').show();
$('#div1').hide();
}
else {
$('#div2').hide();
}
}

JS - Shouldn't this be written better? One function vs multiples?

I have a tweet stream where new tweets are added at the top and the older ones pushed down. You can click on the entire tweet and a panel slides down to reveal, "reply", "retweet", "favorite" etc. The panel is added to each new tweet added in the stream.
The code below works. Shouldn't this be better written so that only one call is being made? Or, as a new tweet is added. would I just have to add to the code with div#tc4, ul#tb4 etc?
$(document).ready(function () {
$("div#tc1").click(function () {
$("ul#tb1").slideToggle("fast");
});
$("div#tc2").click(function () {
$('ul#tb2').slideToggle("fast");
});
$("div#tc3").click(function () {
$('ul#tb3').slideToggle("fast");
});
});
Added Markup:
<div id="tc1" class="tweetcontainer">
<div class="avatarcontainer">
<div class="avatar"></div>
</div>
<div class="content">
<div class="tweetheader">
<div class="name">
<h1>John Drake</h1>
</div>
<div class="tweethandle">
<h2>#Drakejon</h2>
</div>
<div class="tweettime">10m</div>
</div>
<div>
<p>Exceptional Buys Ranger To Give Monitoring Shot In The Arm To Its 'DevOps' Platform http://tcrn.ch/11m3BrO by #sohear </p>
</div>
</div>
</div>
<!-------------Tool Bar -------------------------------->
<ul id="tb1" class="toolbar">
<li><a class="reply" href="#"><span>reply</span></a></li>
<li><a class="retweet" href="#"><span>retweet</span></a></li>
<li><a class="favorite" href="#"><span>favorite</span></a></li>
<li><a class="track" href="#"><span>track</span></a></li>
<li><a class="details" href="#"><span>details</span></a></li>
</ul>
I highly recommend separating your javascript from your detailed page function. The best way to do this is to put the retweeting panel inside the tweet container, then you don't even need to give it an id at all or encode in the javascript information about your html structure and ids. You can then just do:
$('.tweetcontainer').on('click', function(event) {
if ($(event.target).is(':descendantof(.toolbar)')) {
//ignore all clicks within the toolbar itself
return;
}
$(this).find('.toolbar').slideToggle();
});​
It's that easy! See it in action in a jsFiddle.
Now you can add as many tweet containers as you want to your page--and your javascript doesn't have to change one bit. Other solutions that require knowledge of specific ids linking to specific ids are suboptimal.
Note the descendantof pseudo-selector is custom (see the fiddle to find out how it works). Also, since you didn't provide any css, I had to choose some--it was quick so don't expect much. (Aww heck I just saw you updated your question to provide a jsFiddle with css giving a far prettier result--but I won't change mine now.) I did have to add a class to the actual tweet itself, but there is probably a better way to style it.
And if you want a click on the displayed toolbar itself (outside of a link) to allow collapsing the toolbar, change the code above to :descendantof(a).
If you don't want to change your page layout, another way to it is to encode the information about the linkage between html parts in the html itself using a data attribute. Change your tweetcontainer div to add a data attribute with a jQuery style selector in it that will properly locate the target:
<div class="tweetcontainer" data-target="#tb1">
You don't really have to remove the id if you use it elsewhere, but I wanted you to see that you don't need it any more. Then on document.ready:
$('.tweetcontainer').click(function () {
$($(this).data('target')).slideToggle('fast');
});
Here is another jsFiddle demonstrating this alternate technique (though it less elegant, in my opinion).
Last, I would like to mention that it seems possible you have a little bit of "div-itis". (We have all been there.) The toolbar anchor elements have unnecessary spans inside of them. The tweet name h1 element is inside a div, but could just be an h1 with class="name" instead.
In general, if there is only a single item inside a div and you can change your stylesheet to eliminate the div, then the div isn't needed. There are an awful lot of nested divs in your html, and I encourage you to remove as many of them as you can. Apply style to the other block elements you use and at least some, if not many, won't be needed.
I'd suggest (though currently untested):
$('div[id^="tc"]').click(function(){
var num = parseInt(this.id.replace(/\D+/g,''),10);
$('#tb' + num).slideToggle("fast");
});
Though given that you don't need the num to be a number (it'd be fine as a string), you could safely omit the parseInt().
Yes, you can write this code much more compactly like this:
$(document).ready(function() {
for (var i = 1; i < 3; i++) {
$("div#tc" + i).click(function() { $("ul#tb" + i).slideToggle("fast"); } );
}
});

Javascript show/hide - I don't want it to hide the entire element

This is probably a fairly easy question, but I'm new to JavaScript and jquery....
I have a website with a basic show/hide toggle. The show/hide function I'm using is here:
http://andylangton.co.uk/articles/javascript/jquery-show-hide-multiple-elements/
So here's my question..... I would really like the first 5-10 words of the toggled section to always be visible. Is there some way I can change it so that it doesn't hide the entire element, but hides all but the first few words of the element?
Here's a screenshot of what I would like it to do:
http://answers.alchemycs.com/mobile/images/capture.jpg
There are many different implementation possibilities:
You can divide the contents up into the first part and the second part (two separate spans or divs inside your main object) and hide only the child object that represents the second part, not hide the parent object.
Rather than hide the object at all, you can set its height to only show the first part (with overflow: hidden)
Change the contents of the main object to only have the first part as the contents (requires you to maintain the full contents somewhere else so you can restore it when expanded again).
Here's a working example of option 1: http://jsfiddle.net/jfriend00/CTzsP/.
You'd need to either:
Put in a span/etc. after the first n words, and only hide that part, or
Change the viewable region, or
Replace or toggle the span/etc. with the "collapsed" view.
The last is a bit more customizable; using two separate elements allows trivial games to be played (showing an image, for example, like a little curly arrow) without modifying adding/removing DOM elements.
I tend towards the last because it's simple and obvious, but that's a personal preference, and really isn't as true as it used to be.
You can do some plugin authoring,I did a sample demo here ,based on your screenshot
<div class="toggle">ShowHide</div>
<div class="content">some content some content some content some content some content <br/> some content some content some content </div>
<div class="toggle">ShowHide</div>
<div class="content">some content some content some content some content some content <br/> some content some content some content </div>
here is javascript/jquery code
jQuery.fn.myToggle = function(selector, count) {
var methods = {
toggle: function(selector, count) {
if ($(selector).is(':visible')) {
var span = $('<span>');
span.text($(selector).text().substr(0, count) + "...");
span.insertAfter($(selector));
$(selector).hide();
}
else {
$(selector).show();
$(selector).next('span').hide();
}
}
};
$(this).each(function() {
methods.toggle($(this).next(selector), count);
$(this).click(function(evt) {
methods.toggle($(this).next(selector), count);
});
});
};
$(function() {
$('.toggle').myToggle('.content', 3);
});
Here is a solution using css properties only instead of mangling the dom.
http://jsfiddle.net/AYre3/4/
Now if you want some sort of animation happening as well you'll probably need to do a bit of measurement along the way.

Text captions on multiple Images with jQuery

I'm new to jQuery so please be patient. I want to create a text caption that slides down on an image when you hover over a link on the page. I can do this when there's just one image with one caption but I have several images with different captions on one page.
I would like to create one function that can handle all of these in seperate instances and not create a function for each image/textcaption. The reason being is that the images and text is dynamic and changing in quantity overtime.
Please see an example of the code below, the .portText is a class of about 7 instances, when I hover over .moreInfo the text for every image slides down. I understand why this is happening, and I think I need to use ($this) somehow, but I also think i need to connect the picture to the text differently that it's done here. Hope this makes sense. Can anyone help? Cheers!
$(function() {
$('.moreInfo').hover(
function() {
$('.portText').slideDown('slow');
},
function() {
$('.portText').slideUp('slow');
}
)
});
You can refer to the element that was hovered over using $(this).
The way I usually do this is to make portText a child of the moreInfo div:
<div class="moreInfo">
<div class="portText">
....
</div>
</div>
Then instead of just $('.portText') you can do $('.portText', this) (i.e. all portTexts that are children of the hovered element).
Edit: Another way to do it would be to use the data attribute and give each portText an ID:
<div class="moreInfo" data-id="1">....</div>
<div class="portText" id="portText-1">...</div>
Then for Javascript:
$('.moreInfo').hover(
function() {
var myId= "#portText-" + $(this).data('id');
$(myId).slideDown('slow');
},
function() {
var myId= "#portText-" + $(this).data('id');
$(myId).slideUp('slow');
}
);

Categories