I’m facing a small issue in JavaScript. I need to to make a code stop and do nothing for a while. I tried setTimeout, but it only scheludes the function, continues in executing the code and then comes back. I really need to wait for the user to put some value in the input field and then press the button. The sleep function on the beginning of my code works, but the code somehow stops showing my html input form and button. I can’t figure out why. I also can’t use onclick attribute on the submit button, because of the same problem. Does someone know what can be the problem here??
var returning = 0; // variable for deciding which part of function to use
function sleep(milliseconds) { // sleep method found here on stackoverflow
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function acceptValue(){
// show an input field with button next to it
if (returning == 0) {
var co = document.createElement("input"); // show input field and set attributes
var kam = document.getElementById("telo");
var indexId = 0;
while(document.getElementById("pole" + indexId) != null) {
indexId++; // look for closest unused id name
}
co.setAttribute("id", "pole" + indexId);
kam.appendChild(co);
var co1 = document.createElement("input");
var kam1 = document.getElementById("telo");
var indexId1 = 0;
while(document.getElementById("cudlik" + indexId1) != null) {
indexId1++; // look for closest unused id name
}
co1.setAttribute("id", "cudlik" + indexId1); // show button and set attributes
co1.setAttribute("type", "submit");
co1.setAttribute("value", ">");
co1.setAttribute("onclick", "vraceni()");
kam1.appendChild(co1);
console.log(document);
document.getElementById("telo").appendChild(document.createElement("br"));
returning = 1;
acceptValue();
} else if (vrat == 1) {
sleep(500);
acceptValue();
}
} else {
var indexPole = 0;
while (document.getElementById("pole" + indexPole) != null) {
indexPole++;
}
vrat = 0;
return document.getElementById("pole" + (indexPole - 1)).value; // return the value from last shown input field
}
}
function returnFunc() {
vrat = 2; // called from html button
}
Thanks,
Adam Hendrych
I think the feature you are attempting to create here may need some re-architecting. It feels very strange to have all these while loops and sleep tricks in place.
What you describe wanting this code to do is basically the default behavior of how inputs and buttons work. A simple form containing an input and submit button, with an onsubmit handler on the form, should meet the "accept input and fire an action when the button is pressed" requirement.
An example
Related
Working on a JavaScript program, and the first thing that happens when run is asking the user whether they want to enter something using prompt()s, or using a textarea. The textarea option comes with a clickable button element to press once the user has entered everything they want into the textarea.
If this option is chosen, I want the rest of my program to not run until this button is clicked, and the user is confirming that they are finished with their input. Currently I have the button code within the selection part (where the user has chosen to use a textarea), as below:
if (trimmedResponse == 'manual') {
... (irrelevant code)
} else { //if paste is chosen
var createArray = function(howMany){
var pasteInput = document.createElement("TEXTAREA");
var makingArray = [];
document.body.appendChild(pasteInput);
pasteInput.rows = howMany;
let done = document.createElement("button");
done.innerHTML = 'Enter terms';
done.onclick = function(){
for (var j = 0; j < howMany; j++){
makingArray[j] = String((pasteInput.value).replace(/ /g,'').split('-')).split('\n');
}
pasteInput.style.display = 'none';
done.style.display = 'none';
}
document.body.appendChild(done);
return makingArray;
}
termArray = window.createArray(numOfTerms); //getting a variable holding the array from the prior function, to access later
}
The rest of the script.js file is made up of the regular subroutines - preload, setup, draw, and some initialisation and other small methods in the open scope before preload(), as below in a greatly reduced format:
let BG;
let translateEdit = document.createElement("button");
translateEdit.innerHTML = "Edit a translation";
translateEdit.style.position = 'absolute';
translateEdit.style.left = '50px';
translateEdit.style.top = '130px';
let list = "";
translateEdit.onclick = function () {
this.blur();
do {
replaceChoice = prompt("Which translation do you want to edit? (1-"+numOfTerms+") \n"+list+" \nOr enter any letter to leave this screen.");
} while (replaceChoice < 1 || replaceChoice > termArray.length)
termArray[replaceChoice-1][1] = prompt("What is the new translation for the term "+termArray[replaceChoice-1][0]+"?");
list = "";
for (let i = 0; i < numOfTerms ; i++){
list += ((i+1)+". ["+termArray[i][0] + "] - [" + termArray[i][1] + "]\n") //adds each term and translation in a user-friendly / clear display to the list variable for later display
}
alert("The term list currently looks as follows: \n"+list);
};
document.body.appendChild(translateEdit);
let temp1;
let temp2;
let temp3;
var performanceDisplay = "";
function preload() { //function loading image from file into variable
Helvetica = loadFont('Helvetica-Bold.ttf');
BG = loadImage('images/background.png');
}
function setup() { //function to create display/background using image file and dimensions and instantiate objects (character,terms,counters) as well as slider and icon to be displayed for it
alert("Below are the terms you have entered: \n" + list + "If any of the above are incorrect, use the edit buttons on the next screen to adjust terms or translations.");
speakericon = loadImage('images/speaker.png');
createCanvas(width, height);
... (further code in setup())
}
function draw() { //make background + objects visible on screen, allow them to act as they must, creating new terms when necessary, calling functions in class files such as player movement (calls all functions in classes throughout function) - all run every tick
image(BG, 0, 0, width, height); //set the display to the background image from BG variable in preload()
... (further code in draw())
}
In essence, I need to stop everything else from running until the button 'done' is clicked, and would appreciate any help with anything to achieve this.
How do I use Jquery to find the last checked/unchecked item and so that I can add or remove them from other two listboxs?
I am creating a dropdown listbox(excludedPeople) with multiselect checkbox with two other listboxs(PrimaryPerson,secondaryPerson) in same form. All three list box are having same set of data during form load. If any item in excludedPeople is selected(checked), I need to remove that item from PrimaryPerson and secondaryPerson and vise-versa.
ASP.Net MVC multiselect Dropdown Listbox code:
#Html.ListBoxFor(m => m.ExcludedPeople, Model.AllPeopleListViewModel,
new { #class = "chkDrpDnExPeople" , #multiple = "multiple"})
jQuery code:
$(".chkDrpDnExPln").change(function ()
{
console.log("Trigger" + $(this).val()); //this code gets the list of all items selected. What I need is to log only last selected/unselected item's val & text into the console.
});
Any help is appreciated. Ask questions if any.
Well, after waiting for 2 days I made a solution myself and posting it here so that others can make use of it.
I made this code for multiselect dropdown listbox with checkboxes in each list item. I expect this to work on similar controls like checked listbox but haven't tested it.
I followed register control and get notified by event so the usage can be made seamless without getting into details.
Usage:
1) include the "JQuery based Library" part into your project as shared or same js script file.
2) Use the below approach to consume the functionality. The event should get you the changed values when the control selection is changed.
RegisterSelectedItemChangeEvent("chkDrpDnctrl#1");
RegisterSelectedItemChangeEvent("chkDrpDnctrl#2");
RegisterSelectedItemChangeEvent("chkDrpDnctrl#3");
$(".chkDrpDnctrl").on("OnSelectionChange", function (e,eventData)
{
var evntArgs = {
IsDeleted: false,
IsAdded: false,
AddedValues: [], //null if no change/None. Else changed value.
DeletedValues: [] //null if no change/None. Else changed value.
};
var source = e;
evntArgs = eventData;
var elementnm = $(this).attr("id");
if (evntArgs !== "undefined" && elementnm != "")
{
if (evntArgs.IsAdded == true)
{
//if excluded checked then remove.
for (var i = 0; i < evntArgs.AddedValues.length; i++)
{
PerformAction (control#, evntArgs.AddedValues[i]);
}
}
if (evntArgs.IsDeleted == true)
{
//if excluded checked then remove.
for (var i = 0; i < evntArgs.DeletedValues.length; i++)
{
PerformAction (control#, evntArgs.AddedValues[i]);
}
}
}
});
JQuery based Library:
function RegisterSelectedItemChangeEvent(selector) {
var dropdownElementRef = selector;
//Intializes the first time data and stores the values back to control. So if any of the checkboxes in dropdown is selected then it will be processe and added to control.
$(dropdownElementRef).data('lastsel', $(dropdownElementRef).val());
var beforeval = $(dropdownElementRef).data('lastsel');
var afterval = $(dropdownElementRef).val();
//storing the last value for next time change.
$(dropdownElementRef).data('lastsel', afterval);
//get changes details
var delta = GetWhatChanged(beforeval, afterval);
//stores the change details back into same object so that it can be used from anywhere regarless of who is calling it.
$(dropdownElementRef).data('SelectionChangeEventArgs', delta);
//prepares the event so that the same operation can be done everytime the object is changed.
$(dropdownElementRef).change(function () {
var beforeval = $(dropdownElementRef).data('lastsel');
var afterval = $(dropdownElementRef).val();
//storing the last value for next time change.
$(dropdownElementRef).data('lastsel', afterval);
//get changes details
var delta = GetWhatChanged(beforeval, afterval);
//stores the change details into same object so that it can be used from anywhere regarless of who is calling it.
$(dropdownElementRef).data('OnSelectionChangeEventArgs', delta);
//fires the event
$(dropdownElementRef).trigger('OnSelectionChange', [delta]);
//$.event.trigger('OnSelectionChange', [delta]);
});
var initdummy = [];
var firstval = GetWhatChanged(initdummy, afterval);
//fires the event to enable or disable the control on load itself based on current selection
$(dropdownElementRef).trigger('OnSelectionChange', [firstval]);
}
//assume this will never be called with both added and removed at same time.
//console.log(GetWhatChanged("39,96,121,107", "39,96,106,107,109")); //This will not work correctly since there are values added and removed at same time.
function GetWhatChanged(lastVals, currentVals)
{
if (typeof lastVals === 'undefined')
lastVals = '' //for the first time the last val will be empty in that case make both same.
if (typeof currentVals === 'undefined')
currentVals = ''
var ret = {
IsDeleted: false,
IsAdded: false,
AddedValues: [], //null if no change/None. Else changed value.
DeletedValues: [] //null if no change/None. Else changed value.
};
var addedvals;
var delvals;
var lastValsArr, currentValsArr;
if (Array.isArray(lastVals))
lastValsArr = lastVals;
else
lastValsArr = lastVals.split(",");
if (Array.isArray(currentVals))
currentValsArr = currentVals;
else
currentValsArr = currentVals.split(",");
delvals = $(lastValsArr).not(currentValsArr).get();
if (delvals.length > 0)
{
//console.log("Deleted :" + delvals[0]);
for (var i = 0; i < delvals.length; i++)
{
ret.DeletedValues.push(delvals[i]);
}
ret.IsDeleted = true;
}
addedvals = $(currentValsArr).not(lastValsArr).get();
if (addedvals.length > 0)
{
//console.log("Added:" + addedvals[0]);
for (var i = 0; i < addedvals.length; i++)
{
ret.AddedValues.push(addedvals[i]);
}
ret.IsAdded = true;
}
return ret;
};
I'm trying to figure out a way to automatically randomize slider positions (type range) when I come across them on a webpage (mostly on web survey forms like Qualtrics or Surveymonkey). I would like to add this slider randomization to an already-existing autofill that I demonstrated below. But first, here are a couple examples of the type of sliders I would like to automate (with CSS/HTML):
&
Currently, I'm using the following script to randomly autofill survey forms on page load (radio buttons, text fields, etc). I would like to add slider randomization in the same vein to this script:
// ==/UserScript==
(function() {
// Save a random number
var modifier = Math.floor(Math.random() * 9000000);
// Create a fake user data
var user = {
pass : modifier + "",
mail : modifier + '#Example.com'
};
// Array to save data
var save_data = [];
// Check window for tags
function check(win, tagName) {
try {
// Get tags
tagName = win.document.getElementsByTagName(tagName)
} catch (e) {
// Not found - Empty array
tagName = []
}
// For each tag
for (i = 0; i < tagName.length; i++) {
// This tag
var tag = tagName[i];
// Exclude read-only or desabled
if (tag.readOnly || tag.disabled) continue;
// Get tag values
var name = tag.name;
var type = tag.type;
var value = tag.value;
// If Check box
if ('checkbox' == type){
tag.checked = Math.random() > .5;
}
// If password
else if ('password' == type){
value = user.pass;
// Update tag value
tag.value = value;
}
// If text
else if ('text' == type) {
// If mail
if(name.match(/mail/i)){
value = user.mail;
}
// Update tag value
tag.value = value;
}
// If radio
else if ('radio' == type) {
// If data don't exist
if (!save_data[name]) {
save_data[name] = 1;
}else{
save_data[name] ++;
}
// Check it with probabilities (depending on the length)
tag.checked = Math.random() < (1 / save_data[name]);
}
// If select
else if (type.match(/^select/)){
// Set a random options
tag.selectedIndex = Math.random() * (tag.options.length - 1) + 1;
}
}
// Try to set focus to the input
if (tag) try {
tag.focus()
} catch (e) {}
}
function recursive(win) {
check(win, 'password');
check(win, 'select');
check(win, 'input');
// For each frame on page
for (var i = 0; i < win.frames.length; i++) {
// Check all frames inside
recursive(win.frames[i])
}
}
recursive(window);
}());
Since I know that sliders are of the input type range, my added code would need to start with something that looks like this:
else if ('range' == type) {
if (!save_data[name]) {
save_data[name] = 1;
}else{
save_data[name] ++;
}
tag.checked = Math.random() < (1 / save_data[name]);
}
As you can see, I am basing this code off the radio button portion of the script. Unfortunately, this doesn't seem to work, and I am currently unable to find the syntax for how to select a new slider position or initiate the movement of a slider. I assume it works differently than a clickable check box or radio button. I know that sliders have ranges generally specified in the CSS/HTML, so this will obviously need to be accoutned for. Any and all help would be absolutely wonderful. Thanks in advance.
From w3school:
Change the value of a slider control:
document.getElementById("myRange").value = "75";
Tweaked it a bit to make it random (if your input range is between 0 and 100):
document.getElementById("myRange").value = Math.floor(Math.random() * 100);
I am working client side on a web page that I am unable to edit.
I want to use JS to click on a particular button, but it does not have a unique identifier.
I do know the class and I do know a (unique) string in the innerHTML that I can match with, so I am iterating through the (varying number) of buttons with a while loop looking for the string:
var theResult = '';
var buttonNum = 0;
var searchString = '720p';
while (theResult.indexOf(searchString) == -1
{
theResult = eval(\"document.getElementsByClassName('streamButton')[\" + buttonNum + \"].innerHTML\");
buttonNum++;
}
Now I should know the correct position in the array of buttons (buttonNum-1, I think), but how do I reference this? I have tried:
eval(\"document.getElementsByClassName('streamButton')[\" + buttonNum-1 + \"].click()")
and variation on the position of ()'s in the eval, but I can't get it to work.
You could try something like:
var searchStr = '720p',
// Grab all buttons that have the class 'streambutton'.
buttons = Array.prototype.slice.call(document.querySelectorAll('button.streamButton')),
// Filter all the buttons and select the first one that has the sreachStr in its innerHTML.
buttonToClick = buttons.filter(function( button ) {
return button.innerHTML.indexOf(searchStr) !== -1;
})[0];
You don't need the eval, but you can check all the buttons one by one and just click the button immediately when you find it so you don't have to find it again.
It is not as elegant as what #Shilly suggested, but probably more easily understood if you are new to javascript.
var searchString = '720p';
var buttons = document.getElementsByClassName("streamButton"); // find all streamButtons
if(buttons)
{
// Search all streamButtons until you find the right one
for(var i = 0; i < buttons.length; i++)
{
var button = buttons[i];
var buttonInnerHtml = button.innerHTML;
if (buttonInnerHtml.indexOf(searchString) != -1) {
button.click();
break;
}
}
}
function allOtherClick() {
console.log("Wrong button clicked");
}
function correctButtonClick() {
console.log("Right button clicked");
}
<button class='streamButton' onclick='allOtherClick()'>10</button>
<button class='streamButton' onclick='allOtherClick()'>30</button>
<button class='streamButton' onclick='correctButtonClick()'>720p</button>
<button class='streamButton' onclick='allOtherClick()'>abcd</button>
I would stay clear of eval here, what if the text on the button is some malicious javaScript?
Can you use jQuery? if so, check out contains. You can use it like so:
$(".streamButton:contains('720p')")
I have a form that lists users, and for each user there is a drop down menu (2 choices: waiting, finished) and a comments textbox. The drop down menus are each labeled "status-userid" and the comments textbox is labeled "comments-userid" ... so for user 92, the fields in his row are labeled status-92 and comments-92.
I need to validate the form in the following way:
If the value of the status is "finished", I have to make sure that the user entered comments to correspond with that specific drop down menu.
So far, I have:
function validate_form () {
valid = true;
/*here's where i need to loop through all form elements */
if ( document.demerits.status-92.value == "finished" &&
document.demerits.comments-92.value == "")
{
alert ( "Comments are required!" );
valid = false;
}
return valid;
}
How do I loop through all of the status-userid elements in the form array?! Or is there another way to do this?
This should do it in raw Javascript (no framework).
var form = document.demerits;
for (var i = 1; i <= 100; i++)
{
if (form["status-" + i.toString()].value == "finished" &&
form["comments-" + i.toString()].value == "")
{
// enable visibility of element next to comments indicating validation problem
valid = false;
}
}
Using alerts would be bad though.
You'll need a collection of the dropdowns in your form. This can be acquired by using getElementsByTagName.
var dropdowns = document.demerits.getElementsByTagName("select");
for (var i = 0; i < dropdowns.length; i++)
{
// You can now reference the individual dropdown with dropdowns[i]
}