JavaScript - adding spaces after push in empty array & one checkbox is free - javascript

Here's my codepen:
https://codepen.io/CwittleZ/pen/vdzazO?editors=1010
When you click on the meat selection, it gets pushed into an array and then displayed, but there's no space between selections. How would I go about adding that space?
function meatSelected() {
var meat = [];
var meatChecked = document.querySelectorAll(
"input[name=meat_options]:checked"
);
for (var i = 0; i < meatChecked.length; i++) {
meat.push(meatChecked[i].value);
}
console.log(meat);
document.getElementById("meat").innerHTML = meat;
}
Also, I need one of the meats to be free, but anything over will be extra. I don't know how or where to add that 'if meat checked is > 1, all other meats will be an additional $1 each.' Is there somehow a way to access the function meatSelected for that purpose? I'm just starting out with JavaScript, so please no jQuery and simple terms if possible, even if it is a longer code. I just want to be able to understand why it works.
if (document.getElementById("pepperoni").checked) {
add += 1;
}
if (document.getElementById("sausage").checked) {
add += 1;
}
if (document.getElementById("canadian_bacon").checked) {
add += 1;
}
if (document.getElementById("ground_beef").checked) {
add += 1;
}
if (document.getElementById("anchovy").checked) {
add += 1;
}
if (document.getElementById("chicken").checked) {
add += 1;
}

The answer is in the line 83 in JavaScript part of your example. In line 77, you made an array of possible meats. Then, you just used this array and attached it to innerHTML as it is, so that the browser has to make it a string. Unfortunately, it doesn't care about spaces.
So, just change that line to this:
document.getElementById("meat").innerHTML = meat.join(", ");
It will use your already made array and convert it directly into string, with ", " between each of its children.
And to your second question, there are more possible solutions, I've implemented the easiest one in this codepen: https://codepen.io/anon/pen/ddqqyY?editors=1010.
Just sum up the number of already selected meats and if it's larger than zero, subtract 1 from your total.

I'd wrap each one of your selections in a "span", and add a margin after. You're using innerHTML, so you can just do it that way. It'll provide more flexibility than trying to style the plain-text.

document.getElementById("meat").innerHTML = meat.map(m => ` ${m}`);
here is your codepen that is modified https://codepen.io/jayas/pen/bLxjXo?editors=1010
edit as per suggestion
The ${m} together with the enclosing ticks `` used in the statement is called a template literal. Template literals can contain placeholders
and these are indicated by the dollar sign and curly braces ${}.
[].map(callBackFunc) used above is a method that creates a new array with each element being the result of the callback function.

Related

double conditions in if statement

as I'm not that good in coding i have a small issue in my code that i need to find a solution for it. my code bellow that i made is to transfer data from one sheet to another one based on value on a specific cell, that it's working perfectly, but for another case that i have i need to make double conditions for my if statement that they need to be both of them true so it can work, first condition it's the one that i already made, and the second one is i want to check if the cell number 12 is not empty.
for (i = 1; i < dataValues.length; i++) {
if (dataValues[i][11] === 'COMMANDE CONFIRMER' && ) {
pasteSheet.appendRow([dataValues[i][0],
dataValues[i][1],
dataValues[i][2],
dataValues[i][3],
dataValues[i][4],
dataValues[i][5],
dataValues[i][6],
dataValues[i][7],
dataValues[i][8],
dataValues[i][9],
dataValues[i][10],
dataValues[i][11]]);
var clearRow = i + 2;
copySheet.getRange('A' + clearRow + ':L' + clearRow).clearContent();
}
}
Column L is probably [i][11]
Based up what you added in the comment below I'd say that this is probably what you are after.
if (dataValues[i][11] === 'COMMANDE CONFIRMER' && dataValues[i][12]) { so then all you need is to make sure it's not empty. Or it's also possible that you not really sure what you want so let us know.

What would cause slice() to work, but splice() to fail?

I am working on a sheet that contains job description information, including an Overview and Responsibilities. The source data is not exact, but it roughly has the Overview in one cell of a column, and each Responsibility in additional cells in the same column. I am writing the Overview (which I am determining based on character count) in one results column, and building an unordered list with each the Responsibilities into another results column.
My source isn’t always perfect though. I have situations where the first Responsibility is included in the same cell as its corresponding Overview. I can recognize that by the text, and have an indexOf() statement written to do that.
When I use a slice() method, the script is correctly indicating the text that is occurring after the appropriate index. But what I need is to use the splice() method, so that I can remove that text from the source data before creating the results data. However, when I change the statement from slice() to splice(), I’m getting an error: “TypeError: Cannot find function splice in object {beginning text of the cell}”
for(i=0; i<data.length; i++) {
var iRow = data[i];
if(iRow[12].length > 250) { // this is an overview
if(iRow[12].indexOf("What you’ll do")>-1) { // is there a responsibility at the end of the overview?
var startIndex = iRow[12].indexOf("What you’ll do");
// this is the line that works for slice(), but not splice()
var txt = iRow[12].splice(startIndex, 26); // splice out the end of text, starting at the index.
data[writeRow][18] += iRow[12]; // write the overview, without the added responsibility
data[writeRow][19] += "<li>" + txt + "</li>"; // add the extracted responsibility to its list
} else { // these is no responsibility added to the end of the overview
data[writeRow][18] += iRow[12]; // write the overview
}
} else { // this is a responsibility
data[writeRow][19] += "<li>" + iRow[12] + "</li>"; // add it to the list
}
}
There's obviously a lot more going on (defining var data, var writeRow, initiating the , etc) which all works fine. I’m sure that I’m just being an idiot somewhere. But can someone help me figure out why slice() works here, but splice() doesn’t?
splice is an array function. slice is both, an Array function and a String function.
References
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice

AngularJs Filters

I'm writing a module, using a custom filter, and I noticed something weird. if I use console.log() inside a filter, it logs the value twice, even though I call it only once. Is there a way to log it only once? Does that mean the code inside the filter gets executed twice?
Here's the filter:
.filter('arrayToSentence', function($sce, $rootScope) {
return function(array, index) {
console.log(index);
var i, word, sentence = '<span style="color:red;">';
for (i = 0; i < array.length; i++) {
if (i < array.length - 1) {
sentence += array[i] + '&bnsp;';
} else {
sentence += array[i];
}
}
sentence = sentence += '</span>'
return $sce.sentence;
}
})
The console.log(index) is logging twice. I need to make sure that my filter logic will not be duplicating anywhere, as further down I need to compare two arrays (the one being filtered, and another one to colour the differences between them, like missing word, or word mismatch).
[EDIT]
It is pointed out to me that my question is a duplicate, of this
Yet the original question doesn't answer how to avoid this issue, but I believe #defaultcheckbox provided a fulfilling answer.
Are you using the filter in the DOM with piping, or are you using it in the controller? Using a filter in the DOM will always be "slower" than using one in the controller, but more importantly (and possibly related to your case) DOM filters always run twice.
source: https://toddmotto.com/use-controller-filters-to-prevent-digest-performance-issues/

Looping to a specific index within a string

I'm currently doing a puzzle and am having trouble formulating my thoughts on how to do the following. Heres some code for some context on my thoughts (this isn't working yet)
const words = ['this', 'is', 'my', 'dog', 'bit', 'bite', 'every'];
const strings = ['thisis', 'thisisacat', 'thisisaduck', 'thisismy', 'thisismydog', 'bitevery'];
var count;
for (var i = 0 ; i < strings.length ; i++)
{
for (var j = 0; j <words.length; j++)
{
if(strings[i].indexOf(words[j]) !== -1)
{
count+=words[j].length;
}
}
}
Basically I want to first go to the word this check if it is in strings[j]. If it is then get the length of words[i], and go to the words[i]'th position inside strings[j] meaning I want the 'is' part of the 'thisis'. Basically I just want to test whether each element in strings can be represented by any amount of combos in words. This of course can be done with regular expressions, but I would like to use the current thought process that I have.
TLDR
With my current way, how can I check whether words in the words array exist within each element of strings(I am attempting this with indexOf), and if it is, go to the length of that words position meaning go to the position where i is in thisis. I realize that the way I am phrasing it it might be a bit verbose, but I'm not sure how else to phrase it. Any help is appreciated.
Example Run
We are at strings[i], now we check if any element in words is in strings[i]. Now this is in 'thisis', so add an index of four, since this has a length of four, to get to the 4th position and beyond of thisis, now we have isso loop again through the rest of words, now is is inside is, that means we have succesfully created a word from using some amount of words in the words array. Note, I actually don't want to delete the this from thisis, as I know modifying strings altogether is very costly in memory.
Another Run
Take thisismydog in strings. Let us iterate through words. this is inside thisismydog, so now go to the 4th onwards of thisismydog ( since this has a length of 4) namely now we consider ismydog. Now iterate again looking at the elements in words. We see is is there, so we go to the second element in ismydog, namely mydog. Since we reach the end of the word we can successfully conclude that thisismydog can indeed be represented by a combination of those elements within words.

Custom function for Google Spreadsheet - handling the array passed from the spreadsheet

I am trying to build a simple script to work with a Google Spreadsheet. The spreadsheet takes input from a Google Form, so there is a series of values in the spreadsheet like this:
My goal is to write a script that would strip the number from each form input in a user-specified range, then add all the numbers to provide a single score. So, for example, the user could type =sumColumns(H2:K2) in a cell, and it would return the sum of the scores (for the sample screenshot I posted, it would return the result of 3+3+0+3, 9).
Here is the code that I wrote to do this:
function sumColumns(values) {
var sum = 0;
for(var i = 0; i <= values.length; i++){
var input = values[0][i];
var x = input.toString();
var y = x.charAt(0);
var num = parseInt(y);
sum += num;
}
return sum;
}
The problem is that it only ever seems to add two values together. So, when I put =sumColumns(H2:K2) in a cell in the spreadsheet, it only returns 6. Also, on line 3, if I change it from i <= values.length to i < values.length it only adds one number, so that I get 3 as a result. My guess is that I am misunderstanding the way that the Google Spreadsheet values are passed to the function, but I have been completely unable to make it work. I'd really appreciate any help!
Oops - edited & saved the question, wrote an answer - and forgot to save it. I let Serge beat me to it! And, as usual, Serge's answer works well (with integer values). But you did ask about how things worked, so here you go.
When you give a Custom Function a range as a parameter, H2:K2 in this case, the function receives a two-dimensional array, equivalent to the return value of Range.getValues(). You can test this easily, by (temporarily) changing your function to return a JSON representation of the parameter:
function sumColumns(values) {
return JSON.stringify(values); // For debugging, just return string showing values
...
Here's what you'll see in the cell that contains =sumColumns(H2:K2):
[["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"]]
That's showing an Array enclosed by [ .. ], with another Array inside, also enclosed by square brackets, and that array has four elements. If we change the range to be H2:K3 instead, we get this (with whitespace added for clarity):
[
["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"],
["","","",""]
]
Now that you know that, it's easy to see why your function was giving the results it did.
First, for(var i = 0; i <= values.length; i++) is using the wrong array bounds to loop over, since values.length will tell us how many rows are in values. In H2:K2, that length is 1. Instead, we need to be looping over the columns in the first row (values[0]), with its 4 cells.
You were wondering about < vs <= for this loop - we do need to use < since it's a 0-based index, and .length returns a count of elements. So we end up with:
for (var i=0; i < values[0].length; i++){ ... }
Using parseInt() is a good choice, and works well for the values in your spreadsheet. It can be improved, though, by ensuring that any String values have leading non-numeric values stripped first - parseInt() can then find an Integer inside a string.
function sumColumns(values) {
return JSON.stringify(values); // For debugging, just return string showing values
var sum = 0;
for(var i = 0; i < values[0].length; i++){
var input = new String(values[0][i])
.replace( /^\D+/g, ''); // Strip any leading non-digits
sum += parseInt(input);
}
return sum;
}
I'm not good with custom function because I never use them but it seems that values is not really an array...
Comments in italic :
Hmmm embarrassing ... my first though was that it had to be a 2D array but I logged val[0] in my test and it returned an 'undefined' error... I must have mistyped something at that moment... Anyway, that's why I looked for a way around handling data as a string and using split and regex.
As usual with Mogsdad's answers you have an answer and all the explanations that go with it ;-) and, as often with him too, you get a better answer than mine.
(one restriction though (#Mogsdad) your comment about non integer values could be applied to your code as well... you simply strip out any decimal value with parseInt()...:-)
That said, your use case was well described and in the limits of this example both code should work as expected, Mogsdad's one being more 'academic' and programmatically correct.
end of comment.
Using this trick below it works as expected for any input range (1 or more row and columns):
function sumCol(val) { // returns the sum of all numeric values in range
var values = val.toString().split(',');
var sum = 0;
for(var n=0;n<values.length;++n){
sum+=Number(values[n].replace(/[^0-9+.]/ig,''));
}
return sum;
}
I changed also the number extraction mode to make it more universal.

Categories

Resources