Dictionary Syntax Error in Google Apps Script - dictionary

I have a function that creates a dictionary based on a series of values from a sheet. I then try to pull one of the values from that sheet using a key. It works fine to log to the console. However, in an if statement, it says syntax error and nothing else. I cannot figure it out. Here is the function and the code that crashes. This problem only occurs in the for loop, and does not occur outside of it.
//creates dictionary
function columnLocationWithNotation(notation) {
var spreadsheet = SpreadsheetApp.openByUrl();
var sheet = spreadsheet.getActiveSheet();
var data = sheet.getDataRange();
var cells = data.getValues();
var dictionary = {};
switch (notation) {
case "zeroIndex":
for (var i = 0; i < sheet.getLastRow(); i++) {
dictionary[cells[i][0]] = cells[i][1]
}
return dictionary
break;
case "regularIndex":
for (var i = 0; i < sheet.getLastRow(); i++) {
dictionary[cells[i][0]] = cells[i][2]
}
return dictionary
break;
case "string":
for (var i = 0; i < sheet.getLastRow(); i++) {
dictionary[cells[i][0]] = cells[i][3]
}
return dictionary
break;
}
}
var master0indexDictionary = columnLocationWithNotation("zeroIndex")
for (var i = 1; i =< (sheet.getLastRow() - 1); i++) {
var phone = master0indexDictionary["Tutor Name"]
if (cells[i][phone] === phoneNumber) { //LINE WITH SYNTAX ERROR
//do something
}

It's not the highlighted line that is causing the problem, even though there are many other issues with your script. There's no '=<' operator in JavaScript. Use '<=' instead:
for (var i = 1; i <= (sheet.getLastRow() - 1); i++) {
Also, as Tanaike pointed out, your 'cells' variable is only defined in the context of your 'columnLocationWithNotation(notation)' function and will not be accessible from the global context. Globally-defined variables are visible from the functions you declare inside the global object, but not vice versa. Same applies to the 'sheet' variable. The 'phoneNumber' variable doesn't seem to be defined, at least not in the snippet of code you provided.
Note that putting 'break' after 'return' statements is redundant.
return dictionary;
break;
You can just return out of 'switch' statement without using breaks, or leave the breaks and put a single 'return' statement after 'switch'.
Finally, always put a semicolon at the end of the line. Doing so will help you avoid many potential pitfalls and issues with JS parser. I noticed several instances where you omitted the semicolon:
return dictionary
break;
var phone = master0indexDictionary["Tutor Name"]
For example, the following code will break if you don't have a habit of putting the semicolon in its rightful place
var a = {name: 'John'} //no semicolon
[a].forEach(function(element) {
Logger.log(element); //logs undefined
})
The JS parser treats this code as one line, so 'a' will still be 'undefined' by the time you call the 'forEach()' loop on the array.

Related

Debugger blows up in JsonElement.DebuggerDisplay.get

I'm writing my first project trying to use System.Text.Json in a .net core app. I'm getting a jsonl file with a particular structure, and my requirements are in effect to UNPIVOT/flatten an array of child objects in one object into a stream of transformed objects.
It was going fine until I put a breakpoint on the routine doing the UNPIVOT and the debugger itself started blowing up with an access violation in JsonElement.DebuggerDisplay.get. Interestingly,
a) it floats around which row it blows up on and b) it seems to be somewhat dependent on how long I wait before clicking Continue. In other words, if I wait a couple of seconds, it seems to work; if I click right away it blows up faster.
Just wondering if anyone else had run into something like this. And whether I should just switch back to NewtonSoft to avoid the headache.
Here's what my code looks like:
public static IEnumerable<MyResult> ConvertJson(JsonElement input)
{
JsonElement transformArray, base_url;
if (!input.TryGetProperty("child_objects", out transformArray) || transformArray.ValueKind != JsonValueKind.Array)
yield break;
if (!input.TryGetProperty("base_url", out base_url) || base_url.ValueKind != JsonValueKind.String)
yield break;
int i = 0;
foreach(var o in transformArray.EnumerateArray())
{
// Break point on line below. Click Continue too quickly, and I get DebuggerDisplay.get access violation
var result = new MyResult();
result.BaseURL = base_url.ToString();
result.PageID = i; i++;
JsonElement prop;
if (o.TryGetProperty("prop1", out prop) && prop.ValueKind == JsonValueKind.String) result.Prop1 = prop.ToString();
if (o.TryGetProperty("text", out prop) && prop.ValueKind == JsonValueKind.String) result.Text = prop.ToString();
if (o.TryGetProperty("language", out prop) && prop.ValueKind == JsonValueKind.String) result.Language = prop.ToString();
yield return result;
}
}
and it's called like this:
string l = JsonlStream.ReadLine();
var json = JsonSerializer.Deserialize<JsonElement>(l);
foreach (var i in ConvertJson(json))
{
...
}

Meteor collection insert from input element

This code is trying to insert the data from input elements on the page into a Meteor Collection Task1
I am getting "App is crashing error" because of the Tasks1.insert line. Why and how can I fix it?
I need to get the element name and value as the key:value pair for the Document being inserted. Thanks
Template.footer.events({
'click button': function () {
if ( this.text === "SUBMIT" ) {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
Tasks1.insert({inputs[i].name: inputs[i].value});
}
}
}
});
inputs[i].name cannot be used as a key of an object literal, because it's a variable and we can only use strings for defining properties in an object literal.
Like this it should work (it's the most common workaround):
for (var i = 0; i < inputs.length; i++) {
// First define a variable
var params = {};
// Then you can use a variable (or a function) to set the key
params[inputs[i].name] = inputs[i].value;
Tasks1.insert(params);
}

SQLite read from SQLITE database in plugin

I need to read values from an SQLite database in my plugin. For that I found the sqlite.jsm module. My problem is I want to make a row as a global variable, but the code used in SQLite (promises and tasks) is asynchronous. Is there a way I can collect information from my database into a global variable?
let iDs = [];
Task.spawn(function* () {
let db = yield Sqlite.openConnection({ path:
permissionFilePath});
try {
let row = yield db.execute(
"SELECT id FROM 'moz_hosts'");
for ( i=0; i < row.length; i++) {
console.log("row["+ i +"] :" +
row[i].getResultByIndex(0));
yield iDs.push(row[i].getResultByIndex(0));
}
}
finally {
yield db.close();
}
});
// Part of the code that doesn't work, because IDs are not yet assigned any values!
console.log("debug");
for (i=0; i<iDs.length; i++) {
yield console.log("iDs ["+i+"] = "+ iDs[i]);
}
First of all, for a Task you only have to yield things that return promises and therefore run asynchronously. There is no need to yield iDs.push(row[i].getResultByIndex(0));, because the push operation will synchronously return the new length of the array. This shouldn't be much of an issue for the code itself though.
Do you really need the ids to be global? Maybe you can refactor your code so that you don't need to save them globally.
If this is not an option, you will have to block all operations that are going to access the ids until the SQL call has completed. You can do this by relying on the fact that Task.spawn() itself will also return a promise. This also has the nice side effect that you don't need the extra global array:
let idsPromise = Task.spawn(function*() {
let ids = [];
let db = yield Sqlite.openConnection({ path: permissionFilePath});
try {
let row = yield db.execute("SELECT id FROM 'moz_hosts'");
for (let i = 0, len = row.length; i < len; i++) {
ids.push(row[i].getResultByIndex(0));
}
// Instead of the loop you can also use:
// ids = row.map(row => row.getResultByIndex(0));
} finally {
yield db.close();
}
return ids;
});
Then, in other parts of your code, when you want the ids you can use:
idsPromise.then(function(ids) {
// Do something with ids
});
Alternatively, you can also get them in a Task:
Task.spawn(function*() {
let ids = yield idsPromise;
});
You can do this multiple times. Once a promise is resolved the then() part will be executed as soon as possible.

how to handle this type of things. using asp.net mvc

I have
public jsonresult update(studentinfo s)
{
for(i=0;i>0;i++)
{
var x = // i am getting some x so i am checking again
if( x != null)
{
var updateuser = student.update(s.student,"","");
**return json(updateuser.ToString());** // if i keep it here i am getting exceptoin saying not all code paths return value bec this return i can not keep it out for loop bec each and evary updateuser i need to return json..
}
}
}
How to overcome this type of things?
What language are you using to write your code? What you've posted doesn't look like any of the valid languages I know for .NET. Here's how the controller action might look in C# (assuming this is the language you are using):
public ActionResult Update(StudentInfo s)
{
// create some collection that will contain all updated users
var updatedUsers = new List<StudentInfo>();
// Revise the loop as it is absolutely not clear from your code
// what you are trying to do. The way you wrote the loop it will
// never execute - for(int i=0; i>0; i++)
for (int i = 0; i < 5; i++)
{
var updatedUser = student.Update(s.student, "", "");
updatedUsers.Add(updatedUser);
}
// return the list of updated users outside the loop so that the compiler
// doesn't complain about paths of the method not returning a value
return Json(updatedUsers);
}
If I understand correctly, you want to return a collection of users. The 'return' keyword does not work like that. You need to return the entire collection at once.

Create HTML table out of object array in Javascript

I am calling a web Method from javascript. The web method returns an array of customers from the northwind database. The example I am working from is here: Calling Web Services with ASP.NET AJAX
I dont know how to write this javascript method: CreateCustomersTable
This would create the html table to display the data being returned. Any help would be appreciated.
My javascript
function GetCustomerByCountry() {
var country = $get("txtCountry").value;
AjaxWebService.GetCustomersByCountry(country, OnWSRequestComplete, OnWSRequestFailed);
}
function OnWSRequestComplete(results) {
if (results != null) {
CreateCustomersTable(results);
//GetMap(results);
}
}
function CreateCustomersTable(result) {
alert(result);
if (document.all) //Filter for IE DOM since other browsers are limited
{
// How do I do this?
}
}
else {
$get("divOutput").innerHTML = "RSS only available in IE5+"; }
}
My web Method
[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
NorthwindDALTableAdapters.CustomersTableAdapter adap =
new NorthwindDALTableAdapters.CustomersTableAdapter();
NorthwindDAL.CustomersDataTable dt = adap.GetCustomersByCountry(country);
if (dt.Rows.Count <= 0)
{
return null;
}
Customer[] customers = new Customer[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
NorthwindDAL.CustomersRow row = (NorthwindDAL.CustomersRow)dt.Rows[i];
customers[i] = new Customer();
customers[i].CustomerId = row.CustomerID;
customers[i].Name = row.ContactName;
}
return customers;
}
Try to look what is the result variable value in debug mode. If the structure seems the structure that i'm imagining, something like this could work:
function CreateCustomersTable(result) {
var str = '<table>';
str += '<tr><th>Id</th><th>Name</th></tr>';
for ( var i=0; i< result.length; i++){
str += '<tr><td>' + result[i].CustomerId + '</td><td>' + result[i].Name + '</td></tr>';
}
str += '</table>';
return str;
}
And then You can do somethig like this:
var existingDiv = document.getElementById('Id of an existing Div');
existingDiv.innerHTML = CreateCustomersTable(result);
I wish this help you.
Something like this, assuming you have JSON returned in the "result" value. The "container" is a div with id of "container". I'm cloning nodes to save memory, but also if you wanted to assign some base classes to the "base" elements.
var table = document.createElement('table');
var baseRow = document.createElement('tr');
var baseCell = document.createElement('td');
var container = document.getElementById('container');
for(var i = 0; i < results.length; i++){
//Create a new row
var myRow = baseRow.cloneNode(false);
//Create a new cell, you could loop this for multiple cells
var myCell = baseCell.cloneNode(false);
myCell.innerHTML = result.value;
//Append new cell
myRow.appendChild(myCell);
//Append new row
table.appendChild(myRow);
}
container.appendChild(table);
You should pass the array as JSON or XML instead of just the toString() value of it (unless that offcourse is returns either JSON oR XML). Note that JSOn is better for javascript since it is a javascript native format.
Also the person who told you that browser other then IE can not do DOM manipulation should propably have done horrible things to him/her.
If your format is JSON you can just for-loop them and create the elements and print them. (once you figured out what format your service returns we can help you better.)

Resources