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?
Related
Idea for making elements visible or invisible:
So… how the loop works right now is it for each category, it loops through each question in each category.
The idea is: Each question can be answered yes or no, and then for each question answered yes, there can be up to 5 dates added.
What I want to do:
-If yes, first date appears:
-If the first date is answered, then a second question appears, and so on.
These questions are stored in a sql server like so:
I want only the inner loop to have this ability to be visible or invisible..
My thought is to do a nested loop and check check on each element.
//Psuedo code
//For each first question which has 5 sub questions that are all set to hidden:
var questioncount = (count of the first questions)
for(int i = 0; i<questioncount; i++){
// set first variable to hold the first questions object.
var element(‘#questionElement’ + i);
// set firstElement to selected answer
var isAnsweredYes = firstElement.(‘Yes’);
for int j = 0; i<subQuestionCount; j++)
if (isAnsweredYes == True){
// jQuery selector to get an element
var query = $('#element' + j);
// check if element is Visible
var isVisible = query.is(':visible');
if (isVisible === true) {
// element is Visible
// do nothing
} else {
// element is Hidden
query.show();
}
else
{
//do nothing
}
}
}
Does my logic seem forward? or can anyone advise me in a better way?
I would use a button that says "Add another date", which is displayed under the last date field as soon as at least one is visible. That way you won't have to decide on a certain number (e.g. 5) as the maximum, plus I think it's a rather intuitive way of extending a form.
On each press of the button, create new input controls; be it in javascript or server side, it makes no real difference.
So recently I built a search and replace program with Java, now I am working on translating/rebuilding that program with JavaScript. However, I am having trouble finding JS method alternatives for next() and hasNext(). I am new to JS so I don't know what JS methods would work similarly to the Java methods I am used to.
This is my program, I commented through it to show exactly what I am doing with the previously mentioned methods. Basic set up, 2 text areas, one for the search box (search criteria, box 2), and one for the main document (the field of search, box 1). It basically boils down to a cross-reference. It will highlight all the similarities between the documents.
function search() {
//define an array to store the search criteria.
var array = [];
// define a counter.
var n = 0;
// define a constant for the first box, the search field.
const box1 = document.getElementById("box1");
// define a constant for the second box, the search criteria.
const box2 = document.getElementById("box2");
// loop through the search criteria, storing each word as a seperate element in the array.
// this uses non js terms, this is where I need the help.
while (box2.hasNext()) {
array[n] = box2.next();
n = n + 1;
}
// resets the counter.
n = 0;
// loops through each search item, finding and replacing each item with itself, surrounded by mark tags.
while (n <= array.length) {
box1.replace(array[n], "<mark>" + array[n] + "</mark>");
}
}
</script>
There is bound to be other issues, bugs and syntax, feel free to point them out but lets try and keep the focus on the methodology (i.e. method alternatives for next() and hasNext()).
Thanks.
-EDIT- I'd prefer to use native alternative (no jquery) becuase I know even less about jquery than I do js.
I have a spreadsheet that takes input of stock symbols. I would like them to always be in ALL CAPS regardless of how they are typed in. This appears to require some scripting as there is no way to do this with a function unless a second copy of the column exists, which is not acceptable.
I have a solution which works, with one critical problem. The code is as follows:
function OnEdit(e) {
var ss = e.source.getActiveSheet(),
sheets = ['Trades', ''],
ind = sheets.indexOf(ss.getName());
if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1 ) {
e.range.setValue(e.value.toUpperCase());
}
}
It works great, and allows me to add as many tabs and columns to format as I wish. Unfortunately it also capitalizes the FORMULAS inside the cells, which is breaking formulas that use the importhtml() function, because it capitalizes the URL being requested.
So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?
EDIT: Thanks to #ocordova's comment, I thought I had something that would do the job well enough. Unfortunately it's behaving strangely... it works partly o some columns, and not at all on others. Here is my current code (slightly altered from earlier for clarity):
function onEdit(e){
var activeSheet = e.source.getActiveSheet(),
sheets = ['NEW Trades', ''],
sheetIndex = sheets.indexOf(activeSheet.getName());
if (sheetIndex === 0 && e.range.rowStart > 1 && e.range.columnStart >0 && e.range.getFormula() == '') {
e.range.setValue(e.value.toUpperCase());
}
}
Anyone have any ideas why some cells in some columns will capitalize as expected, and other cells in those same columns won't, and yet other columns won't capitalize at all, anywhere?
EDIT 2: My trouble appears to be related to, or a conflict with, Data Validation. The columns I'm trying to capitalize are fed by lists of values on another sheet. If the value was present previously in lower case, and then I applied the data validation to the column, the script will not capitalize the value. However if I select the appropriate, capitalized selection from the data validation list, and then re-type the same value in lower case, the script DOES kick in and capitalize. Very strange and confusing. I could be wrong about the conflict, but that's what it seems like to me.
EDIT 3: It's not related to data validation, because it's behaving the same way on a simple column that has no validation at all. If the value I had previously entered was already in lowercase, then typing it again in lowercase will not activate the script. BUT if I type the value in CAPS, then re-type it in lowercase, the script capitalizes it. Maybe some strange condition relating to when the script is triggered...?
If you don't want to capitalize if the cell contains a formula, you can use the method getFormula() and check if the cell contains a formula.
Returns the formula (A1 notation) for the top-left cell of the range, or an empty string if the cell is empty or doesn't contain a formula.
The code should look like this:
if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1 && e.range.getFormula() == '') {
e.range.setValue(e.value.toUpperCase());
}
EDIT:
If I've understood you correctly, you're typing exactly the same value, example: if the value in the cell is México, and you delete all or some characters and inmediately type México again, in that scenario the old value and the new value are the same and the OnEdit() won't be fired. Another example is if you change the format of the value, that's another type of event.
If you want know how the event is considered, you can use an installable on change trigger:
function triggerOnChange(e) {
MailApp.sendEmail('john.doe#gmail.com', 'Testing triggerOnChange', JSON.stringify(e));
}
Then in the Script Editor menu: Resources -> Current Project Triggers -> Add a new trigger -> ['triggerOnChange', 'From spreadsheet', 'On change']
On how to change the case of the formula's result, I think #Rubén has the right idea, but it will only work if the formula contains UPPER() in the first characters, and also since you're using the formula IMPORTHTML() using UPPER() will break it and maybe some other functions like array formulas, unless you use INDEX():
=INDEX(UPPER(IMPORTHTML(url, query, index)))
Another option could be Regular expressions, but I think it's a little risky considering all the combinations.
So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?
Consider to make a slight change in the OP approach: rather than capitalize all the cells content for any case, capitalize according the following conditions:
If the cell value, including the values of cells that holds constants or formulas, is not a string then do nothing .
If the cell value is a string
and the cell content is a constant, then change the case directly from the script.
and the cell content is a formula, then nest the original formula inside the built-in function UPPER.
Example:
function onEdit(e) {
var range = e.range;
var value = range.getValue();
var sheet = range.getSheet();
var sheetName = sheet.getName();
if (sheetName === 'Sheet1' &&
range.getRow() > 1 &&
range.getColumn() > 1 &&
typeof value === 'string') {
if(!range.getFormula()) {
range.setValue(value.toUpperCase());
} else {
if(range.getFormula().substring(0,6).toUpperCase() == '=UPPER') {
return;
} else {
range.setFormula('=UPPER(' + range.getFormula().substring(1) + ')');
}
}
}
}
Notes:
For simplicity the ind array was not included.
typeof e.value always returns 'string', so instead range.getValue(); is used.
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
I need to take a textbox that is full of formatted info about accounts and then sort it somehow. I would like to know if it would be ideal (I'm trying to make this as efficient as possible) to parse the info into a two dimensional array, or if I should make account objects that will hold info in fields.
The program is simply meant to format the data so that it can be printed out without having to copy/paste.
So far I have...
function generateOutputfvoc()
{
var accountLines = document.getElementById('accountLines').value;
var accountLinesTemp = accountLines.split(/[\s]/);
for(var i = 0; i < accountLinesTemp.length; i++)
{
if(accountLinesTemp[i].match(/
Edit (1-18-13): Here is an example input. It is basically text copied from a web CRM tool. Note, this example input is something I typed up randomly.
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
I would like my program to take the text and simply output the text like this:
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
Also, I would like to know if I should use jQuery variables. I asked this because I have been looking online a lot and I found examples that use code that looks like this:
$check=fcompcheck();
if($check)
{
$output=document.frm1.type.value+" / ";
$output=$output+"Something - "+document.frm1.disco.value+" / ";
Note the: $output variable. The dollar sign indicates a jQuery variable, right?
Thank you for any help you might be able to offer me.
Update (1-19-13): I've taken a shot at it, but I'm making slow progress. I'm used to programming Java and my JavaScript looks too similar, I can tell I'm makings errors.
I'm taking it one step at a time. Here is the logic I'm using now.
Person pastes text into text box and pushes the generate button
Program takes the contents of the text box and parses it into a large array, removing only whitespace
Program then searches for patterns in the text and begins passing values into variables
I am trying to get the program to simply identify the pattern "Summary section collapse Name" because these four words should always be in this sequence. Once it identifies this it will pass the next two array values into first and last name variables. Here's some of the code:
var contactNameFirst, contactNameLast;
// Parse the input box into an array
var inputArr = document.getElementById('inputBox').value.split(/[\s]/);
for(var i = 0; i < inputArr.length; i++)
{
if(inputArr[i] == "Summary" && inputArr[i - 1] == "section" && inputArr[i - 2] == "Collapse" && inputArr[i + 1] == "Name")
{
if(inputArr[i + 2] != "Details")
{
contactNameFirst = inputArr[i + 2];
}
else
{
contactNameFirst = "";
}
if(inputArr[i + 3] != "Details")
{
contactNameLast = inputArr[i + 3];
}
else
{
contactNameLast = "";
}
}
}
document.getElementById('contactNameOutput').innerHTML = contactNameFirst + " " + contactNameLast;
Also, should I create a new post for this now, or keep editing this one?
Your accountLinesTemp is an Array of String, you could use the Array.sort function to sort your array as expected, and then use Array.join to get the full String if necessary.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort on MDN for more information.