I am attempting to add and remove images contained in divs based on if they are locked or unlocked. Any divs that are unlocked are emptied and a new image is added accordingly.
function dieClicked(){
console.log(this);
if (this.locked == true){
this.locked = !this.locked;
$(this).css("border-bottom", "none");
}
else{
this.locked = !this.locked;
$(".pics").each(function(){
if (this.locked == true){
$(this).css("border-bottom", "solid red 5px");
}
});
}
}
function swapUnlocked(){
$(".pics").each(function(){
if (this.locked == false){
$(this).empty();
$(this).append("<img src='style/images/dice.png'/>")
}
});
}
Both of these functions are called in the main as follows:
$("#newRoll").on("click", swapUnlocked);
$(".pics").on("click",dieClicked);
newRoll is the id for a button, and .pics is the class that all of the divs belong to. Upon clicking a div in the .pics class, a red border will appear and the div will be locked. If the same div is clicked again, the border disappears and it is now unlocked.
When this code is executed, an image will switch as intended when it has been locked and then unlocked via the dieClicked function. However, when some or all of the divs have not been clicked (they are not locked or unlocked) those images do not switch, ie. they are treated as if they are locked. How can I get the images that have not been clicked to be treated as if they were unlocked?
You need to initialize the lock value:
$(".pics").on("click",dieClicked).each(function() { this.locked = false; });
ETA: Have you considered using CSS? You can streamline your code a bit and it would also help keep your styles centralized:
CSS
.locked { border-bottom: solid red 5px; }
JS
function dieClicked(){
$(this).toggleClass("locked");
}
function swapUnlocked(){
$(".pics:not(.locked)").each(function(){
$(this).empty();
$(this).append("<img src='style/images/dice.png'/>");
});
}
I'm not exactly sure if you mean that:
function dieClicked(){
console.log(this);
if (this.locked == true){
this.locked = !this.locked;
$(this).css("border-bottom", "none");
//$(this).remove(); //to delete
//$(this).hide(); //to hide -> can be shown with calling .show() on object
}
else{
this.locked = !this.locked;
$(".pics").each(function(){
if (this.locked == true){
$(this).css("border-bottom", "solid red 5px");
//$(this).show();
}
});
}
}
function swapUnlocked(){
$(".pics").each(function(){
if (this.locked == false){
$(this).empty();
$(this).append("<img src='style/images/dice.png'/>");
this.locked = true;
}
});
}
Related
I'm trying to add an autocomplete option to the title field in Wordpress - the titles of one of my custom document types will often (but not always) have a standard name.
I've hooked into Wordpress to add a div with an id of suggestions below title, and add a javascript onKeyUp event to title telling it to make an ajax request to a page that suggests names based on what's typed so far. This is all working fine.
Currently, however, I'm only able to select the suggestions via a mouseclick (which then uses val to update the value of #title. I'd also like users to be able to use the arrow keys to select a suggestion, a la Google.
I'm working on building this by giving each suggestion focus (each line is a li element with a dynamically generated tabindex.)
This works for a split second - the expected element gets the focus - but then it immediately loses it, going back to the body. Why is this happening?
Code for gethint.php:
<?php
$sofar = stripslashes($_GET['sofar']); // This is important as otherwise the url gets confused and won't work on anything with an apostrophe in it.
$common_file_names = array(
"Here's suggestion 1",
"This is suggestion 2",
"Suggestion 3");
if(strlen($_GET['sofar'])>1) { //Ignores single letters
echo '<ul id="autocomplete">';
$tabindex=0;
foreach ($common_file_names as $suggestion) {
if(false !== stripos($suggestion, $sofar)) : ?>
<li
tabindex="<?=$tabindex?>"
onClick="acceptSuggestion('<?=addslashes($suggestion)?>')"
onBlur="console.log('Lost focus!'); console.log(document.activeElement);";
><?=$suggestion?></li>
<?php $tabindex++; endif;
}
echo '</ul>';
}
?>
JS Code:
$.ajaxSetup({ cache: false });
window.onload = function () {
$( "<div id='suggestions'></div>" ).insertAfter( "#title" );
$(document).on('keydown', '#title', function (){
var hint_slash = this.value;
showHint(hint_slash);
checkKey(event);
});
$(document).on('focus', '#acf-field-extranet_client_area', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-field-extranet_document_type', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-date_picker', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-file-value', function (){
clearSuggestions();
});
console.log("Scripts loaded successfully");
}
function showHint(str) { //If the user has typed 2 or more characters, this function looks for possible matches among common document names to speed up data entry.
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("suggestions").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "/gethint.php?sofar=" + str, true);
xmlhttp.send();
}
function acceptSuggestion(str) {
$('#title').val(str); //Puts the clicked suggestion into the title box.
clearSuggestions();
}
function clearSuggestions() {
showHint(""); //Clears suggestions.
}
function checkKey(event) {
console.log('Key press: ' + event.keyCode);
if(40 == event.keyCode) {
event.preventDefault(); // Stops scrolling.
var autocomplete = $("#autocomplete");
$(autocomplete.children('li:nth-child(' + 2 + ')')).focus() ;
console.log(document.activeElement);
}
}
This is just test code currently, hence always setting focus to the 3rd child element.
I wouldn't try focus on the suggestions. You'll have to add the keychecking code to every suggestion in this case, because the input will lose focus. Instead, create a CSS class for the "focused" suggestion, remove the class on key up/down and add it to the previous/next suggestion...
$input.keyup(function(e) {
if(e.which == 38) {
// up key
var active = $('.suggestions li.active');
if(active.length) {
active.removeClass('active');
active.prev().addClass('active');
} else {
$('.suggestions li:last').addClass('active');
}
} else if(e.which == 40) {
// down key
var active = $('.suggestions li.active');
if(active.length) {
active.removeClass('active');
active.next().addClass('active');
} else {
$('.suggestions li:first').addClass('active');
}
}
});
Building on #evilunix's answer, I realised that each keystroke was resetting the #suggestions div, which meant that it could never hold focus (or keep an appended class etc).
So, wrote a new function called checkKey:
function checkKey(e) {
if(e.which == 38) {
// up key
e.preventDefault(); //Stops scrolling and cursor movement.
var active = $('#suggestions li.active');
if(active.length) {
active.removeClass('active');
active.prev().addClass('active');
} else {
$('#suggestions li:last').addClass('active');
}
} else if(e.which == 40) {
// down key
e.preventDefault(); //Stops scrolling and cursor movement.
var active = $('#suggestions li.active');
if(active.length) {
active.removeClass('active');
active.next().addClass('active');
} else {
$('#suggestions li:first').addClass('active');
}
} else if(e.which == 13) {
//Return key
e.preventDefault(); //Stops form submission.
acceptSuggestion(document.getElementsByClassName('active')[0].innerHTML);
} else {
console.log(e.which);
showHint($('#title').val());
}
}
and changed #title's onKeydown event to:
$(document).on('keydown', '#title', function (){
checkKey(event);
});
Now #suggestions only refreshes if the keystroke is not an up arrow, down arrow or return, and on a return runs acceptSuggestion on whichever li has the active class.
I'm trying to write a program in JavaScript in which certain functions must be performed before a button can be pressed again.
The button performs a function that should only be performed once per turn, but I want other actions to be performed before the next turn, and to have a sort of confirmation before progressing to the next turn. In psuedocode it might look something like this:
buttonFunction();
actionOne();
actionTwo();
turnOverConfirm();
etc.
But I'm not so sure how to do that. Right now the button can be pressed at any time. How do I make it so that the user must confirm before the button can be pressed again?
You can disable and enable buttons via javascript. You could block it like that:
document.getElementById("button").disabled = true
Just set it to false again to make it clickable again!
You can use the javascript confirm function. This function will popup a message box with ok and cancel
Here is an example
var r = confirm("Press a button!");
if (r == true) {
alert("OK was clicked");
} else {
alert("Cancel was clicked");
}
What you can do is when a user clicks on a button, popup a confirm box, then if they click ok you can then run the function you listed above.
There are few ways
You can hide the button till processing is ready or replace with an "please wait..." image
You can create an prevent varaible or remove temporary click event function
var Action = (function(){
var prevent = false;
function _start() {
if (prevent === false) {
prevent = true;
_process();
}
}
function _process() {
// DO Action
prevent = false;
}
return { start: _start }
})();
Fire
you can make event for evry click here is an example with alert and change button color all in one function
var clicked = 0;
var btn = document.getElementById("btn");
function clickBtn(){
if (clicked == 0) {
alert("it's first click");
btn.style.background = "black";
clicked = 1;
}else if (clicked == 1) {
alert("it's second click");
btn.style.background = "orange";
clicked = 2;
} else if (clicked == 2) {
alert("it's third click");
btn.style.background = "green";
clicked = 3;
}
}
#btn{
border-radius:15px 0 15px 0;
color:white;
border:none;
padding:15px;
background:blue;
font-weight:bold;
}
#btn:hover{
border-radius:0 15px 0 15px;
}
<button id="btn" onclick="clickBtn()">Click Me</button>
I am creating a Memory Game for a class at school, and I am using Bootstrap and jQuery. See Github. For testing use this jsfiddle, as the github code will change, I've included it if you would like to fork it for your own purposes.
I've constructed the code on the following logic:
Pick with how many cards you want to play.
Cards get loaded and randomized. Each pair have the same class(card* and glyphicon*).
You click on one card, then on another, and if they match they get discarded, else you pick again.
The problem that I'm currently having is with the third step, namely when you click on the third card it shows the previous two, meaning I need to include something to escape the first click events. At least that was my first suggestion for the problem. If you have other suggestions to completely restructure the third step, please don't shy to elaborate why.
// check if picked cards' classes match
jQuery("[class^=card]").click(function() { //picking the first card
jQuery(this).css('color', '#000');
var firstCard = $(this);
var firstCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
jQuery("[class^=card]").click(function() { //picking the second card
var secondCard = $(this);
var secondCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
console.log(firstCardClass);
console.log(secondCardClass);
if (firstCardClass == secondCardClass) {
console.log("yes")
$(firstCard).css('color', '#005d00'); //make them green
$(secondCard).css('color', '#005d00');
setTimeout(function() {
$(firstCard).css('display', 'none'); //discard
$(secondCard).css('display', 'none');
}, 1000);
}
else {
console.log("no");
$(firstCard).css('color', '#cc0000'); //make them red
$(secondCard).css('color', '#cc0000');
setTimeout(function() {
$(firstCard).css('color', '#fff'); //hide again
$(secondCard).css('color', '#fff');
}, 1000);
}
});
});
Note that the icons should be white as the cards, made them grey to see witch ones match without the need of firebug. If you click on more then two cards you will see what the problem is (if I failed to explain it well). I tried with including click unbind events in the end of each statement, but couldn't make it work.
Try your best! Thanks!
EDITED:
Seems I misunderstood the question so here's how I would go about having such game.
First I'll have my cards to have a structure like this:
<span class="card" data-card-type="one">One</span>
I'll use data-card-type to compare whether two cards are of the same type
I'll have a global variable firstCard which is originally null, if null I assign the clicked card to it and if not I compare the clicked card with it and then whether it's a match or not, I assign null to it meaning another pairing has begun.
I'll do all the logic in one onclick, looks weird to have a click listener inside another makes it to somehow look over-complicated.
var firstCard = null;
$('.card').on('click', function() {
$(this).addClass('selected');
if(!firstCard)
firstCard = $(this);
else if(firstCard[0] != $(this)[0]) {
if(firstCard.data('card-type') == $(this).data('card-type')) {
firstCard.remove();
$(this).remove();
firstCard = null;
//$('.card.selected').removeClass('selected');
}
else {
firstCard = null;
$('.card.selected').removeClass('selected');
}
}
});
jsfiddle DEMO
when a card is clicked, you can add a class to that particular card (e.g. classname clickedcard). Whenever you click another card you can test if there are 2 cards having this clickedcard class. If so, you can take action, for example remove all the clickedcard classes and add one again to the newly clicked one.
In pseudo code I would do it something like this:
jQuery("[class^=card]").click(function() {
if (jQuery('.clickedcard').length == 2) {
// two cards where clicked already...
// take the actions you want to do for 2 clicked cards
// you can use jQuery('.clickedcard')[0] and jQuery('.clickedcard')[1]
// to address both clicked cards
jQuery('.clickedcard').removeClass('clickedcard');
} else {
// no card or only one card is clicked
// do actions on the clicked card and add classname
jQuery(this).addClass('clickedcard');
}
});
You could use `one' (to bind an event once):
$("[class^=card]").one(`click', firstCard);
function firstCard() { //picking the first card
$(this).css('color', '#000');
var firstCard = $(this);
var firstCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
$("[class^=card]").one('click', secondCard);
function secondCard() { //picking the second card
var secondCard = $(this);
var secondCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
console.log(firstCardClass);
console.log(secondCardClass);
if (firstCardClass == secondCardClass) {
console.log("yes")
$(firstCard).css('color', '#005d00'); //make them green
$(secondCard).css('color', '#005d00');
setTimeout(function() {
$(firstCard).css('display', 'none'); //discard
$(secondCard).css('display', 'none');
}, 1000);
}
else {
console.log("no");
$(firstCard).css('color', '#cc0000'); //make them red
$(secondCard).css('color', '#cc0000');
setTimeout(function() {
$(firstCard).css('color', '#fff'); //hide again
$(secondCard).css('color', '#fff');
}, 1000);
}
$("[class^=card]").one(`click', firstCard);
}
}
At first visit my fiddle
When the submit button is being clicked if the text input field are unchanged alert appears. And the text input gets red border.
What I want is, how many input field is unchanged that doesn't matter, there will be only one alert to appear.
Here is my Jquery approach:
$(".submit").click(function (e) {
$(".textInput").each(function () {
if ($(this).val() === "input here") {
e.preventDefault();
$(this).css({
border: "1px solid #f00",
color: "#f00"
});
alert("Please input the texts in red box");
} else {
$(this).css({
border: "1px solid #DCDCDC",
color: "#000"
});
}
});
});
How can I do that?
Thank you
You just need to aggregate your answer before performing the alert:
$(".submit").click(function (e) {
var doAlert = false; // don't alert, unless the condition sets this to 'true'
$(".textInput").each(function () {
if ($(this).val() === "input here") {
e.preventDefault();
$(this).css({
border: "1px solid #f00",
color: "#f00"
});
// instead of performing the alert inside the "loop"
// set a flag to do it once the "loop" is complete.
doAlert = true;
} else {
$(this).css({
border: "1px solid #DCDCDC",
color: "#000"
});
}
});
if(doAlert) { // do the alert just once, if any iteration set the flag
alert("Please input the texts in red box");
}
});
Sth like that would help with a flag variable:
$(".submit").click(function (e) {
e.preventDefault();
var error = false;
$(".textInput").each(function () {
if ($(this).val() === "input here") {
$(this).css({
border: "1px solid #f00",
color: "#f00"
});
error = true;
} else {
$(this).css({
border: "1px solid #DCDCDC",
color: "#000"
});
}
});
if(error == true) alert("Please input the texts in red box");
});
just initiate a variable for example Count
and when your condition ($(this).val() === "input here") is true make it counter by 1 i-e Count+=1;
and in the end put one condition if (Count>0){ alert("Please input the texts in red box");}
While you've already accepted an answer, I'd suggest a simpler approach:
$(".submit").click(function (e) {
e.preventDefault();
/* 1. gets the input elements,
2. sets their border-color back to that specified,
3. filters the collection, keeping only those elements without a value,
4. sets the border-color of only those empty inputs to red,
5. assigns the length property of the collection to the variable.
*/
var empties = $('.textInput').css('border-color', '#ccc').filter(function () {
return !this.value;
}).css('border-color', 'red');
// if the length is greater than zero, triggers the (single) alert:
if (empties.length) {
alert('please fill out the red-boxes');
}
});
JS Fiddle demo.
I have a JavaScript function that looks like this:
function UpdateFilterView() {
if (_extraFilterExists) {
if ($('#F_ShowF').val() == 1) {
$('#extraFilterDropDownButton').attr('class', "showhideExtra_up");
$('#extraFilterDropDownButton').css("display", "block");
if ($('#divCategoryFilter').css("display") == 'none') {
$('#divCategoryFilter').show('slow');
}
return;
} else {
if ($('#divCategoryFilter').css("display") == 'block') {
$('#divCategoryFilter').hide('slow');
}
$('#extraFilterDropDownButton').css("display", "block");
$('#extraFilterDropDownButton').attr('class', "showhideExtra_down");
return;
}
} else {
if ($('#divCategoryFilter').css("display") != 'none') {
$('#divCategoryFilter').hide('fast');
}
$('#extraFilterDropDownButton').css("display", "none");
}
}
This will be triggered by the following code (from within the $(document).ready(function () {}):
$('#extraFilterDropDownButton').click(function() {
if ($('#F_ShowF').val() == 1) {
$('#F_ShowF').val(0);
} else {
$('#F_ShowF').val(1);
}
UpdateFilterView();
});
The HTML for this is easy:
<div id="divCategoryFilter">...</div>
<div style="clear:both;"></div>
<div id="extraFilterDropDownButton" class="showhideExtra_down"> </div>
I have two problems with this:
When the panel is hidden and we press the div button (extraFilterDropDownButton) the upper left part of the page will flicker and then the panel will be animated down.
When the panel is shown and we press the div button the panel will hide('slow'), but the button will not change to the correct class even when we set it in the UpdateFilterView script?
The correct class will be set on the button when hovering it, this is set with the following code:
$("#extraFilterDropDownButton").hover(function() {
if ($('#divCategoryFilter').css("display") == 'block') {
$(this).attr('class', 'showhideExtra_up_hover');
} else {
$(this).attr('class', 'showhideExtra_down_hover');
}
},
function() {
if ($('#divCategoryFilter').css("display") == 'block') {
$(this).attr('class', 'showhideExtra_up');
} else {
$(this).attr('class', 'showhideExtra_down');
}
});
To set a class completely, instead of adding one or removing one, use this:
$(this).attr("class","newclass");
Advantage of this is that you'll remove any class that might be set in there and reset it to how you like. At least this worked for me in one situation.
Use jQuery's
$(this).addClass('showhideExtra_up_hover');
and
$(this).addClass('showhideExtra_down_hover');
<script>
$(document).ready(function(){
$('button').attr('class','btn btn-primary');
}); </script>
I like to write a small plugin to make things cleaner:
$.fn.setClass = function(classes) {
this.attr('class', classes);
return this;
};
That way you can simply do
$('button').setClass('btn btn-primary');