Disabling an input box conditionally using jQuery - javascript

I'm building out a Sudoku game using just jQuery. I have most of the logic built out (it's still pretty rough at this point - planning to refactor after I get this last piece). I'm stuck on when I generate a board, I'd like to disabled those specific input fields. Here is the section of code I'm using to build out the board:
var context = this;
$td = $('<td>')
.append($('<input>')
.data('row', i)
.data('col', j)
.data('region', region)
.val(function(){
var prefillValue = easyGame[i][j];
if(prefillValue !== -1){
context.currentMatrix.rows[i].push(prefillValue);
context.currentMatrix.columns[j].push(prefillValue);
context.currentMatrix.regions[region].push(prefillValue);
return prefillValue;
}
})
.on('keyup', $.proxy(this.validateInput, this))
.on('click', $.proxy(this.captureInput, this)));
High level view:
What's happening is I have an array of arrays stored in the easyGame variable. This variable contains the prebuilt number locations for the "easy" board.
I then do a lookup on the easyGame variable for each row and column and if there's a value (aka as long as the lookup on easyGame isn't -1) I set that as the value of the current input box that I'm building out. If the lookup comes back as -1, the input value is left blank.
The code above works fine (it's pretty slow and clunky but the wireframe is there for now).
Where I'm getting stuck, is I want to disable only the input boxes where a value is present on the initial build (aka the code above).
I think I'm overthinking this but is there a way to apply the disabled property .prop('disabled', true) conditionally - aka when the lookup isn't -1?
Thanks in advance and if there's any more information that's needed, let me know!

Figured it out. Here's the answer for anyone else trying to do this:
.prop("disabled", easyGame[i][j] !== -1 ? true : false)

Related

Individual custom start position in Qualtrics through Javascript

I want to use either a slider question or a draggable bar chart in Qualtrics to present to respondents how they answered in former questions. More specifically, I compute a value out of then answers with weighting, and want the slider or bar to be positioned at this value.
Notably, as each respondent has a value (stored in an embedded data field), the position will thereby be individual for each respondent. Piping only works for text fields, as far as I understood the support page.
Based on this question/answer I came to the following code for the bar graph:
Qualtrics.SurveyEngine.addOnload(function()
{
var result = "${q://Field/result}";
var qwidth = $('QID1936~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$('QID1936').select('.bar').each(function(name, index) {
name.setStyle({ width: resrec +"px"});
});
});
Basically, I get the result for each respondent out of the embedded data, get the width of the full bar graph, compute the ratio that should be colored based on the result, and update the position of the bar graph (following the mentioned answer).
Funny enough, everything works when done in the console. Also, the embedded data is correctly loaded, qwidth as well.
Two problems arise: it seems resrec could be computed wrongly, as a console.log() spits out 0 instead of the correct value. I assumed this could be somehow as a variable is not recognized as number, but several tries with Number() or 0+var did not change how this works in Qualtrics. In the console, it works just fine.
Also, no update of the bar (or slider with similar code) happens, neither with the correct value nor with the 0 that is produced by Qualtrics.
I search for two things: either a solution to the Javascript problem as described, basically how I can update the bar or slider with embedded data. Or another solution how to directly get embedded data into one of those two question formats as a starting value for each respondent individually.
Thanks for your help or ideas!
Try this:
Qualtrics.SurveyEngine.addOnload(function()
{
var qid = this.questionId;
var result = parseFloat("${e://Field/result}");
var qwidth = $(qid+'~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$(qid).select('.bar').each(function(name, index) {
name.style.width = resrec + "px";
});
});
Notes:
It is best not to use a hardcoded QID
In a pipe use e: to refer to an embedded variable. q: is for questions.
Use parseFloat to convert the string to a number
No need to use setStyle if you are only setting one value
One solution proposed by Qualtrics support: when you use bars and/or sliders, piped values are actually possible.
The trick is to have the value of the bar/slider shown (a thing we do not use in the whole survey elsewhere). Then, you can access over the Advanced Question Options > Add Default Choices the blue arrow for piping text behind the value. Through this, the value is individually set to either embedded data or another answer.
Note, however, to tick "Show value" before accessing the default choices, else you will only be able to drag around the bar and set it for all simultaneously.
Here is a solution using the Qualtrics Question API method setChoiceValue that does not require you to compute the ratio and update the length of the bars manually.
Below is an example code for the result of ten respondents saved in embedded data from previous questions.
Qualtrics.SurveyEngine.addOnload(function()
{
var embedded = ["${e://Field/r1}", "${e://Field/r2}",
"${e://Field/r3}", "${e://Field/r4}", "${e://Field/r5}",
"${e://Field/r6}", "${e://Field/r7}", "${e://Field/r8}",
"${e://Field/r9}", "${e://Field/r10}"];
for (var i = 0; i < 11; i++) {
var index = i + 1;
var choiceInput = embedded[i];
this.setChoiceValue(index, choiceInput);
}
});
For one respondent:
Qualtrics.SurveyEngine.addOnload(function()
{
var value = "${e://Field/r1}";
this.setChoiceValue(1, value);
});

onkeydown, and auto complete

I was wondering if anyone could help me solve this issue or point me towards the right direction.
In my project we have a filed that needs to be autofilled, at this moment I use onblur which works wonders as it only does it so once you leave the focus. However, due to recent changes, it needs to only do so when there is only one unique item in the map which it matches the input.
I have a large array defined as following:
var myArray = [
[content, content],
[content, content],
...
]
Later in my code I associate it with a map, at least this is what most stackoverflow questions I looked at referred to it as follows:
var myMap = {};
for(0 to myArray.length) {
var a = myArray[i][0];
var b = myArray[i][1];
myMap[a] = b;
}
Now, finally I iterate over this array as follows:
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0)
the above is the line of code I am struggling to figure out how to change. At this moment, while using on blur, if I type in the letter 'A' for example, and leave the focus area it will automatically fill it in with a certain name. However, in the array there are many other objects that begin with, or contain A. How can I change it so that the onkeydown event will keep going until it finally filters it down to to only possible key-value pair? I tried looking at MDN's documentation for filtering, but I do not think that will work for my purposes, or at least I am too inexperienced with JS.
If the indexOf the first and last are nonnegative and equal, there is just one. You could do this with an && and boolean short circuit evaluation, but that will run very far right off the screen, so I am showing your code with one more nested if (up to you to add the end of the block). But we also need to see if there are matches on multiple keys.
var matchCount=0;
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0){
if (map[key].toLowerCase().indexOf(location.toLowerCase()) == map[key].toLowerCase().lastIndexOf(location.toLowerCase())) {
matchCount++;
then outside your for loop:
if (matchCount==1){ //do your stuff

Custom Text filter for DC.js dataTable

I'm building a dashboard to show some data. I have several charts and a table listing all of the data. I'm trying to add search functionality to filter the chart. I have a bunch of companies and some data about each. So if I search for "Appl" only companies that start with "Appl" will be listed in the data table and the charts will reflect this.
The only issue I have with the current implementation is when I change this filter or clear it. The data seems fine, but the charts render incorrectly. They don't return to their original positions when cleared, or they add extra data somehow. Any tips would be appreciated.
$("#table-search").on('input',function(){
text_filter(companyDimension,this.value);//companyDimension is the dimension for the data table
function text_filter(dim,q){
dashTable.filterAll();
var re = new RegExp(q,"i")
if (q!='')
{
dim.filter(function(d){
if (d.search(re)==0)
return d;
});
}
dc.redrawAll();
graphCustomizations(); }});
dc.js code
var ndx = crossfilter(resource_data);
//Dimensions
companyDimension = ndx.dimension(function(d){
return d["Company Name"]
});
dashTable.width(800).height(800)
.dimension(companyDimension)
.group(function(d){
return "List of all Selected Companies";
})
.size(1774)
.columns([
function(d){return d["Company Name"]; },
function(d){return d["Revenue Source"];},
function(d){return d["Commodity"];},
function(d){return "$"+parseFloat(d["Revenue"]).formatMoney(0,'.',',');}
])
.sortBy(function(d){return d["Company Name"]})
.order(d3.ascending);
That's about it, the charts are just filtering with different dimensions on the same crossfilter object.
I've tried doing several things to the text_filter function such as, dim.filterAll(), dim.filter(null), dc.renderAll(). When I inspect the data in the dimension, it is correct before and after each filter, the other charts just don't seem to be handling it correctly.
I've tried adding a basic filter to the dc dataTable directly, but I can't get it to work with a custom filter function. So I can do something like dashTable.filter(q) and it will work, but I have to give it the entire company name for it to display anything, but the charts render correctly when I apply it and remove it. I've tried using dashTable.filterHandler() but it always returns an error, but if you know how to get that to work, I would be curious, because I couldn't get it to function even with the example in dc.js's documentation.
Any help would be greatly appreciated.
EDIT:
Here's a fiddle of the mostly complete code, I jumbled some code together to get it working. http://jsfiddle.net/rbristow/HW52d/1/
To reproduce the bug, enter a letter in the search box then clear it and enter another letter, you can see the total not resetting correctly.
In this block:
if (q != '') {
dim.filter(function(d) {
if (d.search(re) == 0)
return d;
});
}
Your filter needs to be:
dim.filter(function(d) { return 0 == d.search(re); });
But then, you're not applying any filter to dim if q == '' so it should be
if (q != '') {
dim.filter(function(d) {
return 0 == d.search(re);
});
} else {
dim.filterAll();
}
Explanation:
In crossfilter.js the return value of your filter callback is tested like this:
if (!(filters[k = index[i]] & one) ^ (x = f(values[i], i))) {
if (x) filters[k] &= zero, added.push(k);
else filters[k] |= one, removed.push(k);
}
If the filter returns true and the item is already in the current view, it's not supposed to do anything. true ^ true -> false.
But in your case, true is being xor-ed with a string -- note, this is bitwise xor, not logical, as Javascript lacks a logical xor -- which will always evaluate to a true value. So the values you want in your filtered set are being put into added when they should be left alone.
It's an oddball use of a bitwise xor. I looked this up on SO and the top voted answer to Why is there no logical xor in JavaScript? contains "Bitwise XOR is extremely useful, but in all my years of programming I have never needed a logical XOR." Given that crossfilter.js emphasizes performance maybe they drop some error checks and want to use fast "mathy" operations.

Generate multiple checkboxes from Javascript array?

My jsfiddle will help explain things better than I ever can >< http://jsfiddle.net/L65QD/17/
I've got two select boxes, when you select something from the first select it enables the second. I have quite a few arrays that I'm using as sort of a fake database.
What I need to happen is that depending on what is selected in profile_select it needs to generate checkboxes for every PRIVILEGE_CODE it has, however the checkboxes must be generated with SEC_PRIVILEGES.Name next to them instead of the actual PRIVILEGE_CODE and they must be generated in the correct DIV. Since it's so hard to explain I made a JSFiddle which just about summarizes it http://jsfiddle.net/L65QD/17/
If my instructions aren't clear:
Depending on what profile is selected in the PROFILE_SELECTION
Needs to generate some checkboxes based on what PRIVILEGE_PROFILES.PRIVILEGE_CODES it has
However the checkboxes must have the name from SEC_PRIVILEGES next to them instead of the code, so PRIVILEGE_CODES = Unique_Code
Checkboxes are generated in either the DA div or the MR div based on what Group_Code they have in SEC_PRIVILEGES (this bit really confuses me, can you make it so a DIV ID can be equal to something from an array?) However to generate them in DA or MR it can't really be an IF because my fiddle is just an example and I'd actually have about 30 different codes so I couldn't do 30 IF statements.
This is the method I was experimenting with but it doesn't really make sense and is probably not even close to being on the right lines:
$(document).on('change', '#select_profile', function () {
var Select = $("#select_profile option:selected").text();
$("#apps").html;
for (var i = 0; i < SEC_Privileges.length; i++) {
if (SEC_Privileges[i].Unique_Code == //something?) {
$('#DA').html("<b>lol</b>");
}
}
});
So that's pretty simple:
Correct this fatal error: Array literals are written in square bracket notation ([], not ()). When you log the PRIVILEGE_PROFILE[0].PRIVILEGE_CODE you'll see only the first code is logged as the key's value.
Building the function: Consider what you need:
When a user changes company, all checkboxes must be reset
When a user changes profile, all checkboxes must be reset, then changed accordingly
When 'None' is selected in either dropdown, all checkboxes must be reset
Result: http://jsfiddle.net/kevinvanlierde/L65QD/19/
Some conventions:
Please choose one naming convention and stick with it. The more common ones are lowercase_underscore or CamelCase. You can opt for uppercase, but don't mix them (easier readability). I've had several errors just because I wrote the names incorrectly.
Declare your variables at the start of your function, assign them further on.
Also want to add that if I were to have control over the object's structure, I would probably opt for a more hierarchical tree/ JSON-like structure, eg instead of your current object, do:
var SEC_Privileges = {
'DA': {
'name': 'Dispatch App',
'accesses': {
'DAAccess': 'Access',
'DASuper': 'Supervisor'
}
},
'MR': {
'name': 'MyRoster',
'accesses': {
'MRAccess': 'Access',
'MRSuper': 'Supervisor'
}
}
}
Because the object keys are themselves values, you can use them to build your UI, eg to get the full name of your MRAccess you could do something like SEC_Privileges.MR.name + SEC_Privileges.MR.accesses.MRAccess to get MyRoster Access
There is different ways to approach this but the amount of Privileges would always be the same?. Depending on what your SEC_privileges is if its JSON array then you could loop through that array and access the code and the description. You would then want to validate the selected privileges again the whole set and say something like:
var array = ('one','two','three');
if($.inArray(SEC_privileges[i].Unique_code, array))
{
$('#DA').html("<input type='checkbox' id='"+i+"' value='"+SEC_privileges[i].Unique_code+"' checked/>"+SEC_privileges[i].Unique_desc);
}
else
{
$('#DA').html("<input type='checkbox' id='"+i+"' value='"+SEC_privileges[i].Unique_code+"'/>"+SEC_privileges[i].Unique_desc);
}
A ticked value is done by adding the word checked as part of the html input object. Like illustrated above

String creation and comparison in Drag n' drop game

I'm trying to make a simple drag and drop game where users need to re order someone's name by dragging characters into a dropping zone.
I'm ok with the drag and drop animations but I'm not being able (mostly due to technical lack of skills) to create strings with this letters in order to make a comparison between both of them.
Check my example code here jsFiddle
I'm creating the first string with the name before I randomize all the letters dragItemsContent = [];
I'm kinda being able to create a new string for letters I'm dragging dragedItemsContent += ui.draggable.text();
But when I wan't to delete any of those letters I can't delete them, and the worst thing is I have no idea how to look for that letter's index and delete it properly from my string.
I'm using data-letra which is a unique indicator for each letter, maybe it can help.
So, to sum up, I need to add/remove letters (or some comparable data) to my strings and compare them to know if the users finish the game correctly.
Thanks
Very fun game.
I have edited it to display You Won! or Sorry. Please try again. based on the results (Spelling out Fredfigglehorn.
Clicky.
The important part is:
var letters = $('.drop-area').find('.drag-item');
if (letters.length == dragItemsLength ) {
var final = '';
for (var i=0;i<dragItemsLength;i++)
final += letters[i].innerText.substring(0, 1);
if (final == 'fredfigglehorn')
alert("You won!");
else
alert("Sorry. Please try again.")
}
Instead of dragedItemsContent += ui.draggable.text(); you should use dragedItemsContent.push(ui.draggable.text()) this way you will get a good array in proper order. Later you can use toString to make your string and to remove simply remove the element from the array
You might also want to check out sortable from jQuery UI which can handle almost everything out of the box
I have made a fiddle for u which does comparison based drag items text hope it helps u.. http://jsbin.com/oluhuk/2/edit

Categories

Resources