I have a a number of buttons that a user can click on in response to a question. Some of the buttons are correct answers, and others are incorrect. If the button is an incorrect answer, the button remains live, but a counter increments counting wrong answers. If the button is a correct answer, then I want to increment the correct answer count, change the button styling, and disable the button. Code snippet (html):
<div class="container" ng-controller="myCtrl">
<div>
Right answers: {{ right_answers }}
</div>
<div>
Wrong answers: {{ wrong_answers }}
</div>
<button ng-style="answer1Style" ng-click="clickThis('answer1')" ng-disabled='answer1'> Answer1 </button>
<button ng-style="answer2Style" ng-click="clickThis('answer2')" ng-disabled='answer2'> Answer2 </button>
<button ng-style="answer3Style" ng-click="clickThis('answer3')" ng-disabled='answer3'> Answer3 </button>
<button ng-click="clickThis('wrong1')" ng-disabled='wrong1'> Wrong1 </button>
<button ng-click="clickThis('wrong2')" ng-disabled='wrong2'> Wrong2 </button>
<button ng-click="clickThis('whatever')" ng-disabled='whatever'> Whatever </button>
</div>
Code snippet (controller):
var myCtrl = function($scope) {
$scope.right_answers = 0;
$scope.wrong_answers = 0;
$scope.answers = ['answer1','answer2','answer3'];
$scope.clickThis = function(answer) {
if ($scope.answers.indexOf(answer) != -1) {
$scope.right_answers += 1;
switch(answer){
case 'answer1':
$scope.answer1 = true;
$scope.answer1Style = {'background-color':'green', 'color':'white'};
break;
case 'answer2':
$scope.answer2 = true;
$scope.answer2Style = {'background-color':'green', 'color':'white'};
break;
case 'answer3':
$scope.answer3 = true;
$scope.answer3Style = {'background-color':'green', 'color':'white'};
break;
};
}
else {
$scope.wrong_answers += 1;
};
};
};
My question is, is there a way to make this more generic, where I don't have to use a CASE and include a $scope for each individual answer in order to disable it (or change the style for that matter), i.e. ng-disabled="answer1", ng-disabled="answer2", $scope.answer1, $scope.answer2?
Thanks!
You can pass $event object as argument of ngClick directive.
<button ng-click="clickThis($event, 'answer')"> Answer </button>
Then you will be able to do manipulations with target element in $scope.clickThis function
$scope.clickThis = function(event, answer) {
if ($scope.answers.indexOf(answer) != -1) {
$scope.rightAnswers += 1;
element = angular.element(event.target);
element.css({'color': 'white', 'background-color': 'green'});
element.prop('disabled', true)
} else {
$scope.wrongAnswers += 1;
};
}
Example: plnkr.co
Related
I'm trying to use a chrome extension (shortkeys) to create shortcut keys that can press buttons within our warehouse management system (so they can be matched to barcodes).
One of the buttons has no ID, and once it has been clicked the button innertext changes. Ideally I'd like the shortcut to work on either version of the button
It is either
<input type="submit" value="Create Shipment" class="btn btn-success pull-right">
or
<a class="btn btn-success" href="/Order/OrderDocumentP/15467" target="_blank">Print Label</a>
I then have another button to be assigned to a different shortcut key
<a class="btn btn-success" href="/Picking/DespatchOrder?OrderId=13413">Despatch</a>
But I'm sure once I've figured out the first one the next will be easier :)
Any help greatly appreciated, I've been through a number of other questions that are similar but not quite what I'm after and my JS knowledge is pretty rubbish
Learn CSS a bit and use https://developer.mozilla.org/ru/docs/Web/API/Document/querySelector
Your extensions probaply supports that
// cuz I don't like to type long "document.querySelector"
q = sel => document.querySelector(sel)
qq = sel => document.querySelectorAll(sel)
function clickOnly(sel) {
let list = qq(sel);
if (list.length == 1) list[0].click();
else alert('element "'+sel+'" is not unique!');
}
// handles *any* keypress
onkeypress = function (event) {
if (event.target.tagName == "INPUT") return; // noop on input focused
if (event.target.tagName == "TEXTAREA") return; // noop on input focused
console.log(event.code); // to see what the key is
let rawCode = event.code; // keyboard key, `KeyM` for M, `Digit7` for 7, `Slash` for /
let code = rawCode; // make CtrlAltShiftKeyM
if (event.shiftKey) code = 'Shift' + code;
if (event.altKey) code = 'Alt' + code;
if (event.ctrlKey) code = 'Ctrl' + code;
if (!kds[event.code]) return;
event.preventDefault(); // prevent CtrlKeyM browser handler for bookmarks or whatever
kds[event.code](event);
}
kds = {}
// it's a function so starts with `() => `
kds.KeyM = () => alert('it works!')
// a is for <a>, [href^=] is for href starts with
kds.ShiftKeyM = () => clickOnly('a[href^="/Order/OrderDocumentP/]')
// , is for one of multiple selectors
kds.CtrlKeyM = () => clickOnly('input[value="Create Shipment"], a[href^="/Order/OrderDocumentP/]')
This is a simple script on getting a button by class name and clicking it. I think this is what you are looking for, if not let me know I will rewrite it.
EDIT: I added a loop that will click all buttons or links found with the class name btn-success
I've inserted a second function so people looking for a solution by classname can also still find the first one. AutoClickBtnByValue() will click the button with inner text "click me now".
function AutoClickBtn() {
var button = document.getElementsByClassName("btn-success");
for (var i = 0; i < button.length; i++) {
button[i].click();
console.log('Success! Clicked button' + i);
}
}
setInterval(AutoClickBtn, 2000);
/* Click button by innerHTML text */
function AutoClickBtnByValue() {
var button = document.getElementsByClassName("btn-success");
for (var i = 0; i < button.length; i++) {
if (button[i].innerHTML.indexOf('click me now') > -1) {
button[i].click();
console.log('Success! Clicked button' + i + ' with value: "click me now" ');
}
}
}
setInterval(AutoClickBtnByValue, 2000);
<input type="submit" value="Create Shipment" class="btn btn-success pull-right">
<a class="btn btn-success" href="#" target="_blank">Print Label</a>
<a class="btn btn-success" href="#">Despatch</a>
<button class="btn-success">click me now</button>
I am in the process of learning Javascript and at the moment I'm only using vanilla js to code stuff.
I'm trying to make 2 button (+ and -) to add and subtract a number.
Here's what I have so far:
let value = document.querySelector("#number");
let add = document.querySelector("#add").addEventListener("click", function(value){
add = value++;
document.querySelector("#number").textContent = add;
});
With the above code, when I click my button my p tag changes to NaN. It is 0 form the start.
Goal it to make it 1.
In case you need the HTML code then this is what I have:
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
You need to set a global var and add and subtract value on that.
You also need to check value is more then zero using ternary operator (if condition) so that the value is always displayed above zero when subtracting
Live Demo
let value = document.querySelector("#number");
//Store value
let valueNumber = 0
//Add value
document.querySelector("#add").addEventListener("click", function(value) {
valueNumber++;
document.querySelector("#number").textContent = valueNumber;
});
//Subtract value
document.querySelector("#sub").addEventListener("click", function(value) {
valueNumber--;
document.querySelector("#number").textContent = valueNumber > 0 ? valueNumber : 0;
});
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
Even though the answer has been given, I'd like to share mine.
document.querySelector("#add").onclick = function(){
let num = number.innerText;
number.innerText = num/1 + 1;
}
document.querySelector("#sub").onclick = function(){
let num = number.innerText;
if(num > 0){
number.innerText = num/1 - 1;
}
}
<div class="content">
<button id="add">+</button>
<p id="number">0</p>
<button id="sub">-</button>
</div>
I'm making a search engine program. People can ask questions and it will be listed in a different div. People can then click a question listed to answer it, and the answer (and that particular question) will be listed in another div.
But my code only shows the last question entered in the answer list. So if there are 3 questions and a user answered the first one, the expected output is:
Question 1?
Ans: Answer 1
But the actual output is:
Question 3?
Ans: Answer 1
function separate()
{
var question = document.createElement("p");
question.innerHTML = document.getElementById("qInput").value;
document.getElementById("stackDisplay").appendChild(question);
question.addEventListener("click", answerBox);
}
function answerBox(ques)
{
document.getElementById("answerBox").style.display = "block";
}
var i =1;
function collectAns() {
if(event.key === 'Enter') {
var quest = document.getElementById("qInput").value;
var ans = document.getElementById("ansSpace").value;
document.getElementById("ansDisplay").innerHTML += i+") "+quest+"<br> Ans: "+ans+"<br><br>";
document.getElementById("answerBox").style.display = "none";
i+=1;
}
}
<div class="search">
<input type="text" placeholder="Search.." name="search" id="qInput">
<button type="submit" onclick="separate()">
<i class="fa fa-search"></i>
</button>
</div>
<div class="stack">
<span id="stackDisplay">
<center><b><u> LIST OF QUESTIONS</u></b></center>
<button id="close" onmouseover="clo()"> × </button>
</span>
<button onmouseover="list()"> ☰ </button>
</div>
<div class="ans">
<span id="ansDisplay">
<center><b><u> LIST OF ANSWERS</u></b></center>
<button id="closeans" onmouseover="closeans()"> × </button>
</span>
<button onmouseover="listans()">
<i class="fa fa-commenting-o"></i>
</button>
</div>
<div id="answerBox">
<center><b> Write your answer:</b></center>
<button id="closeans" onmouseover="closeansbox()"> × </button>
<textarea id="ansSpace" placeholder="Your answer here..." onkeydown="collectAns()"></textarea>
</div>
I know it's because of var quest = document.getElementById("qInput").value; so it only takes the last question, but I don't know what to write instead of this.
I tried adding question.addEventListener("click", function(){collectAns(ques)}); in the separate() but it prints undefined instead of the question.
I tried adding var q = document.getElementById("stackDisplay").children; in the collectAns() but I don't know which question they'll click so I can't give the index, so I wrote q[this] when printing, and it still gives undefined.
What should I do to make it show the question? (without jquery or php if possible, just html, css, javascript)
I removed unnecessary stuff to answer the question.
The idea is to call collectAns with the question as argument. To do that you can use the bind method.
As you are adding eventListners, you will need to remove old ones to prevent them to be executed too. The difficulty to remove old ones is that you don't know their name, they are anonymous because of the use of bind. You could store them in an array but it is simplier to clone the node, which do not clone the eventlistners attached to it.
function separate() {
var question = document.createElement("li");
question.innerHTML = document.getElementById("qInput").value;
document.getElementById("stackDisplay").appendChild(question);
question.addEventListener("click", answerBox);
}
function answerBox() {
const answerbox = document.getElementById("answerBox");
const question = this.innerText;
answerbox.querySelector('.ques').innerText = question;
// find textarea, clone it and remove it
// this is to remove any eventListener from it.
const textarea = answerbox.querySelector('textarea');
const new_textarea = textarea.cloneNode();
textarea.remove();
// add new eventListner with question as parameter
new_textarea.addEventListener('keydown', collectAns.bind(null, this.innerText));
answerbox.appendChild(new_textarea);
// display answer box
answerbox.style.display = "block";
}
var i = 1;
function collectAns(ques) {
if (event.key === 'Enter') {
var ans = document.getElementById("ansSpace").value;
document.getElementById("ansDisplay").innerHTML += i + ") " + ques + "<br> Ans: " + ans + "<br><br>";
document.getElementById("answerBox").style.display = "none";
i += 1;
}
}
<div class="search">
<input type="text" placeholder="Question.." name="search" id="qInput">
<button type="submit" onclick="separate()">
add
</button>
</div>
<h4>LIST OF QUESTIONS:</h4>
<ul id="stackDisplay"></ul>
<h4>LIST OF ANSWERS</h4>
<ul id="ansDisplay"></ul>
<div id="answerBox">
<div>Write your answer to question "<span class="ques"></span>":</div>
<textarea id="ansSpace" placeholder="Your answer here..."></textarea>
</div>
I am making a To-do list, where I want to be able to add new tasks, and delete tasks that are checked off. However, it seems my function just deletes all tasks, not just the ones that are checked off. Neither does it seem to allow new tasks to be added.
html:
<h1 id="title"> To-do list</h1>
<div id="task_area">
</div>
<input type="text" id="putin"></input>
<button id="add">add</button>
javascript:
<button id="clear">Clear completed tasks</button>
var tasks = document.getElementById("task_area")
var new_task = document.getElementById("add")
var clear = document.getElementById("clear")
new_task.addEventListener("click", function() {
var putin = document.getElementById("putin")
var input = document.createElement('input')
input.type = "checkbox"
var label = document.createElement('label')
label.appendChild(document.createTextNode(putin.value))
task_area.appendChild(input)
task_area.appendChild(label)
})
clear.addEventListener("click", function() {
for (i = 0; i < task_area.children.length; i++) {
if (task_area.children[i].checked === true) {
task_area.remove(tasks.children[i])
}
}
})
jsfiddle: https://jsfiddle.net/4coxL3um/
.remove removes the element you are calling it from, and doesn't take an argument for what to remove. The following:
task_area.remove(tasks.children[i])
should be
tasks.children[i].remove()
EDIT: As Mononess commented below, this will only remove the checkboxes and not the labels. While you could delete both using Jayesh Goyani's answer below, it's probably better that each input/label pair be wrapped in a single div or span for easier management.
You could try adding an event listener to each child of task_area that calls the below function. Haven't gotten a chance to test it out, and may not fulfill all of your requirements, but should get the job done.
function removeClicked() {
this.parentNode.removeChild(this);
}
Please try with the below code snippet. Below code will help you to remove selected checkbox with label.
<body>
<h1 id="title">To-do list</h1>
<div id="task_area">
</div>
<input type="text" id="putin" />
<button id="add">add</button>
<button id="clear">Clear completed tasks</button>
<script>
var tasks = document.getElementById("task_area")
var new_task = document.getElementById("add")
var clear = document.getElementById("clear")
new_task.addEventListener("click", function () {
var putin = document.getElementById("putin")
var input = document.createElement('input')
input.type = "checkbox"
var label = document.createElement('label')
label.appendChild(document.createTextNode(putin.value))
task_area.appendChild(input)
task_area.appendChild(label)
//document.getElementById("task_area").innerHTML = putin.value
})
clear.addEventListener("click", function () {
for (i = 0; i < task_area.children.length; i++) {
if (task_area.children[i].checked === true) {
tasks.children[i].nextSibling.remove();
tasks.children[i].remove();
}
}
})
</script>
</body>
Please let me know if any concern.
I'm trying to get the value of each button, but what i get is the value of the first button. This is my content
<div class="my_btn">
<button id="id_button" value="page-1">Page One</button>
<button id="id_button" value="page-2">Page Two</button>
<button id="id_button" value="page-3">Page Three</button>
<button id="id_button" value="page-4">Page Four</button>
</div>
and this is my script
jQuery('.my_btn').on('click',function(){
var my_content = jQuery('#id_button').val();
var my_link = '<li>Link</li>';
if( !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden()) {
jQuery('textarea#content').val(my_link);
} else {
tinyMCE.execCommand('mceInsertContent', false, my_link);
}
});
Basically this is a wordpress function. I'm trying to add different links inside the textarea box.
Thanks in advance
Apply the event listener to the buttons instead of the wrapper, then get the value with this.value.
jQuery('.my_btn button').on('click',function(){
var my_content = this.value;
var my_link = '<li>Link</li>';
if( !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden()) {
jQuery('textarea#content').val(my_link);
} else {
tinyMCE.execCommand('mceInsertContent', false, my_link);
}
});
Also, you should use unique values for each id attribute. While it won't effect this script, if you try to select by id then it will only affect the first element with that id.
jQuery('.my_btn button').on('click',function(){
var my_content = this.value;
alert(my_content);
/*var my_link = '<li>Link</li>';
if( !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden()) {
jQuery('textarea#content').val(my_link);
} else {
tinyMCE.execCommand('mceInsertContent', false, my_link);
}*/
});
<div class="my_btn">
<button id="id_button_1" value="page-1">Page One</button>
<button id="id_button_2" value="page-2">Page Two</button>
<button id="id_button_3" value="page-3">Page Three</button>
<button id="id_button_4" value="page-4">Page Four</button>
</div>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
first off id_button should be a class because it is on multiple elements
second your first jquery command should look like this, this way it will handle the button click and get the correct value
jQuery('.my_btn').on('click', '.id_button',function(){
var my_content = $(this).val();
var my_link = '<li>Link</li>';
if( !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden()) {
jQuery('textarea#content').val(my_link);
} else {
tinyMCE.execCommand('mceInsertContent', false, my_link);
}
});