Iterating over an array in packages - backbone.js

I want to create a handlebars helper that works like {{#each}} but gives me the possibility to specify a number so that every n iterations some additional code is run.
The reason I need this is that I need to spit out the content in rows of three items, so every three items I need to open and close a new container div.
Of course I could simply let backbone format the array in packages of three items and iterate over that using {{#each}} but I thought it would be more elegant to create a helper so that I can say something like
{{#each_pack data 3}}
<div class="container">
{{#each pack_items}}
<span>{{content}}</span>
{{/each}}
</div>
{{/each_pack}}
I'm not entirely sure how to do this.
How do I make pack_items available to the inside block?

I solved this in a way that lets me use the exact same syntax I just proposed.
Here is the code:
window.Handlebars.registerHelper('each_pack', function(context, packsize, fn){
var ret = '';
/*
Function that creates packages of size
packsize from a given array
*/
var packagify = function(array, packsize){
var i = 0;
var length = array.length;
var returnArray = [];
var pack = [];
while(i < length){
/*
If this is not the first entry,
if this is the packsize-d entry
or this is the last entry,
push the pack to the return array
and create a new one
*/
if(((i % packsize) == 0 && i != 0) || (i == (length - 1))){
returnArray.push(pack);
pack = [];
}
pack.push(array[i]);
i++;
}
return returnArray;
}
var packArray = packagify(context,packsize);
for(var i = 0; i < packArray.length; i++){
var pack = packArray[i];
this['pack_items'] = pack;
ret = ret + fn(this);
}
delete this['pack_items'];
return ret;
});

Related

Value not returning right

I am having a issue getting my code to return the correct value.
I am building spreadsheet to help me with cooking for a video game I play. I am trying to track the amount of all the ingredients I have for cooking. I want to be able to update the amount I have from a dashboard rather than go scroll through the list to find each ingredient individually.
Here is what I have setup so far.
I have a page called Updater where I am selecting from a drop down a certain ingredient(cell A2). Next to that drop down is cell for me to enter a new amount of that ingredient that I have(cell B2).
The second page is called Ingredients. This has a 2 columns. Column 1 is a list of the ingredients and in column 2 is the number I currently have on hand.
The script I have written so far can find me the row number, but when I try to get the current amount I have for the ingredient to make sure the code is working, it doesnt return anything in the log.
There is my code
function finalTest(){
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var fs = spreadsheet.getSheetByName("Ingredients");
var ts = spreadsheet.getSheetByName("Updater");
var data = fs.getDataRange().getValues();
var luItem = ts.getRange("A2").getValue();
var newAmt = ts.getRange("B2").getValue();
var rn = 0;
Logger.log(rn);
Logger.log(newAmt);
Logger.log(data);
Logger.log(luItem);
for(var i = 0; i<data.length;i++){
if(data[i][0] == luItem){ //[1] because column B
Logger.log((i+1))
return i+1;
}
}
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
}
Right now the logger will return up to where it logs "i", but will not return the new rn or fsr values.
Any help would be greatly appreciated.
A function immediately returns on the return statement. So you can only return one value there - or an object with multiple values inside.
As it looks that you just want to log data out, you would have to do that inside the if, but before the return to reach:
for (var i = 0; i < data.length; i++) {
if (data[i][0] == luItem) {
// first do all the logging
Logger.log(i + 1);
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
// and then return from the function
return i + 1;
}
// what should be returned here??
}
Please also note that you should return a value or handle it somehow else when the loop runs through and the condition is never met.
If the return value then is still i + 1, you could make the if-condition instead part of the stop condition of the loop:
var i = 0;
for (; (i < data.length) && (data[i][0] == luItem); i++);
// no loop body needed here!
// do the logging outside the loop
Logger.log(i + 1);
rn = i;
Logger.log(rn);
var fsr = fs.getRange(rn,2).getValue();
Logger.log(fsr);
// and then return from the function
return i + 1;

Replace user in a protected range by script (Google Sheet)

here my specific case:
I have some range protected in google sheets
I need to replace some specific Editor if is editor of those range (var Editor2Replace and Editor2Add are emails)
Logically I tried to, for each sheet:
Cycle (FOR) of all the protected range (counter p)
For each protected range catch current editors and have it in array
Of the Editors read the email ==> this is what generate the mistake
Cycle (FOR) all the editors looking if someone of those is == Editor2Replace (that
is an email)
Here the code, but something is logically wrong, I doubt in what is an array and what not..
var Protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var p = 0; p < Protections.length; p++) {
var Protection_Desc = Protections[p].getDescription();
var Protection_Editors = [];
var Protection_Editors = [Protections[p].getEditors()];
for (var r = 0; r < Protection_Editors.length; r++){
var Protection_Email[r] = [Protection_Editors[r].getEmail()];
if (Protection_Idontknow == Editor2Replace){
Protections[p].addEditor = Editor2Add;
Protections[p].removeEditor = Editor2Replace;
var Protection_Range = Protections[p].getRange();
var Protection_Row = Protection_Range.getRow();
var Owner1 = sheet.getRange(Protection_Row,5).getValue();
var Owner2 = sheet.getRange(Protection_Row,6).getValue();
if (Owner1 == Editor2Replace){
sheet.getRange(Protection_Row,5).setValue(Editor2Add);
}
if (Owner2 == Editor2Replace){
sheet.getRange(Protection_Row,6).setValue(Editor2Add);
}
}
}
Many thanks for hepling
There were a lot of issues in your script and I will enumerate them one by one. Also, I was able to replace a user in the protected sheet by modifying your script.
Issues:
Duplicate declaration
var Protection_Editors = [];
var Protection_Editors = [Protections[p].getEditors()];
Storing the returned value (array) in another array (which should not be done in your issue, it doesn't help you with anything)
var Protection_Editors = [Protections[p].getEditors()];
...
var Protection_Email[r] = [Protection_Editors[r].getEmail()];
Newly declared variable having an index (which I don't understand why)
var Protection_Email[r] = [Protection_Editors[r].getEmail()];
Variable not declared Protection_Idontknow
if (Protection_Idontknow == Editor2Replace){
Incorrect usage of methods addEditor and removeEditor
Protections[p].addEditor = Editor2Add;
Protections[p].removeEditor = Editor2Replace;
Below code should fix those issues (added some comments):
Code:
var Protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var p = 0; p < Protections.length; p++) {
var Protection_Desc = Protections[p].getDescription();
// returned value of getEditors is already an array, return as is
var Protection_Editors = Protections[p].getEditors();
for (var r = 0; r < Protection_Editors.length; r++) {
var Protection_Email = Protection_Editors[r].getEmail();
// compare current email with the one you want to replace
if (Protection_Email == Editor2Replace) {
// add new and remove the one to replace
Protections[p].addEditor(Editor2Add);
Protections[p].removeEditor(Editor2Replace);
}
}
}
Note:
I have removed anything that were unrelated to the replacement of editors.
Reference:
Protection

Can I create array based on field names that exist in PDF?

I am trying to count the number of a specific field which is not empty and would like to use an array to store the field names based on whether they exist in the PDF form.
My code looks like this so far and it works as long as the field names in the array exists, if that field does not exist then the code breaks.
The SiteDeficiency_DeficiencyNumber_# could have 0 instances or anywhere up to 50 instances or so.
I did find that you can check if a name exists with this code but I can't seem to get it to work.
Any help is appreciated. I have coded simple things but maybe this is just too advanced for me.
This is what my code looks like so far:
var aFields = new Array("SiteDeficiency_DeficiencyNumber_1",
"SiteDeficiency_DeficiencyNumber_2",
"SiteDeficiency_DeficiencyNumber_3",
"SiteDeficiency_DeficiencyNumber_4",
"SiteDeficiency_DeficiencyNumber_5",
"SiteDeficiency_DeficiencyNumber_6");
var count = 0;
for (i = 0; i < aFields.length; i++) {
if (this.getField(aFields[i]).valueAsString != "") count++
}
event.value = count;
I tried incorporating this too
if(document.forms[0].SiteDeficiency_DeficiencyNumber_1)
{
...
}
I would really like the array at the beginning to populate with only the SiteDeficiency_DeficiencyNumber_# fields that exist and then have the array looped through to count which fields are not blank.
I tried doing this but still does not work.
var aFields = [];
for(i = 1; i <101; i++)
{
if(document.forms[0].("SiteDeficiency_DeficiencyNumber_"+i).valueAsString.length > 0) //Checks if field exists
{
aFields.push("SiteDeficiency_DeficiencyNumber_"+i); //adds field name to array
}
}
var count = 0;
for (a = 0; a < aFields.length; a++) {
if (this.getField(aFields[a]).valueAsString != "") count++ //counts field if not empty
}
event.value = count;
Try this code:
var count = 0;
for(var i = 0; i < this.numFields; i++)
{
if (this.getNthFieldName(i).indexOf("SiteDeficiency_DeficiencyNumber")!= -1){
if (this.getField(this.getNthFieldName(i)).valueAsString != "")
count = count +1
}
}
event.value = count;
The first if statement will check if name of the field contain string SiteDeficiency_DeficiencyNumber. If SiteDeficiency_DeficiencyNumber is present in the field naem then it will check the field value and increment accordingly.
Don't forget to upvote! let me know if you need anything else

AS3 Picking a random object from an Array with certain conditions

I'm looking for the fastest way to pick a random object that has a certain condition (from an array).
In the example below I have a multidimensional array, 50 * 50 that contains objects. I want to pick a random object from that array but that object needs to have a size larger than 100.
while (object.size <= 100)
{
attempts++;
object = grid_array[Math.round(Math.random() * 49)][Math.round(Math.random() * 49)];
}
Currently I have tested this and in some instances it takes over 300+ attempts. Is there a more elegant way to do this?
Thanks,
What I would do is first filter the source array to extract only valid candidates, then return a random one (if there are any).
For example:
function getRandomObject(grid_array:Array, minSize:Number):Object {
var filtered:Array = [];
for(var i:int = 0; i < grid_array.length; i++){
var inner:Array = grid_array[i];
for(var ii:int = 0; ii < inner.length; ii++){
var object:Object = inner[ii];
if(object.size >= minSize){
filtered.push(object);
}
}
}
return filtered.length ? filtered[int(Math.random() * filtered.length)] : null;
}
// example:
var object:Object = getRandomObject(grid_array, 100);
if(object){
// do stuff with `object`
}
I asked if you need the indexes because you could do this with RegExps and the JSON Class (Flash Player 11). With this example I stored the indexes of the objects:
Create random multidimensional Array to test the function
//---I stored a variable size and the indexes inside the Object
//---Size variable will be numbers between 0 and 500
var array:Array = [];
var i;
var j;
var size:uint = 50;
var obj:Object;
for(i = 0; i < size; i++){
array[i] = [];
for(j = 0; j < size; j++){
obj = new Object();
obj.size = Math.floor(Math.random() * 500);
obj.files = i;
obj.columns = j;
array[i][j] = obj;
}
}
Method to get random Object with size property bigger than 100
//---I'll use to search the object a JSON string
var str:String = JSON.stringify(array);
//---Function to get the random Object
function getRandom():Object{
//---RegExp to search object with size between 100 and 500
var reg:RegExp = /\{[^\}]*"size":(?:10[1-9]|1[1-9]\d|[2-5]\d\d)[^\}]*\}/g;
//---Get all matches
var matches:Array = str.match(reg);
//---Return a random match converted to object
//---If no match founded the return will be null
return matches ? JSON.parse( matches[Math.floor(Math.random() * matches.length)] ) : null;
}

can I check a regular expression on one array element?

I am trying to test if a specific element in an array is a range of characters, from a-z lowercase. what am I doing wrong? I am very new to coding (1 month in) and I am probably trying to do stuff thats too hard for me.
var array ["a","b","c"];
var myRegularExpression = /[a-z]/;
if (myRegularExpression.test(array[index])) {
//do stuff
}
To give you a working example as #Tushar mentioned:
var arr = ["a","b","c","123"];
var myRegularExpression = new RegExp("^[a-z]+$");
var matchCount = 0;
for (var index = 0; index < arr.length; index++) {
if (myRegularExpression.test(arr[index])) {
//do stuff
matchCount += 1;
}
}
document.getElementById("result").innerText = matchCount;
Number of elements matching the regex "^[a-z]+$":
<div id="result"></div>

Resources