I've created a script (my first) that accepts input text and then runs about 30 regular expressions on the text, outputting discovered values into an HTML table. The purpose is for me to be able to paste in text containing specification information for products and have them uniformly outputted so I can paste them into a spreadsheet.
I've had it working really well and I've been tuning the regexes as I've pasted data with different variations/layouts in. However, I've hit an impasse and need some assistance:
One of the regular expressions searches for the product part number (sku) and returns the value in a column. Some of the source data includes more than one match because there are regional variations to the products. In all cases the first match is the only one that I want. I've tested the RegEx on RegEx101 and it returns the first match only with the 'global' flag switched off. However, the same RegEx running in my script causes it to return console messages infinitely before crashing. It's immediately unresponsive so I can't see any error messages.
Here's a sample of the regex section in my script. sku being the one that's causing problems:
let wallMountable = /(?<wallmountable>[Ww]all [Mm]ount)/mg;
let sku = /^.*\((?<sku>\d\d\w\w[\d\w]+?).+?\).*$/m;
function parseData() {
// Execute the Regular Expressions on the text in 'specSheet'
let specSheet = document.getElementById("specSheet").value;
let wallMountableToken = wallMountable.exec(specSheet);
let skuToken = sku.exec(specSheet);
do {
// If Token isn't null, then test to see if the regex group value is undefined. If either are true, do nothing, otherwise write the value to the document.
if (wallMountableToken !== null) {
if (wallMountableToken.groups.wallmountable !== undefined)
{document.write(`${wallMountableToken.groups.wallmountable}`);}
else {}
}
else {}
if (skuToken !== null) {
if (skuToken.groups.sku !== undefined)
{document.write(`${skuToken.groups.sku}`);}
else {}
}
else {}
}
// Loop through the script until a condition is met.
while (
(wallMountableToken = wallMountable.exec(specSheet)) !== null,
(skuToken = sku.exec(specSheet)) !== null
);
}
The while loop may not be necessary and in truth I'm not entirely sure what purpose it serves here, but it seemed to consistently appear in the reference material I was studying. I have included it here because it's part of the script, but please note that the script works if I change the second regex to /mg instead of /m, however, it returns multiple values and I only want it to return the first capture.
I know there's a lot wrong with the script, but this particular question is about why the regex is causing an infinite loop, so any help toward that goal is much appreciated.
Long after a page has loaded (e.g. a minute or more), we can receive push messages which would cause us to append new content. After doing this when we query using Jquery hash selector it never returns the newly added content. In all cases, the length is always zero. We can see the content, but the selector returns nothing.
var section = '<section id="NewSection">Hello</section>';
$('.container').append(section);
if ($('#NewSection').length == 0)
{
alert('This should not be zero at this point... Why is it?');
}
Is there something we need to do in order to enable JQuery to find the appended content after it is appended?
Thou shall not cast when not necesairly.
You're casting to boolean using !, See this cold run:
len = $('#NewSection').length
CASE len = 0
then !len = true
if(1){
// code excecutes
}
CASE len = 1
then !len = false
if(0){
// no code executes
}
In order work, you should rework your condition.
// #updated!
var section = '<section id="NewSection">Hello</section>';
$('.container').append(section);
if ($('#NewSection').length > 0) // meaning one or MORE than one element got selected
{
alert('I should have found this!');
}
Here is a jsfiddle
I have a uiApp that is creating table views from spreadsheet data, but I'm having difficulty with empty cells in a date column.
Basically, some of the spreadsheet cells are optional, and I haven't figured out how to put no (or a null) value into the table. Right now it works if I set the column value to:
projectDataRaw[i][projectDataKeys[j]]= new Date(); // inserting dummy data
But I want to leave those cells blank in the table view too, however, when I use:
projectDataRaw[i][projectDataKeys[j]]= null; //
Or some variation of that, it errors because the column type is set to DATE.
I could convert to strings, but I kind of wanted to be able to compare date values to each other when they are available.
-- Example of issue with table view and null data --
// load data from sheet
var _PMsheet = "sheet key";
var sSheet = SpreadsheetApp.openById(_PMsheet);
var projectData = sSheet.getRangeByName("ProjectDateCol").getValues();
var projectDataTable = Charts.newDataTable();
projectDataTable.addColumn(Charts.ColumnType.DATE, "Date Column");
for (var i=0; i < projectData.length; i++) {
if (projectData[i] == undefined || projectData[i] == "undefined") {
projectDataTable.addRow([null]);// Object type does not match column type.
// null fails, "undefined" fails, "" fails, [] fails
}
else {
projectDataTable.addRow([projectData[i]]); // this cell has a valid date obj
}
}
I created a simple script which writes null to the A1 cell and current date to the A2 cell. The complete column A is validated to be a date time. After the script execution the cell A1 is empty even if it contained a value before and there is no any warning or error message.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var rangeValues = [[null], [new Date()]];
sheet.getRange("A1:A2").setValues(rangeValues);
}
If this example does not help you, please publish as smallest as possible working script which does not work as you expected.
Update, basing on the author clarification: I wrote a simple script trying to find the problem cause and to find a workaround. The code is bellow. If to uncomment the data.addRow(['', 2.0]); line, then an exception thrown by the addRow method. It is an expected behavior. If to uncomment the data.addRow([null, 3.0]); line, then the chart.setDataTable(data) line throws an exception. This behavior is not correct, from my point of view, and I think it is necessary to report an issue to the issue tracker.
Also there is a workaround of this problem by using the DataTableBuilder.setValue method. The code demonstrates it.
By the way, the DataTableBuilder.setValue description in the documentation is not correct. It does not contain the column parameter. It is a topic to the issue tracker.
function doGet(e) {
var app = UiApp.createApplication();
var chart = Charts.newTableChart();
var data = Charts.newDataTable();
data.addColumn(Charts.ColumnType.DATE, 'Date');
data.addColumn(Charts.ColumnType.NUMBER, 'Value');
data.addRow([new Date(), 1.0]);
// data.addRow(['', 2.0]); // throws the "Object type does not match column type" exception in this line.
// data.addRow([null, 3.0]); // throws the "We're sorry, a server error occurred. Please wait a bit and try again" exception in the "chart.setDataTable(data)" line.
data.setValue(1, 1, 3.0);
chart.setDataTable(data);
app.add(chart.build());
return app;
}
I have a series of arrays that contain words I want to use as text in various HTML divs (there are about 35 of these, I included only a few for brevity).
var bodyplan = ['Anguilliform', 'Compressiform', 'Depressiform', 'Filiform', 'Fusiform', 'Globiform', 'Sagittiform', 'Taeniform'];
var mouthposition = ["Inferior", "Jawless", "Subterminal", "Superior", "Terminal"];
var barbels = ['1', '2', '4 or more'];
var caudalshape = ['Continuous', 'Emarginate', 'Forked', 'Lunate', 'Rounded', 'Truncate'];
I have a switch function that is supposed to change the text based on user selections:
switch(n){
case 1:
changelabels(bodyplan, 8);
break;
case 2:
changelabels(mouthposition, 5);
break;
case 3:
changelabels(barbels, 3);
break;
case 4:
changelabels(caudalshape, 6);
break;
case 5:
changelabels(dorsalspines, 8);
break;
default:
alert("handquestsel error")}};
Finally, I have the function which I would like to make the changes (except it doesn't):
function changelabels(opt1,opt2){
var i = opt2;
var im = opt2 - 1;
var c = 1;
var index = 0;
while (i>=c){
var oldlbl = document.getElementById("rb" + c + "lbl");
var newlbla = opt1.slice(im,i);
var newlblb = opt1.toString();
oldlbl.innerHTML = newlblb;
c = c + 1
index = index + 1
}};
I know the code for my function is just plain wrong at this point, but I have altered it so many times that I'm not sure what's going on anymore. At one point I did have the function able to change the text, but it did so incorrectly (it parsed the name of the array, not extracted a value from the array as I wished). Please help. I know I am overlooking some fundamental concepts here, but am not sure which ones. I've lost count of the hours I've spent trying to figure this out. It's seems like it should be so simple, yet in all my chaotic attempts to make it work, I have yet to stumble on an answer.
EDIT: I want my switch statement to call the function and pass to the function, the appropriate array from which to pull the labels from. The purpose of the app is to help a user learn to identify fish. When the user makes selections on the page, a series of pictures will be shown for various character states with an accompanying label describing the state. For example, when the user selects Mouth Position a series of divs will show the different mouth positions that fish have and have a label below the picture to tell the user what that certain character state is called. I can get the pictures to change just fine, but I am having a hell of a time with the labels.
Why not just something along the lines of:
document.getElementById("bodyplan_label").innerHTML = bodyplan[bodyplan_index];
You seem trying to put everything in really abstract data structures, I see no reason to. Just keep it simple.
Also bodyplan has only 8 elements, so bodyplan[8] will give you an out of bounds exception because arrays start at 0 as is common in all modern programming languages.
If I'm reading your requirement and code correctly, in your switch statement you are passing both a reference to the appropriate array and that array's expected length - you don't need the second parameter because all JavaScript arrays have a .length property.
You don't want to use .slice() to get the individual values out of the array, because that returns a new array copied out of the original - just use arrayVariable[index] to get the individual item at index.
So, putting that together try something like this (with your existing array definitions):
switch(n){
case 1:
changelabels(bodyplan);
break;
case 2:
changelabels(mouthposition);
// etc.
}
function changelabels(data) {
var i,
lbl;
for (i = 0; i < data.length; i++) {
lbl = document.getElementById("rb" + (i+1) + "lbl");
lbl.innerHTML = data[i];
}
}
Notice how much simpler that is than your code? I'm assuming here the elements you are updating have an id in the format "rb1lbl", "rb2lbl", etc, with numbering starting at 1: I'm getting those ids using (i+1) because JavaScript array indexes start at zero. Note also that you don't even need the lbl variable: you could just say document.getElementById("rb" + (i+1) + "lbl").innerHTML = data[i] - however I've left it in so that we have something to expand on below...
Within your function you seem to be changing the labels on a set of elements (radio button labels?), one per value in the array, but you stop when you run out of array items which means any leftover elements will still hold the values from the previous selection (e.g., if the previous selection was "bodyplan" with 8 options and you change to "mouthposition" with only 5 - you probably should hide the 3 leftover elements that would otherwise continue to display the last few "bodyplan" items. One way to do that is instead of setting your loop up based on the array length you could loop over the elements, and if the current element has an index beyond the end of the array hide it, something like this:
function changelabels(data) {
var i,
lbl,
elementCount = 20; // or whatever your element count is
for (i = 0; i < elementCount; i++) {
lbl = document.getElementById("rb" + (i+1) + "lbl");
if (i < data.length) {
lbl.innerHTML = data[i];
lbl.style.display = "";
} else {
lbl.innerHTML = "";
lbl.style.display = "none";
}
}
}
If these elements are labels for radio buttons (just a guess based on the ids) then you'd also want to hide or show the corresponding radio buttons, but I hope you can figure out how to add a couple of lines to the above to do that.
(As mentioned above, be careful about having element ids count up from 1 when the array indexes start at 0.)
If the above doesn't work please post (at least some of) the relevant HTML - obviously I've just had to guess at what it might be like.
SOLUTION: Changed the scope of the array variables to local by moving them into the function where they are used, instead of having them as global variables at the top of the page. I don't understand as I was following every rule of variable declaration. But for some unknown reason, global variables in javascript are abhorrent.
Solution Edit: Found an error in declaring my global variables. This may have been the source of my problem of why I could not access them. But it is a non-issue at this point since I corrected my code.
I don't understand what your trying to achieve exactly with your code. But to pass a variable (in this case an array) by reference you just have to add "&" before the variable.
function the_name(&$var_by_ref, $var_by_value) {
// Here if you modify $var_by_ref this will change the variable passed to the function.
}
More: http://php.net/manual/en/language.references.pass.php
Hope that helps.
var allRows = this.getTbodyEl().rows;
for (var i = allRows.length - 1; i >= 0; i--){
var thisRowID = allRows[i].id;
// Clean up any existing Drag instances
if (myDTDrags[thisRowID]) {
myDTDrags[thisRowID].unreg();
delete myDTDrags[thisRowID];
}
// Create a Drag instance for each row
myDTDrags[thisRowID] = new YAHOO.util.DDProxy(thisRowID);
};
I can't figure out why, but the above code is not yielding a DDProxy object for each row in my table. I have verified that the DDProxy code is all loaded and running properly by passing a string reference to a DOM element:
myDTDrags[thisRowID] = new YAHOO.util.DDProxy('yui-rec30');
This makes the corresponding row draggable as expected! I have also verified, using typeof, that the value of thisRowID is indeed of the type 'string' AND that the string contains the id of appropriate row elements.
What have I missed?
UPDATE: My code posted above is correct. I was wrong in that the contents of my thisRowID variable did NOT contain a reference to an appropriate row element!