How to convert content within a div into a series of variables? - javascript

I have a rough bit of code I borrowed from another site that has served me well in one regard, but now I'm having some trouble.
I have a file that can be saved with a series of variables... Variable X is 17, and Variable Y is 5. You hit the save button and you download a txt file with the content being "17 05". That part I definitely have down-pat and do not need help with.
However, once I have this file with the "17 05" inside of it, I upload it to the HTML and it spits out the content into a DIV. Boom, "17 05" right in my HTML, cool as hell. Except... How do I get this completely new HTML to sort out "17" and "05" as Variables X and Y like it was in the aforementioned HTML?
function readBlob(opt_startByte, opt_stopByte) {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('byte_content').textContent = evt.target.result;
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target.getAttribute('datastart');
var endByte = evt.target.getAttribute('dataend');
var strxs = evt.target.getAttribute('ds-str');
var strxe = evt.target.getAttribute('de-str');
$('#flodump-str #start').text(strxs);
$('#flodump-str #end').text(strxe);
var readStr = $('#flodump-str').text();
$('#devtestdump span').text(readStr);
readBlob(startByte, endByte);
}
}, false);
With this current code that I barely understand, it takes the byte number from the HTML and reads it from a certain amount (startByte) to another amount (endByte) and dumps it all in one location.
My problem, as I'm trying to do is... well, get it to dump in multiple places! If I can just get "17" and "05" into separate spans, that's childs play to finagle them as variables. However, they're both in one div, without any differentiating spans or id tags, its just one DIV with number salad as its content... unless there's some method to reach into a DIV using the same character count / byte number method and say "the first two characters are Variable X, the next two characters are Variable Y."
Either that, or there's a way to get this whole readBlob business to have multiple outputs for each specified byte area?
Can anyone help me with this? Any help is greatly appreciated.
EDIT: I should note that I left some of my half-hearted attempts to fix the problem myself within the code. I tried to export the specified byte fields as variables, only to find out that instead of outputting the content, it outputted the actual byte fields, like "35 and 37" for reading the position within the text file, as opposed to the actual content at the 35 and 37 position.
EDIT2: I should also note that "17" and "05" is just an example for brevity's sake. I have about forty of these two-digit variables in my actual text file.

If I can just get "17" and "05" into separate spans, that's childs
play to finagle them as variables. However, they're both in one div,
without any differentiating spans or id tags, its just one DIV with
number salad as its content... unless there's some method to reach
into a DIV using the same character count / byte number method and say
"the first two characters are Variable X, the next two characters are
Variable Y."
Try defining X , Y as property names of an object , using String.prototype.match() with RegExp /\d+/g to return one or more digit characters followed by digit characters , Object.keys() to retrieve property names of created object , Array.prototype.forEach() to set properties X , Y to matches found in div . If expected result is for X and Y to be number objects , can cast string returned by .match() to number utilizing Number(res[i]) , where res is array returned by .match() , i is index of item in array iterated within .forEach()
var obj = {X:void 0, Y:void 0};
var res = document.querySelector("div").textContent.match(/\d+/g);
Object.keys(obj).forEach(function(val, i) {
obj[val] = res[i]
})
console.log(obj)
<div>17 05</div>

Related

Incrementing ID again from last row google apps script

last week I asked something here Increment ID from last row google apps script
Everything was working well but then again, when I used WP1-1000 as a starting row, the result is still appearing as WP1-0NaN
var riskid = mysheet.getRange(rlast,2).getValue();
if (riskid.length > 3){
// Extract number ex. 3
var riskidnb = parseInt(riskid.substring(1,riskid.length));
// Increase risk number +1
riskidnb++
// Convert to string "0004"
var s = "000" + riskidnb.toString();
// Write risk nb i.e. "R004"
mysheet.getRange(r,2).setValue("WP1-"+ s.substring(s.length-4))
}
I tried changing/increasing/decreasing the riskid.length, var s, and s.length-4 from the code but still no avail. The result still appears as "WP1-0NaN"
From my question, the string is already inverted into an integer, but it still appears as NaN when I changed it to WP1.
Also, it seems the code from my last question only workds if there is only 1 letter like in the solution.
I literally tried everything for 2 hours and going mad now.
Explanation / Issue:
That is because in your previous question, the id has the structure
of R-002 but now you are using 3 letters before the -:
WP1-1000. You can now use 4 instead of 1 and it will work:
parseInt(riskid.substring(4,riskid.length));
However, a more generic approach would be to substring after -, therefore you can use indexOf to find that position:
parseInt(riskid.substring(riskid.indexOf('-')+1,riskid.length));
You can apply the same logic for the last line. Instead of hardcopying WP1- you can just get the text before and including -:
riskid.substring(0,riskid.indexOf('-')+1);
Solution:
var riskid = mysheet.getRange(rlast,2).getValue();
if (riskid.length > 3){
// Extract number ex. 3
var riskidnb = parseInt(riskid.substring(riskid.indexOf('-')+1,riskid.length));
// Increase risk number +1
riskidnb++
// Convert to string "0004"
var s = "000" + riskidnb.toString();
// Write risk nb i.e. "R004"
var start = riskid.substring(0,riskid.indexOf('-')+1);
mysheet.getRange(r,2).setValue(start + s.substring(s.length-4))
}

Transfer random String to .innerHTML

I want to change the content of a div randomly by .InnerHTML. The text are saved as variables. The random number is another variable. The Problem is, that if I put text and random number together it will print text1 for example.
Can someone help me with that?
function switchText(){
var text1 = "hello";
var text2 = "there";
var text3 = "ObiWan";
var randomNumber = Math.floor(Math.random() * 3) + 1;//creates random No. from 1 - 3
document.getElementById("randomText").innerHTML = "text" + randomNumber;
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
How about storing all random strings in an array, like so:
function switchText(){
var randomWords = ["hello", "there", "ObiWan"];
var randomIndex = Math.floor(Math.random() * 3);//creates random No. from 1 - 3
document.getElementById("randomText").innerHTML = randomWords[randomIndex];
//the problem
}
Actually you can access those variables by using index notation (it's described really nicely here) so in your specific case of function you just need to change the line where you try to access the variable to
document.getElementById("randomText").innerHTML = this['text' + randomNumber];
However though such notation is not something I would recommend. Usage of array as it was suggested is much more readable in fact.
Store those texts into an array and use the random number.
Get the random number as follow: Math.floor(Math.random() * 3)
function switchText(){
var texts = ["hello", "there", "ObiWan"];
var randomNumber = Math.floor(Math.random() * 3);//creates random No. from 1 - 3
console.log(randomNumber)
document.getElementById("randomText").innerHTML = texts[randomNumber];
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
You can store those texts into an object as well.
function switchText() {
var texts = {
"text1": "hello",
"text2": "there",
"text3": "ObiWan"
};
var randomNumber = Math.floor(Math.random() * 3) + 1; //creates random No. from 1 - 3
console.log(randomNumber)
document.getElementById("randomText").innerHTML = texts[`text${randomNumber}`];
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
Your question is focused on how to dynamically construct a variable name, but usually this problem comes up because the solution you are attempting is based on a coding pattern that has boxed you into a corner. Instead of writing a potentially hazardous solution or one that is overly complex, re-think your approach.
Whenever you have several pieces of data to store that don't have key names to go with them, you should be storing those data in an Array. The advantages to storing data in an array are huge. So, you should place the strings into an array instead of individual variables that all have to have similar names. So, now you have less variables to worry about and no variable names that have to be set to certain values and the problem of dynamically creating a variable name is gone entirely.
All you need to do now is to use the random number as an index to the array. Don't adjust the random to make it 1-based, because arrays are 0-based. And, when you get the random, multiply it by the length of the array, rather than hard code a number. This way, all you have to do is add/remove strings to the array for them to become possible resulting strings.
This structure and solution make your code simpler and more flexible.
Also, don't set up your event handlers using HTML event attributes. There are many reasons why you shouldn't use this 25+ year old technique. Do it in JavaScript.
var strings = ["hello","there","ObiWan"]; // Store the possible strings in an array
var btn = document.getElementById("randomText"); // Get a reference to the trigger element
var output = document.getElementById("output"); // And the output area
// Set up the event handler in JavaScript, not HTML
btn.addEventListener("click", function(){
// Set the output to a string from the array using a random index
output.innerHTML = strings[Math.floor(Math.random() * strings.length)];
});
<button id="randomText">click here</button>
<div id="output"></div>

Using javascript to Capitalize, Break it up with a new line every, and Add String to the beginning of each new line

Using javascript to (1) Capitalize all characters from a user input string, (2) break it up with a new line every 45 characters, and (3) add a certain string ("///////" for example) to the beginning of each new line.
I want a simple application where I can copy and paste a string of text, and have a function do the above.
For example:
Copy and paste "I am new to JavaScript, so even this simple code is very difficult to write" and get the following:
"
//////I AM NEW TO JAVASCRIPT, SO EVEN THIS SIMPLE C
//////ODE IS VERY DIFFICULT TO WRITE
"
I would like to, in the future, make it so that it doesn't cut off a word like that in the middle, and can use the SPACES to find where the new line should be, but that seems like a little much right now.
All I have is the Capitalization function working:
var txt = prompt("Enter string of text");
var cap = txt.toUpperCase();
alert(cap);
but I want it to run all three functions at once and alert() the final product.
In a "functional programming style", you can do it like this:
var txt = prompt("Enter string of text");
var cap = txt.toUpperCase().split('').reduce(function(agg, item, i) {
if(i % 45 === 0) {
if(i > 0) {
agg.push('\r\n');
}
agg.push('//////');
}
agg.push(item);
return agg;
}, []).join('');
alert(cap);
Essentially what happens here is that the string is:
Converted to upper case. Then...
Split into an array of single characters. Then...
The array is "reduced"1 to a new array with interwoven new lines and "separator" string (//////). Then...
The new array is joined to form a new string.
1 Reducing an array is an operation that iterates array items sequentially, and incrementally generating a single "reduced" result. Typically this is used in scenarios such as summing multiple values. In this code this is not a "logically correct" usage of this function as it doesn't reduce anything, but it does enable a functional style solution.

Javascript: Delete text after cursor

Have been trying to adapt a snippet of code I found that deletes 1 character forward in a block of text into a code snippet that deletes all text forward (i.e through the end) of the text block. I can make the length into a larger number (say 100) to capture most instances, but that does not seem as clean.
var sel = getSelectedRange();
var start = sel[0];
var length = sel[1];
setTextInRange(start, length == 0 ? 1 : length, "");
setSelectedRange(start, 0);
For example, if the text read "This is the sample text" and the cursor was in front of the word "is", the result would just be the word "This "
I am using this code in the Drafts app on iOS to process text - very new to this and first post, so hopefully I included all information...
Edit: The location of the Drafts app help page that details the functions being used.
Not sure I completely understood you but I've thrown a quick prototype together.
http://jsfiddle.net/5bLxjja9/
$("#Javascript_example").click(function(){
var x = $("#Javascript_example").val();
var newStr = []
for(var i = 0; i< curPosition();i++){
newStr.push(x[i]);
}
console.log(newStr.join(''));
$("#Javascript_example").val(newStr.join(''));
});
function curPosition()
{
var ctl = document.getElementById('Javascript_example');
var curPos = ctl.selectionStart;
return curPos;
}
Never used, nor completely sure what Drafts is but having a look at the function definitions you might just need to use a different one.
test = "The lazy brown dog" \\ (imagine brown was selected)
sel = getSelectedRange() \\ returns [10, 5] if i counted right...
if you want to delete "brown dog" you can't use the length returned by getSelectedRange you will need to determine the length of the entire string first.
length = getText().length
length = length - sel[1] \\ find the length you want
setTextInRange(sel[0], length, "")
hope this helps
Could you include the code for the functions getSelectedRange, setTextInRange & setSelectedRange? That would give me a better idea of what sel is.
You're right that setting length to 100 isn't that clean. What you want to do is dynamically get the length of the rest of the text & delete that. It could be that you just want to pass in sel.length, but I'm not too sure what sel is an array of.

How to reference an array in a function argument

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.

Categories