Generate multiple checkboxes from Javascript array? - javascript

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

Related

JavaScript - if class list contains value from Array

I'm trying to setup a filter on a database application, for lost property for a scout camp. The idea is the following:
The lost property items are logged into the database by reception as either 'Lost', 'Handed In', 'Owner Notified' or 'Returned' (meaning 4 lists generated from a table, with a status flag which is used to filter which list an item appears in).
At the top of each list, I have a form field (text) which I would like to use to filter the list, simply by the reception team member typing in some words that describe the item (eg, Jacket blue)
I've set a common class name to each row in the list table (a different one for each list, so listLost, listFound, listNotified, listReturned)
I've then used some of the database fields to add additional classes to the list (eg, item, colour, first name, surname - these are converted to UCASE to get around the case sensitive nature of JavaScript), so the final class might look like:
class="listLost JACKET BLUE FRED BLOGGS"
The reception team member can then type into the text field, something like 'Jacket Blue' and my JavaScript function is supposed to filter the list as follows:
the input from the text field is split into an array, using SPACE as the separator
it looks for all items in the page with a particular common class name (in this example, it would be listLost)
it then pages through the array comparing the class list for each (in this case, table row) with the array value and it if finds a match, the table row will be displayed, if not, it won't
Here's my JavaScript function:
function filterLostProperty(filterField,filterList)
{
var filterStr = document.getElementById(filterField).value;
var filterVals = filterStr.split(" ");
var filterItems = document.getElementsByClassName(filterList);
var displayCheck = 0
for (x = 0; x < filterItems.length; x++)
{
for (y = 0; y < filterVals.length ; y++)
{
if (filterItems[x].classList.contains(filterVals[y].toUpperCase()))
{
displayCheck++
}
}
if (displayCheck > 0)
{
filterItems[x].style.display = "table-row";
}
else
{
filterItems[x].style.display = "none";
}
}
}
The form field has:
onChange="filterLostProperty('filterLost','listLost')
where filterLost is the ID of the text field from which the search string comes.
PROBLEM: it doesn't really filter in the way it should... some strings just generate everything, some bring up the item you wanted plus 2 you didn't, some don't generate anything at all. And when there is more than one word it goes even more weird.
Does anyone have any suggestions about where I might have gone wrong here? Or is my method here just too overly complicated and I'm missing a simple trick with something?
21.11.2017
So - I edited my function further after having a bit of an idea that I would instead of generating an Array of the filter text (as the array approach was only using the last entered word as the filter text), I would just create a string with AND between each one (using a replace function to replace SPACE with AND Operator), in the hope that it would do a 'If class list contains X and Y and Z then blah blah'...
I tested this with fixed values at first on my test page:
function manualFilter(filterList)
{
var filterItems = document.getElementsByClassName(filterList);
for (x = 0; x < filterItems.length; x++)
{
{
if (filterItems[x].classList.contains("WALLET" && "BLUE"))
{
filterItems[x].style.display = "table-row";
}
else
{
filterItems[x].style.display = "none";
}
}
}
}
My test page is at https://bookings.springbank.org.uk/testFilter.asp and the test filter can be triggered by clicking the 'Manual Filter' button.
Problem is that when I do this, I get the row with WALLET BLUE in as expected (and not the row with WALLET BLACK which is good)... but I also get the row with JACKET BLUE (presumably because it's matched BLUE)... ideally, I don't want this to display.
If this can be made to work (effectively replacing the spaces from the text field entry with an AND operator to be interpreted by the IF statement)... the only other bit I'm not totally clear on (not being particularly proficient in JavaScript) is how I can do this dynamically from the function... presumably it's going to be a case of a certain number of consecutive quotes so that the && is interpreted as and AND operator and not simply as part of a string?

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

Selectize.js - Enforce At Least One Item From Select To Be Picked

I have used the allowEmptyOption : false but it has not helped.
I need to always have at least one item selected (the first one in the list is fine to default to).
I am not sure how to quickly and easily do this. It seems like it should be simple but I must be overlooking something in the documentation. The way I have my code, currently the select returns a blank or null value when I don't want it to.
Just a note. I am using the clearOptions() and addOption() methods to load items into the select. After all options are loaded, I want to then select the first item in the dropdown. That is all I really want to do. Any easy way of doing this using the options or programmatically?
Using selectize events works for me:
// add 'staff' and maintain if attempt by user to remove
rolesStz.addItem('staff', true);
rolesStz.on("item_remove", function(item) {
if(item == "staff")
this.addItem(item);
});
Running on:
// The selectized obj
var $roles = $('.input-roles');
$roles.selectize({
options: roles
});
var rolesStz = $roles[0].selectize;
See also:
https://github.com/brianreavis/selectize.js/blob/master/docs/events.md

How can I remove blank lines in an array generated that show in a dropdown

I have a dropdown that is generated using javascript and html. I have some code which I will post below that loops through this list and should potentially remove any blank lines found but is not working. "$maxfield1rows" has a value of 7, what I am saying is that if the value is a blank (=='') then remove it. I used removeChild but this doesn't seem to work, I also tried splice, I think filter can work but am not sure. I tried the disabled=true but that just makes them disabled and unselectable. Can someone please help?
for(index=1; index<$maxfield1rows; index++) {
if(document.pickDivision.field1.options[index].value=='') {
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
}
}
Updated below, I'm using $maxfield1rows since that is the amount of maximum number of rows the the loop goes through, also by change I meant that there is an onchange event that gets triggered when the user selects a different option in the dropdown menu, so depending on the option selected the output for field1 changes, sometimes there are 5 values that show and sometimes just 1:
for(index=$maxfield1rows-1; index>=0; index--) {
alert(document.pickDivision.field1.options[index]);
if(document.pickDivision.field1.options[index].value==''){
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
document.pickDivision.field1.options[index].disabled=true;
}
else{
document.pickDivision.field1.options[index].disabled=false;
}
}
To expand upon my comment, I think the issue is that you are looping forwards through the options array. I am surprised that no error is being thrown when you try to do this. You should loop backwards through the collection to keep from skipping an item.
JS Fiddle demonstrating the error. In the example, items 1 and 2 are blank and item 3 is not.
These built in collections are changed each time your add/remove an item. Using the example in the fiddle, my array changes from [1,2,3] to [2,3] to error no item at index 2.
Looping backwards, my collection takes this change: [1,2,3] to [1,3] to [3].
Here is the code with comments explaining what each part of the for loop is used for and why. You can use a while loop if you prefer too.
//options.length - 1 because arrays are 0 based
//i >= 0 because you don't want to use a negative index on an array
//i-- to loop backwards
for(var i = document.pickDivision.field1.options.length - 1; i >= 0; i--) {
//Is this an empty item
if(document.pickDivision.field1.options[i].value == '') {
//Remove the empty item
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[i]);
}
}
UPDATE
With the newly updated code you posted, you are attempting to access an option element after it has been removed. From the looks of the line, you don't need it anymore as you are already removing the element. If you do still want to disable the element before removing it, move that line above the other line (see comment in code).
for(index=$maxfield1rows-1; index>=0; index--) {
alert(document.pickDivision.field1.options[index]);
if(document.pickDivision.field1.options[index].value==''){
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
//This line is causing the issue; move it above the previous line or remove it
document.pickDivision.field1.options[index].disabled=true;
}
else{
document.pickDivision.field1.options[index].disabled=false;
}
}
UPDATE 2
Per the question in the comments, when you change the number of options to 6, your code breaks. This is because you are using the hard coded PHP value $maxfield1rows. Since you already know the name of the form and the name of the field in the form, I would recommend you use the length of the options collection in your for loop rather than this variable. This will make sure that no matter how many option elements there are (1, 10, 1000), you will always loop through the entire collection.
for(var i = document.pickDivision.field1.options.length - 1; i >= 0; i--) {

How can I ensure that changes to a form DOM are complete before POSTing?

Currently I have a race condition existing in my JavaScript code. What I am trying to do with this code is convert all check boxes which are a part of the 'checkbox' class and are not checked into text boxes with a value of zero. Currently when you post a check box that is not checked it does not appear in the $_POST data. However I need to know all the values whether true or false for these particular set of check boxes.
The code I have is here:
Code:
function checkboxConvert() {
var chkBxs = $$('.checkbox');
for (var i = 0; i < chkBxs.length; i++) {
if (chkBxs[i].checked == false) {
chkBxs[i].type = 'textbox';
chkBxs[i].value = '0';
}
}
setTimeout("document.productForm.submit();",1000);
}
Now the problem that I have been getting is that when I try to submit this form the values of the recently changed text boxes does not appear in the $_POST data. Therefore, as you can see above I have postponed the page submit for 1 sec and then I have all the data available to me. However as time goes on and my data set gets larger, 1 sec may no longer be enough. This I think is a race condition and I need to figure some way of running the code only after all the check boxes have been converted and they have their new values. I would have thought that this would be unnecessary from the start, but for some reason it's trying to run both pieces simultaneously and I can't submit until I have the proper values in place.
Any help is much appreciated!
This is definitely not the way to do web. I strongly advise you abandon your checkboxConvert function, and solve this issue on the server side
JavaScript always runs single-threaded in the browser so I don't think it can be a race condition.
I'd generally agree with others that you shouldn't do this, but your problem may be that you're changing the element to a type of "textbox" instead of "text". If you declare an input of type "textbox" in HTML markup, it will usually render as a text field anyway because that's the default. However, changing an already valid "checkbox" type input to the invalid "textbox" may not work predictably.
Try changing it to this:
function checkboxConvert() {
var chkBxs = $$('.checkbox');
for (var i = 0; i < chkBxs.length; i++) {
if (chkBxs[i].checked == false) {
chkBxs[i].type = 'text';
chkBxs[i].value = '0';
}
}
// Because JS in the browser is single-threaded, this
// cannot execute before the preceding loop completes anyway.
document.productForm.submit();
}
There's got to be a better way to do this. Try something like:
Know about all your possible values on the server side. It looks like you're using PHP; keep a simple array with the names of your checkboxes.
When you take your $_POST data, remove the names of checkboxes you've received values for from your array.
The remaining are all false.

Categories

Resources