0

I have this code but I would like to add a ternary operator so that if the cell from the spreadsheet is empty it is replaced by an empty space and thus avoid 'Cannot destructure property 'v' of 'object null' as it is null'

(async () => {
  const data = JSON.parse(
      (
        await (
          //we select the columns we want to use where the box in column C is checked
          await fetch(
            "https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/gviz/tq?&sheet=users&tq=Select%20A,B,C,D,E,F,G,H,I,J,K%20WHERE%20C=true"
          )
        ).text()
        //we remove the first 47chars and last 2 to remove the wrapping text
      ).slice(47, -2)
    )["table"],
    products = data["rows"].map((row) =>
      row["c"].reduce(
        (product, {
          v: value
        }, index) => ({
          ...product,
          [data["cols"][index]["label"]]: value
        }), {}
      )
);
...

I tried to add it myself but it does not work, I am not familiar with javascript and do not get why it doesn't work. Here's what I tried:

[data["cols"][index]["label"]]: value ? value : ' ' ;

Any help welcome

EDIT to add link to codepen: https://codepen.io/Dendenzilla/pen/jOxvMZQ

Dendenzilla
  • 390
  • 2
  • 12
  • 3
    The error is coming from ```product, { v: value }, index```. What you do **inside** the function isn't really relevant. – Quentin Oct 06 '22 at 13:48
  • 2
    The error is not coming from the _"what I tried..."_ line in the script. The error talks about the identifier `v` so it's `(product, { v: value }, index) => ...)` this part – Andreas Oct 06 '22 at 13:48
  • Use `.json` to get the JSON output (without needing to parse the JSON) – evolutionxbox Oct 06 '22 at 13:50
  • Thanks for pointing that out, but then what can I do, putting my ternary there does not work either, maybe because I write it wrong ? – Dendenzilla Oct 06 '22 at 13:54
  • I edited my question to add the Codepen link, maybe you could show me how to implement your answer cause when I do it creates errors. – Dendenzilla Oct 06 '22 at 14:18
  • Just don't destructure the argument. – Quentin Oct 06 '22 at 14:32
  • @Quentin thank you I'll have to read about it and try to apply your solution cause I have no idea how to do that – Dendenzilla Oct 06 '22 at 14:53
  • Does this answer your question? [Replace a value if null or undefined in JavaScript](https://stackoverflow.com/questions/1011317/replace-a-value-if-null-or-undefined-in-javascript) – Yogi Oct 06 '22 at 15:29
  • So I tried to add 'var newValue = products.row[0] || ''; ' right after products = data["rows"].map((row) => row["c"].reduce( (product, { v: value }, index) => ({ ...product, [data["cols"][index]["label"]]: value }), {} ) ); But it doesn't work, I'll have to take some time to actually read documentation about it, thank you for your help though – Dendenzilla Oct 06 '22 at 16:14
  • @Yogi This really seems like this is the correct answer but I don't understand javascript well enough to implement it, any chance you could take a look at my codepen and help me ? https://codepen.io/Dendenzilla/pen/jOxvMZQ? – Dendenzilla Oct 07 '22 at 08:28
  • Were the rows deleted from the sheet? The CodePen stopped working because there is no row data to process. Anyway, the values I saw were strings, booleans, and numbers. So we will need to test for null and undefined and set the value to empty string when true. The fix is simple, but would be better if the CodePen worked to try with real data. – Yogi Oct 07 '22 at 09:54
  • @Yogi Sorry, I created a copy of my sheet ( https://codepen.io/Dendenzilla/pen/bGMvQJz ) so you can look at it while I do tests on another. Thank you for helping me. – Dendenzilla Oct 07 '22 at 15:03
  • Yes, the sheet is working again and I've posted my suggestions as an answer. This should be enough to start you in the right direction. I've also listed some other suggestions on how you might improve the code if you wish. – Yogi Oct 08 '22 at 00:16

1 Answers1

1

OP asked me for assistance in a comment.

Problem Defined

OP's code queries a Google Sheet for table data which is returned as JSONP. This would usually be processed using the Google Sheets API, but in this case we have custom code doing it. This code parses the JSONP into plain JSON, converts it to a sheet object, and finally transforms it into an array of product items that is used to build the GUI. This works, but sometimes a product item return null values, which causes an error.

The Solution

The values are usually strings, but Google Sheets also has number, Boolean, and other data types. So we need to set null and undefined, but not zero and false, to an empty string. And the test can be done using value === null || value === undefined or the shorthand version value == null. See this SO question for details.

And we add this test to the transformation so that no product items have null values. See the example snippet.

Other Problems

Though not part of the question, the code could be greatly simplified and improved.

The code is very monolithic and difficult to follow. Needs to be broken up into smaller chunks.

The code uses property names that are incompatible with object dot notation. The bracket notation results in a lot of extra code.

The code creates large chunks of HTML which it appends to the page and then backfills with data. Template Literals would eliminate much of this extra code.

The page uses entirely custom css rather than one of the popular libraries like Bootstrap. And this makes it harder for others to understand and maintain.

Code Snippet

The section of the code marked ETL shows how to convert the property keys to camelCase for dot notation and convert null values to empty strings. Yet, this changes the product item schema as shown in the example data. The GUI code will need t be reworked to use the new property names, but this will also eliminate the need for much of that code.

  // Query Google Sheet for data
  // The query returns JSONP which must be converted to a JSON string and then a table object
  
  const query = "https://docs.google.com/spreadsheets/d/1tlqyTx48A-4CfgggWbpTbGd8SXCpCSO4UMV7Q0_ogJg/gviz/tq?&sheet=users&tq=Select%20A,B,C,D,E,F,G,H,I,J%20WHERE%20C=True";

  const json = await fetch( query )
    .then(response => response.text())
    .then(text => text.slice(47,-2))
    .catch(error => { throw error; });
  
    const data = JSON.parse(json);
    
  // ETL - The table columns and rows are transformed into an array of product items

    const products = data.table.rows.map(row => 
     data.table.cols.reduce((product, col, index) =>  {
         product[toCamelCase(col.label)] = getValue( row.c[index].v );
       return product;
     }, {} )
  );
  
// Helpers

// see: https://stackoverflow.com/q/5515310/943435
// optionally add other conversions and validations here
function getValue(value) { 
    return value === null || value === undefined ? "" : value;
}

// see: https://stackoverflow.com/a/2970667/943435
// used to create camelCase keys that are compatible with JavaScript dot notation
function toCamelCase(str) {
  return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function(match, index) {
    if (+match === 0) return ""; // or if (/\s+/.test(match)) for white spaces
    return index === 0 ? match.toLowerCase() : match.toUpperCase();
  });
}

Example Data Output

[
  {
    "title": "Neutrik XLR Female",
    "category": "Connectors",
    "productOnSalePage": true,
    "oldPrice": "9.24",
    "newPrice": "3.00",
    "units": "per unit",
    "subTitle": "5 pole chassis connector",
    "description": "Black housing & Gold contacts",
    "imageLink": "https://www.belram.be/wp-content/uploads/2022/10/nc5md-l-b-1.jpg",
    "productLink": "https://www.belram.be/product/connectors/audio/xlr/neutrik-nc5md-l-b-1-5-pole-male-d-size/"
  },
... more elements
]
Yogi
  • 6,241
  • 3
  • 24
  • 30
  • 1
    Thank you so so much for taking the time to share all this knowledge ! You are an amazing help ! I still have a lot to learn and resolving bugs in my code with the help of your answer will be a big step forward for me ! – Dendenzilla Oct 08 '22 at 09:55