I'm very new to JavaScript and jQuery. I know my code is not the prettiest, but I'm trying to start somewhere.
I have a series of questions that are shown one at a time, and want to create some sort of validation to prevent the user from going to the next question if a radio button on the first button hasn't been selected.
HTML (I have four of these .questionContainers
<div class="questionContainer">
<div class="question">
How much storage do you need?
</div>
<div class="answers">
<ul>
<li>
<label>
<input type="radio" id="storage">1GB or less
</label>
</li>
<li>
<label>
<input type="radio" id="storage">More than 1GB
</label>
</li>
</ul>
</div>
<div class="btnContainer">
<div class="next">
<a class="btnNext">Next</a>
</div>
</div>
</div>
JavaScript
(function(){
var Questions = {
container : $('.questionContainer'),
init : function() {
this.start();
if($('input[type=radio]:checked').length > 0){
this.container.find('a.btnNext').on('click', this.next);
}
},
start : function() {
this.container.not(':first').addClass('hide');
},
next : function() {
var container = $('.questionContainer');
$(this).closest(container).hide(function(){
$(this).closest(container).next().show();
});
}
};
Questions.init();
})();
The specific line that isn't working:
if($('input[type=radio]:checked').length > 0) {
this.container.find('a.btnNext').on('click', this.next);
}
The Problem
When I add the if statement and click a radio button followed by next, it does not go to the next question. I am not receiving any errors in the console.
This binds to the click event only if something is checked at the time that the start function is called (not what you want - it will never be true unless you pre-select a radio button for the user without their action):
if($('input[type=radio]:checked').length > 0){
this.container.find('a.btnNext').on('click', this.next);
}
Try replacing it with this instead:
this.container.find('a.btnNext').on('click', function () {
if($('input[type=radio]:checked').length > 0){
this.next();
}
});
This way you always bind to the click event, but the function that is bound only allows next to be called if something is checked at the time that the function is called (i.e. when the next button is clicked).
Related
I am needing to show text for an icon when it is hovered on. The issue is the icons are displaying via a loop. Meaning I have more than one icon with the same name. I'm sure I need to use "this" somehow to only show text next to the icon that is hovered on. However so far I have failed to do so.
My basic code so far. How would I change the code to show text depending on which icon is being hovered on?
$(".material-icons").on({
mouseenter: function () {
console.log('Show Name for this Icon')
},
mouseleave: function () {
console.log('Hide Name for this Icon')
}
});
Any help is appreciated!
Edit: Here is the loop that's being used to show the icons.
<li id='topSection' class="list-group-item active">Amenities </li>
<li id="amnetiesBox" class="list-group-item">
<% for(var i=0; i<rentals.amenities.length; i++){ %>
<i class="material-icons"><%=rentals.amenities[i]%></i>
<% } %>
</li>
</li>
An example of the icons being selected:
<input type="checkbox" name="amenities" value="personal_video"><span>TV</span>
<input type="checkbox" name="amenities" value="call"><span>Phone</span>
You can use $(this) and display the text related to that target element
$(".material-icons").on({
mouseenter: function () {
$(this).next("span").show()
},
mouseleave: function () {
$(this).next("span").hide()
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="material-icons" ><span>Hover </span></div> <span style="display:none">first</span>
<div class="material-icons" ><span>Hover</span></div> <span style="display:none">second</span>
<div class="material-icons" ><span>Hover</span></div> <span style="display:none">third</span>
I came up with a somewhat simple solution that works. The problem with the other suggestions is that I cant add spans per icon because of the loop (as far as I know.)
I went with this:
$(".material-icons").on({
mouseenter: function () {
var text = $(this).text();
if (text === 'wifi'){
text = 'Local Wifi'
}
if (text === 'local_laundry_service'){
text = 'Laundry on site'
}
$(".showName").show()
$(".showName").html(text)
},
mouseleave: function () {
$(".showName").hide()
}
});
So what it's doing is finding the icons name first and if the icon name is "local_laundry_service" etc I'm updating the text to say simply Laundry on site. Obviously you have to do this for each icon that might be used. Not very dry code but I'm not sure how else to go about it.
I am complete beginner in javascript, I don't know many commands. The thing is I want to show that three different div element in the same exact position while clicking three different button meaning each three button have their own separate dropdown. So I check if some other dropdown is showing when I click to open some other dropdown, then I close the previous opened dropdown so both thing don't overlap. Is this efficient way to do so ?
HTML Snippet-
<header class="primary-header">
<div class="big-wrapper">
<div class="first-icon left col-1-3 ">
<img onclick="toggleDropdown("dropOne");" class="cursor-pointer dropbtn " src="assets/images/icon.32x32.user.white.png" alt="menu-nav">
<div id="dropOne" class="dropdown-content big-wrapper">
First Drop menu 1
First Drop menu 2
First Drop menu 3
</div>
</div>
<div class= "second-icon left col-1-3">
<img onclick="toggleDropdown("dropTwo")" class="cursor-pointer dropbtn" src="assets/images/icon.32x32.hearts.white.png">
<div id="dropTwo" class="dropdown-content big-wrapper">
Second Drop menu 1
Second Drop menu 2
Second Dropmenu 3
</div>
</div>
<div class=" third-icon left col-1-3">
<img onclick="toggleDropdown("dropThree")" class="cursor-pointer dropbtn" src="assets/images/icon.32x32.menu.white.png">
<div id="dropThree" class="dropdown-content big-wrapper">
Third Drop menu 1
Third Drop menu 2
Third Drop menu 3
</div>
</div>
<div class="clr"></div>
</div>
</header>
Javascript-
var dropdown1 = document.getElementById("dropOne");
var dropdown2 = document.getElementById("dropTwo");
var dropdown3 = document.getElementById("dropThree");
function toggleDropdown(elementId) {
if(elementId == "dropOne")
{
dropdown1.classList.toggle("show");
if(dropdown2.classList.contains("show"))
{
dropdown2.classList.toggle("show");
}
if(dropdown3.classList.contains("show"))
{
dropdown3.classList.toggle("show");
}
}
else if(elementId == "dropTwo")
{
dropdown2.classList.toggle("show");
if(dropdown1.classList.contains("show"))
{
dropdown1.classList.toggle("show");
}
if(dropdown3.classList.contains("show"))
{
dropdown3.classList.toggle("show");
}
}
else if(elementId == "dropThree")
{
dropdown3.classList.toggle("show");
if(dropdown2.classList.contains("show"))
{
dropdown2.classList.toggle("show");
}
if(dropdown1.classList.contains("show"))
{
dropdown1.classList.toggle("show");
}
}
}
It depends on your definition of efficient. You won't be able to increase the performance significantly since it's probably executing in few milliseconds already.
However, you can cut many line of code by using add / remove instead contain / toggle (and if for some reason the show class is added to a second dropdown, your button will start displaying or hidding the wrong items). You can also write a more generic function by looping into n array. That would allow you to add buttons and dropdowns more easily (This code isn't tested but you'll get the point.):
var dropdownArray = [];
dropdownArray.push(document.getElementById("dropOne"));
dropdownArray.push(document.getElementById("dropTwo"));
dropdownArray.push(document.getElementById("dropThree"));
function toggleDropdown(elementId) {
dropdownArray.forEach(function(dropdown){
if(dropdown.id == elementId) {
dropdown.classList.add("show");
} else {
dropdown.classList.remove("show");
}
});
}
I have two containers in top and bottom,
Top container initially it will have no records i'm adding list of text from bottom container to top container on button click as of now its working fine,
but one small change in my scenario currently now multiple records are adding to my top container i want only once no multiple/same list record should appear in top container
say for example if i have one record placed above in top container next time even if i click add button same list record should not be added into top container either button should be disabled after adding list record or no duplicate record should be allowed in top container
somebody help me out in achieving it Thanks!
https://jsfiddle.net/qx69o1bd/
html
<div>
<ol id="sortable">
</ol>
</div>
<br/>
<div>
<ul id="draggable">
<li>
<div class="qitem">
<label class='lbl'>
Lance
</label>
<button class="hello" >Add To Top container</button>
</div>
</li>
<li >
<div class="qitem" >
<label>
Adam
</label>
<button class="hello" >Add To Top container</button>
</div>
</li>
<li >
<div class="qitem" >
<label>
Rickey
</label>
<button class="hello" >Add To Top container</button>
</div>
</li>
</ul>
</div>
JQuery
$(document).ready(function() {
$("#sortable").sortable();
$("button").click(function () {
var label = $(this).prev().text();
$("#sortable").append('<li>'+label+'</li>');
});
});
only add a class to disable and validate it. With css also you can stylling the button. https://jsfiddle.net/mig1098/qx69o1bd/4/
$(document).ready(function() {
$("#sortable").sortable();
$("button").click(function () {
var label = $(this).prev().text();
if(!$(this).hasClass('disabledbutton')){
$("#sortable").append('<li>'+label+'</li>');
}
$(this).addClass('disabledbutton');
});
});
$(document).ready(function() {
$("#sortable").sortable();
$("button").click(function () {
var label = $(this).prev().text();
if ($("#sortable > li:contains("+label+")").length != 0)
return;
$("#sortable").append('<li>'+label+'</li>');
});
});
This checks if there is already an element which contains the name, and if so doesn't let the user add it again!
If you use the one method to attach your listener to the click event, the button will only run your listener once (per button the selector applies to):
$("button").one('click', function () {
var label = $(this).prev().text();
$("#sortable").append('<li>'+label+'</li>');
});
If you wish to actually disable your button, you can do this by setting the disabled attribute on the object:
$("button").one('click', function () {
var label = $(this).prev().text();
$("#sortable").append('<li>'+label+'</li>');
$(this).attr('disabled', true');
});
I have a simple dropdown that opens up a search field when you click it. Even though I have the text field of this search set to autofocus, it's not working for all browsers.
What method of Javascript/jQuery would I use to check if the containing UL css display is set to block, so that I can force the focus to be on the field using .focus().
HTML:
Quick Search
<ul class="dropdown-menu" role="menu">
<li id="li-quicksearch">
<form id="mainSearch" class="form-search">
<p>
<input type="text" id="inputSearch" class="form-control" placeholder="Quick Search" required="" autofocus autocomplete="off">
<button type="submit">SUBMIT</button>
</p>
</form>
</li>
</ul>
EDIT: There is no css change event so you'll have to approach the problem in 1 of 2 ways.
check the dom element in set intervals to see if its css has changed
trigger an event when the css of the dom element is changed by user interaction/your code.
the first way will look something like this:
var element = $(".dropdown-menu");
function checkForChanges()
{
if (element.css('display') == 'block')
{
// do your .focus() stuff here
}
setTimeout(checkForChanges, 500); // does this every half second.
}
or the second way:
$('.toggle').on('click', function() {
$('.dropdown-menu').toggle();
$('.dropdown-menu').trigger('change');
});
$('.dropdown-menu').on('change', function(){
if($(this).css(.css('display') == 'block')
{
// do your .focus() stuff here
}
});
You can check the display value of the ul using pure JavaScript with this:
JS:
var display = document.getElementById('dropdown-menu')[0].style.display;
if (display === 'block') {
//do what you want.
}
Or using jQuery:
if ($('.dropdown-menu').css('display') === 'block') {
//do what you want.
}
It looks like you are using bootstrap to create the dropdown. If that is the case you can use the "shown" event. However you need to attach the event on a container element.
Html
<div class="quickSearchContainer">
Quick Search
<ul class="dropdown-menu" role="menu">
<li id="li-quicksearch">
<form id="mainSearch" class="form-search">
<p>
<input type="text" id="inputSearch" class="form-control" placeholder="Quick Search" required="" autofocus autocomplete="off">
<button type="submit">SUBMIT</button>
</p>
</form>
</li>
</ul>
</div>
Javascript
$('#quickSearchContainer').on('show.bs.dropdown', function () {
$('#inputSearch').focus();
});
I want to thank everyone for their input, but the working solution that I found was to modify the bootstrap JS to allow for an autofocus on toggleClass of the OPEN for the dropdowns. Everyone gets kudos!
I have an auto-generated list of sections that looks like that:
<div class="list">
<section class="visible list-0"></section>
<section class="hidden list-1"></section>
<section class="hidden list-2"></section>
<section class="hidden list-3"></section>
<!-- unknown amount of sections -->
</div>
And a checkbox:
<input type="checkbox" id="accept" value="1" required>
If checkbox is checked I want to hide the first section .list-0 and show next section list-1. Then if checkbox is checked again, hide list-0 and list-1 and show list-2. Please note that the amount of sections in unknown and can be up to about 25.
The following code is what I wrote by now.
$('#accept').on('click',function() {
var count_sections = $('.list > section').length;
$('.list-0').removeClass('visible').addClass('hidden');
$('.list-1').removeClass('hidden').addClass('visible');
// this should uncheck the checkbox
$('#accept').attr('checked', false);
});
I want to automate it so it will work no matter how many sections I have. Any help is very appreciated. Thanks.
try this one:
$('#accept').on('click',function() {
$('.visible').next('.hidden').removeClass('hidden').addClass('visible');
$('.visible:first').removeClass('visible').addClass('hidden');
// this should uncheck the checkbox
$('#accept').prop('checked', false);
});
this is my first approach. you select the visible element, hide it, toggle class visible, select the next element, show it and toggle class visible.
i completely removed the hidden class from this solution, since we switch between two states - visible and hidden - we only need the visible class to know if it is visible or hidden...
$('#accept').on('click',function() {
if (!$("section:last").hasClass("visible"))
{
$('.visible').hide().toggleClass("visible").next()
.show().toggleClass("visible");
// this should uncheck the checkbox
$('#accept').attr('checked', false);
}
});
UPDATED FIDDLE: http://jsfiddle.net/tbu116w8/2/
added the if statement to check, if you are currently on the last section
Try this -
var $previousSection=$(".list-0").show();
$('#accept').on('change',function() {
if($(this).is(":checked")){
$previousSection.hide();
$previousSection = $previousSection.next("section").show();
}
});
DEMO
You need to store the current visible in a variable. Then show the next one and hide the current one. This is more efficient than finding the visible one again.
You can also store the section you are showing next so you know when you have reached the end:
$('#accept').on('click',function() {
var vis = $('.visible');
var hid = vis.next('.hidden').removeClass('hidden').addClass('visible');
$('#accept').prop('checked', false);
// if we showed something (not at the end yet), hide the current visible one
if(hid.length > 0) {
vis.removeClass('visible').addClass('hidden');
}
});
.visible {
display:block;
}
.hidden {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div class="list">
<section class="visible list-0">0</section>
<section class="hidden list-1">1</section>
<section class="hidden list-2">2</section>
<section class="hidden list-3">3</section>
<!-- unknown amount of sections -->
</div>
<input type="checkbox" id="accept" value="1" required/>
use count on checkbox value
here is the working fiddle with the condition of upto 25
$('#accept').on('click',function() {
var count_sections = $('.list > section').length;
var count = $(this).val();
if(count > 25)
{
return false;
}
$('.list-'+count).removeClass('visible').addClass('hidden');
count++;
$('.list-'+count).removeClass('hidden').addClass('visible');
$(this).val(count);
// this should uncheck the checkbox
$('#accept').attr('checked', false);
});
here is the html
<div class="list">
<section class="visible list-0">1st</section>
<section class="hidden list-1">2nd</section>
<section class="hidden list-2">3rd</section>
<section class="hidden list-3">4th</section>
<!-- unknown amount of sections -->
</div>
working example
jsfiddle.net/dr8Ln350/