Javascript | Change src to data-attribute active - javascript

I am trying to change the selection of a image based on a data attribute of 'data-active'.
When the data-active is equal to true, then it will change the image to something that indicates that the platform has been selected and all of the others deselect showing only one.
The problem I currently have is that the image is being passed the current platform that is clicked so it is changing the deselected images to the current image clicked on disabled so the images become out of order.
You can see this here... https://miotks.co.uk/register (I have a self assigned certificate)
This is my current code that I have for it...
function checkState(obj, platform) {
var checkActive = document.querySelectorAll("[data-active='true']");
var alreadyActive = checkActive.length;
if (alreadyActive >= 2) {
for (var i = 0; i < checkActive.length; i++) {
// Reset the images to the default when all changed to false.
checkActive[i].setAttribute('data-active', 'false');
checkActive[i].setAttribute('src', '/images/' + platform + '-noselect.png' );
obj.setAttribute('data-active', 'true');
obj.setAttribute('src', '/images/' + platform + '-select.png');
}
} else {
}}
It judges the length of how many elements are selected and have 'true' once this exceeds or is equal to 2, then they all get reset and should change to the current one.
This is how I am calling the function on the click event...
checkState(this, 'steam');

It looks like you can just change the -select to -noselect in each image's url:
function checkState(obj, platform) {
var checkActive = document.querySelectorAll("[data-active='true']");
var alreadyActive = checkActive.length;
if (alreadyActive) {
for (var i = 0; i < checkActive.length; i++) {
// Reset the images to the default when all changed to false.
checkActive[i].setAttribute('data-active', 'false');
checkActive[i].src = checkActive[i].src.replace('-select', '-noselect');
}
}
obj.setAttribute('data-active', 'true');
obj.src = obj.src.replace('-noselect', '-select');
}

Related

How can I put off everything in my code until a button is clicked?

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.

JQuery to get the last changed value from #Html.DropDownListFor asp.net mvc multiselect dropdownlistbox

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;
};

Survey form automatic slider randomization

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);

Event listener fails to attach or remove in some contexts

I've created a script that attaches an event listener to a collection of pictures by default. When the elements are clicked, the listener swaps out for another event that changes the image source and pushes the id of the element to an array, and that reverses if you click on the swapped image (the source changes back and the last element in the array is removed). There is a button to "clear" all of the images by setting the default source and resetting the event listener, but it doesn't fire reliably and sometimes fires with a delay, causing only the last element in a series to be collected.
TL;DR: An event fires very unreliably for no discernible reason, and I'd love to know why this is happening and how I should fix it. The JSFiddle and published version are available below.
I've uploaded the current version here, and you can trip the error by selecting multiple tables, pressing "Cancel", and selecting those buttons again. Normally the error starts on the second or third pass.
I've also got a fiddle.
The layout will be a bit wacky on desktops and laptops since it was designed for phone screens, but you'll be able to see the issue and inspect the code so that shouldn't be a problem.
Code blocks:
Unset all the selected tables:
function tableClear() {
//alert(document.getElementsByClassName('eatPlace')[tableResEnum].src);
//numResTables = document.getElementsByClassName('eatPlace').src.length;
tableArrayLength = tableArray.length - 1;
for (tableResEnum = 0; tableResEnum <= tableArrayLength; tableResEnum += 1) {
tableSrces = tableArray[tableResEnum].src;
//alert(tableSrcTapped);
if (tableSrces === tableSrcTapped) {
tableArray[tableResEnum].removeEventListener('click', tableUntap);
tableArray[tableResEnum].addEventListener('click', tableTap);
tableArray[tableResEnum].src = window.location + 'resources/tableBase.svg';
} /*else if () {
}*/
}
resTableArray.splice(0, resTableArray.length);
}
Set/Unset a particular table:
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'resources/tableBase.svg');
resTableArray.shift(this);
};
tableTap = function () {
$(this).unbind('click', tableTap);
$(this).bind('click', tableUntap);
this.setAttribute('src', 'resources/tableTapped.svg');
resTableArray.push($(this).attr('id'));
};
Convert the elements within the 'eatPlace' class to an array:
$('.eatPlace').bind('click', tableTap);
tableList = document.getElementsByClassName('eatPlace');
tableArray = Array.prototype.slice.call(tableList);
Table instantiation:
for (tableEnum = 1; tableEnum <= tableNum; tableEnum += 1) {
tableImg = document.createElement('IMG');
tableImg.setAttribute('src', 'resources/tableBase.svg');
tableImg.setAttribute('id', 'table' + tableEnum);
tableImg.setAttribute('class', 'eatPlace');
tableImg.setAttribute('width', '15%');
tableImg.setAttribute('height', '15%');
$('#tableBox').append(tableImg, tableEnum);
if (tableEnum % 4 === 0) {
$('#tableBox').append("\n");
}
if (tableEnum === tableNum) {
$('#tableBox').append("<div id='subbles' class='ajaxButton'>Next</div>");
$('#tableBox').append("<div id='cazzles' class='ajaxButton'>Cancel</div>");
}
}
First mistake is in tapping and untapping tables.
When you push a Table to your array, your pushing its ID.
resTableArray.push($(this).attr('id'));
It will add id's of elements, depending on the order of user clicking the tables.
While untapping its always removing the first table.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
resTableArray.shift(this);
So, when user clicks tables 1, 2, 3. And unclicks 3, the shift will remove table 1.
Lets fix this by removing untapped table
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'http://imgur.com/a7J8OJ5.png');
var elementID = $(this).attr('id');
var elementIndex = resTableArray.indexOf(elementID);
resTableArray.splice(elementIndex, 1);
};
So you were missing some tables after untapping.
Well lets fix tableClear,
You have a array with tapped tables, but you are searching in main array.
function tableClear() {
tableLen = resTableArray.length;
for (var i = 0; i < tableLen; i++) {
var idString = "#" + resTableArray[i];
var $element = $(idString);
$element.unbind('click', tableUntap);
$element.bind('click', tableTap);
$element.attr("src", 'http://imgur.com/a7J8OJ5.png');
}
resTableArray = [];
}
Im searching only tapped tables, and then just untap them and remove handlers.
fiddle: http://jsfiddle.net/r9ewnxzs/
Your mistake was to wrongly remove at untapping elements.

Having trouble hiding/disabling elements when using timeouts

I'm trying to disable a button, hide a select list & show some text once a button is clicked... because of how long the javascript can take I am using timeouts to prevent the browser locking & the browser ending it prematurely or presenting a warning... however the code I have doesn't seem to be hiding/disabling/showing the elements once the button is clicked.
Edit: I have confirmed that the elements ARE getting hidden & then reshown, however they are being reshown too early.... the javascript hasn't finished doing what it's doing & they are reshown almost instantly after they are hidden.
Edit 2: Fixed it by moving the code that reshows the select list etc from the "addCatsSICMain" function to the "addCatsSIC" function as so..
if (spot < cats.options.length) {
other code here...
} else {
reshow select list etc code here
}
Here is the code:
This first function is the one that is called once the button is clicked.
function addCatsSICMain() {
// Set elements
var addBtn = document.getElementById('add');
var cat_sel = document.getElementById('cat_sic_sel_wrapper');
var addWait = document.getElementById('addWait');
// Disable add button
addBtn.disabled = true;
// Hide selected list
cat_sel.style.display = 'none';
// Show waiting text
addWait.style.display = 'block';
// Use a timeout function so button can be hid/show when we want successfully & not on function completion
setTimeout(function(){
// Add selected cats
addCatsSIC(0);
// Reshow selected list, reenable add button & hide wwaiting text
addWait.style.display = 'none';
cat_sel.style.display = 'block';
addBtn.disabled = false;
}, 10);
}
function addCatsSIC(spot) {
// Set the search results box
var cats = document.getElementById('cat_sic_list');
// Set the selected categories list that we are adding to..
var sel_cats = document.getElementById('cat_sic_sel');
// Set selcted counter var
var sel_count = 0;
// Set category add failed var
var failed = 0;
// Set batch size for looping
var batchSize = 50;
// Still more to do?
if (spot < cats.options.length) {
// Loop through categories from the search results select box
for (var i = spot; i < spot + batchSize && i < cats.options.length; i++) {
// Check if the cat is selected
if (cats.options[i].selected == true) {
// Set this category's values to some variables
var cat_id = cats.options[i].getAttribute('value');
var cat_name = cats.options[i].text;
if (checkCatSICAdd(cat_id) === false) {
// Now we create the new element
var new_option = document.createElement('option');
// Add attribute
new_option.setAttribute('value',cat_id);
// Create text node
var new_text_node = document.createTextNode(cat_name);
// Append new text node to new option element we created
new_option.appendChild(new_text_node);
// Append new option tag to select list
sel_cats.appendChild(new_option);
} else {
failed++;
}
}
}
var nextBitOfWork = function() { addCatsSIC(spot + batchSize) };
// Hand control back to the browser so it can update the page & not timeout & then restart the function
setTimeout(nextBitOfWork, 50);
}
if (failed > 0) {
// Find out if more than 2 cats were selected
for (var i = 0; i < cats.options.length; i++) {
if (cats.options[i].selected == true) {
sel_count++;
}
if (sel_count == 2) {
break;
}
}
// Give them an alert they have added that category already
/*addedCatSICAlert(sel_count);*/
}
}
Any reason why you are not using jQuery for this. You can disable button, hide select box and show elements by doing the following
$('button').click(function() {
$(this).attr('disabled', 'disabled');
$('select').hide();
$('p').show();
})
check working example at http://jsfiddle.net/N697c/1/
Fixed it by moving the code that reshows the select list etc from the "addCatsSICMain" function to the "addCatsSIC" function as so..
if (spot < cats.options.length) {
other code here...
} else {
reshow select list etc code here...
}

Categories