I have a jQuery mobile page with a number of images I'm using as buttons.
When the page initially loads, all of the images have a class of 'inactive'.
If I click 1 of the buttons, its class is changed to 'active' and all of the other buttons are changed from 'inactive' to 'disabled'. If I navigate away from the page and navigate straight back, the 1 image still has a class of 'active', and the rest still have a class of 'disabled'.
When I click the active button it changes class from 'active' to 'inactive', and all of the other buttons change class from 'disabled' to 'inactive'.
This allows me to choose another button to be the active one.
when I click one of the buttons that was previously disabled but is now inactive, the click event doesn't fire. It's as though it thinks the class is still disabled as it was when the page initially loaded. I've checked using Firebug in Firefox and the class is correctly set as inactive, but it's still behaving as though the class is disabled.
Here's my jQuery:
$(document).ready(function() {
$('.inactive, .active').on("click", function(){
// Toggle active/inactive class
$(this).toggleClass("active inactive");
// Disable if 1 active button, else inactive
if($('.active').length == 1) {
$('.inactive').toggleClass("inactive disabled");
} else {
$('.disabled').toggleClass("disabled inactive");
}
});
});
And the HTML buttons:
<a class="button inactive"></a><br />
<a class="button inactive"></a><br />
<a class="button inactive"></a><br />
<a class="button inactive"></a><br />
<a class="button inactive"></a><br />
<a class="button inactive"></a>
And the classes:
.button {
background:url("../images/compare.png") no-repeat;
width: 18px;
height:18px
}
.active {
background-position: 0 -18px;
cursor:pointer
}
.inactive {
background-position: 0 0;
cursor:pointer
}
.disabled {
background-position: 0 -36px;
cursor:default
}
Ok guys, I've figured this out.
When I change the class from disabled to inactive, the click handler doesn't get attached to the 'new' inactive buttons automatically.
I've added a new class 'mybutton' to all the buttons (so an active button would be class="mybutton active" for example), then looked for that class in the click handler so even the disabled buttons will run through the code.
Here's my new code:
$(document).ready(function() {
$('.mybutton').on("click", function(){
if($(this).hasClass("inactive") || $(this).hasClass("active")) {
$(this).toggleClass("active inactive");
}
// Disable if 1 active button, else inactive
if($('.active').length == 1) {
$('.inactive').toggleClass("inactive disabled");
} else {
$('.disabled').toggleClass("disabled inactive");
}
});
});
I had to wrap the $(this).toggleClass("active inactive"); statement in an if statement which has me puzzled.
Without the if statement, clicking a disabled button would turn it to active.
Why would this happen? And why does wrapping the button in an if statement fix it when it's just checking for the same classes as the toggle?
Related
Hello, friends!
I'm new to Javascript. Using native JS.
I need when I click on the red button the blue button becomes disabled using removeEventListener. And vice versa - clicking on the blue button will add removeEventListener to the red button.
But my method does not work because the first array does not see the other array.
Thanks for the help. And, please, add comments to your code))
Here is the code and example https://jsfiddle.net/of83ycmx/
<body>
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
<script>
const box = document.querySelectorAll('.box');
const red = document.querySelectorAll('.red');
const blue = document.querySelectorAll('.blue');
red.forEach((item, i) => {
item.addEventListener('click', function redListener() {
box[i].classList.add('redBox');
//removeEventListener doesnt work because blueListener is not defined
//item.removeEventListener('click', blueListener);
});
});
blue.forEach((item, i) => {
item.addEventListener('click', function blueListener() {
box[i].classList.add('blueBox');
// item.removeEventListener('click', redListener)
});
});
</script>
made some changes that made sense to me. I am quite a beginner, so anyone who sees anything no-no or bad practice go ahead and call me out.
What should happen:
My interpretation of your explanation is this: When a user clicks on 1 of 2 buttons, the button that was NOT clicked should have its event listener removed.
Solution:
Making the functions accessible was your main problem-named functions inside of event listeners are limited to that listener (I assume). So instead move the function outside of the listener and simply call the function:
function blueListener () {
// Do stuff here
}
item.addEventListener('click', blueListener)
Now the function is accessible to the other function, so when you remove the event listener you wont get blueListener is not defined.
By wrapping the buttons and the box in a div allows you to select the button you need. Using .querySelectorAll() on the parent div allows you to select the button with the respective class (i. e the selecting the blue button when you click the red button).
The functions don't need any other info; they use this to access the clicked element. Then you can find the parent element, and select the box to change the background color, and select the respective button to remove the event listener.
DEMO:
const box = document.querySelectorAll('.box');
const red = document.querySelectorAll('.red');
const blue = document.querySelectorAll('.blue');
function redListener() {
var parent = this.parentElement;
var box = parent.querySelectorAll('.box')[0]
var blueButton = parent.querySelectorAll('.blue')[0]
box.classList.add('redBox');
blueButton.removeEventListener('click', blueListener)
}
function blueListener() {
var parent = this.parentElement;
var box = parent.querySelectorAll('.box')[0]
var redButton = parent.querySelectorAll('.red')[0]
box.classList.add('blueBox');
redButton.removeEventListener('click', redListener)
}
red.forEach((item, i) => {
item.addEventListener('click', redListener)
})
blue.forEach((item, i) => {
item.addEventListener('click', blueListener)
});
body {
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
}
.box {
width: 100px;
height: 100px;
background-color: rgb(172, 172, 172);
margin: 0px 0px 40px 0px;
display: flex;
justify-content: center;
align-items: center;
}
.redBox {
background-color: rgb(156, 56, 56);
}
.blueBox {
background-color: rgb(66, 56, 156);
}
<div class="buttons">
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
</div>
<div class="buttons">
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
</div>
I want to close popup window with Esc key. Is it possible to close with Esc key when I have set data-dismissible="false". The Popup should not close when clicked outside of the Popup (that's why I have set data-dismissible="false" and it works great). Only problem is I am not able to close with Esc key. Here is my code:
$(document).keydown(function(e) {
if (e.keyCode == 27) {
namePopup.close();
}
});
Try this, popupBaisc is the id of the popup.
$(document).ready(function() {
$(document).keydown(function(e) {
if (e.keyCode == 27) {
$("#popupBasic").popup("close");
}
});
});
HTML
Open Popup
<div data-role="popup" id="popupBasic" data-dismissible="false">
<p>This is a completely basic popup, no options set.</p>
</div>
When I call fadeOut on my dialog it only does a partial fade and leaves the grey header area where the dialog title is. I've tried removing the title as well as the various attributes that disable the exit button in the upper right corner of the dialog, but that didn't work. As you'll see in my script below, I want the dialog to close after the form submission has been validated.
//HTML
<div id="dialog">
<form id="form">
<p id="thanks">Please provide a contact number. It will only be shared with the
host</p><input id="number" name="number" type="text"/>
<button id="submit" type="submit">Submit</button>
</form>
</div>
//JS
if(myConditional){
//FORM IS HIDDEN ON PAGE LOAD AND SHOWN ON CLICK
$('form').show();
$('#dialog').dialog({
//These parameters are meant to disable the dialog close button
closeOnEscape: false,
beforeclose: function (event, ui) { return false; },
dialogClass: "noclose",
title: "Thanks For Volunteeering",
minWidth: 500
});
$('button').button();
}else{
//other code
}
//Validate the phone number before saving it to local storage
$("#form").validate({
rules: {
number : {
required: true
customvalidation: true
}
},
messages: {
number : {
required: "enter a phone number"
}
},
submitHandler: function(form) {
var number = $('#number').val();
localStorage.setItem('number', JSON.stringify(number));
//THIS FADE OUT ISN'T FULLY FADING THE DIALOG
$('#dialog').fadeOut();
} //closes submit handler
});//close validate
Ok I figured it out.
I got rid of the beforeClose parameter in the dialog init code, and in the form validation submit handler I added this:
$('#dialog').fadeOut('slow', function(){
$( this ).dialog( "close" );
});
//The fadeOut method has a call back function you can use with it to do something after the fade is completed.
I have a jquery UI menu in which I want to highlight a selected item and then un-highlight it once another item has been clicked and highlighted. I got as far as changing the css background color property once the select event is detected on the menu, but before that happens I want to check all items to see if a previous selection is still highlighted, unhighlight it, and THEN highlight the new selection.
<script>
$(function(){
$(".menu").menu({
//detect select event
select:function( event, ui ) {
//highlight the selected menu item
ui.item.css('background-color','red');
}
});
});
</script>
//The Menu
<ul class="menu">
<li><h2> Fitness</h2></li>
<li><h2> Literature</h2></li>
<li><h2>Music</h2></li>
<li><h2>Fine Art</h2></li>
<li><h2>Food</h2></li>
</ul>
I would recommend creating a css class and adding/removing the class, rather than setting the style directly.
$(document).ready(function () {
$(".menu").menu({
select: function (event, ui) {
$('.selected', this).removeClass('selected');
ui.item.addClass('selected');
}
});
});
CSS:
.menu .ui-menu-item.selected {
background-color : red;
}
And add this if you want it to stay red even when the item has focus or has a submenu and is active.
.menu .ui-menu-item.selected > .ui-state-focus,
.menu .ui-menu-item.selected > .ui-state-active {
background-color : red ;
background-image: none;
}
You may need to tweek this some more if you plan to have submenus to get it to work in a way that makes sense.
Without submenus: http://jsfiddle.net/sgearhart2/Fba6L/4/
With submenus: http://jsfiddle.net/sgearhart2/Fba6L/5/
I'd like to pop up a dialog that is not full screen, i.e., it "floats" above the page which opened it. Here is what I am trying:
<div data-role="page" id='Page1'>
<div data-role='button' id="Button1">Open Dialog</div>
</div>
<div data-role="dialog" id='Dialog'
style='width:200px; height:100px; top:100px; left:100px;'>
<div data-role='button' id="Button2">Close</div>
</div>
<script>
Button1.onclick = function() {
//$.mobile.changePage($('#Dialog'))
$.mobile.changePage('#Dialog',{role:'dialog'})
}
Button2.onclick = function() {
$(".ui-dialog").dialog("close");
}
Even though I set the bounds on Dialog's div, it is still full screen.
Here's what I came up with (after some great hints from Jasper):
<div data-role="page" id='Page1'>
<div data-role='button' id="Button1" >Open Dialog</div>
</div>
<div data-role="dialog" id='Dialog'>
<div data-role='header'id='Dialog_header'><h1>Dialog</h1></div>
<div data-role='button' id="Button2">Close</div>
</div>
<script>
Dialog_header.onclick= function(e){
$("#Dialog").fadeOut(500);
}
Button1.onclick = function(e) {
var $dialog=$("#Dialog");
if (!$dialog.hasClass('ui-dialog'))
{$dialog.page()};
$dialog.fadeIn(500);
}
Button2.onclick = function() {
$("#Dialog").fadeOut(500);
}
Button2 is a bonus: it shows how to close the dialog from code.
You can fiddle with it here:
http://jsfiddle.net/ghenne/Y5XVm/1/
You can force a width on the dialog like this:
.ui-mobile .ui-dialog {
background : none !important;
width : 75% !important;
}
Notice I also removed the background so the dialog can appear on top of the other page. The only problem that remains is that when you navigate to the dialog, the other page is hidden so the dialog appears on top of a white background.
Here is a demo: http://jsfiddle.net/jasper/TTMLN/
This is a starting point for you, I think the best way to create your own popup is to manually show/hide the dialog so jQuery Mobile doesn't hide the old page.
Update
You can certainly use a dialog as a popup with a small amount of custom coding:
$(document).delegate('#dialog-link', 'click', function () {
var $dialog = $('#dialog');
if (!$dialog.hasClass('ui-dialog')) {
$dialog.page();
}
$dialog.fadeIn(500);
return false;
});
Where dialog-link is the ID of the link that opens the dialog as a popup.
Here is a slight update to the CSS to center the modal horizontally:
.ui-mobile .ui-dialog {
background : none !important;
width : 75% !important;
left : 50% !important;
margin-left : -37.5% !important;
}
And here is a demo: http://jsfiddle.net/jasper/TTMLN/1/
here is a plugin that u can use..this plugin is also customizable with ur own html.
simpleDialogue plugin for jquery mobile