javascriptarraysutm

Uncaught Type Error for First Object in Multidimensional Array, but Can Still Print to Console


I'm sure there's a simple solution to this, so I feel like a buffoon asking for help. I'm just stuck.

My design intent is to capture UTM data and store it in local storage for later use in a web form (posting to salesforce). I'm trying to loop over a multidimensional array and get the values, namely a parameter name (the UTM string name to parse from the URL) and an id (to get the field in the form later).

I loop over the array by the length using for - and it correctly collects the ID but not the name, which throws the following error: (index):411 Uncaught TypeError: Cannot read properties of undefined (reading 'paramName') at addUtm ((index):411:42).

What's bizarre is if use the console, I can grab the value with the index.

Full script below:

<script>


function getParam(p) {
      var match = RegExp("[?&]" + p + "=([^&]*)").exec(window.location.search);
      return match && decodeURIComponent(match[1].replace(/\+/g, " "));
}

function getExpiryRecord(value) {
  var expiryPeriod = 90 * 24 * 60 * 60 * 1000; // 90 day expiry in milliseconds

  var expiryDate = new Date().getTime() + expiryPeriod;
  return {
    value: value,
    expiryDate: expiryDate
  };
}

var paramsJSON = [
   {
       paramName: "utm_source",
       id: "00N6g00000NiGFS"
   },   
   {
       paramName: "utm_medium",
       id: "00N6g00000NiGFQ"
   },   
   {
       paramName: "utm_campaign",
       id: "00N6g00000NiGFN"
   }
]

console.log(paramsJSON)
function addUtm() {
  for (i=0; paramsJSON.length; i++){
    
    var utmName = getParam(paramsJSON[i].paramName); // OFFENDING LINE!
    console.log('UTM name: ' + utmName);
    var utmId = paramsJSON[i].id;
    console.log('UTM id: '+ utmId);
    var utmRecord = null;
    var currUtmFormField;

    var gclsrcParam = getParam('gclsrc');
    var isGclsrcValid = !gclsrcParam || gclsrcParam.indexOf('aw') !== -1;

    if (document.getElementById(utmId)) {
      currUtmFormField = document.getElementById(utmId);
    }
 
    if (utmName && isGclsrcValid) {
      utmRecord = getExpiryRecord(utmName);
      console.log(utmRecord)
      localStorage.setItem(utmName, JSON.stringify(utmRecord));
    }

    var utm = utmRecord || JSON.parse(localStorage.getItem(utmName));
    console.log('UTM: ' + utm);
    var isUtmValid = utm && new Date().getTime() < utm.expiryDate;

    if (currUtmFormField && isUtmValid) {
      currUtmFormField.value = utm.value;
      console.log('UTM value: '+ utm.value);
    }
  }
}

window.addEventListener('load', addUtm);

 </script>

I put a comment in the script for the offending line:

var utmName = getParam(paramsJSON[i].paramName); // OFFENDING LINE! . I'm sure I'm missing something obvious but any help would be greatly appreciated. I've searched for out-of-the-box solutions for this but come up a bit short, as I'm inexperienced with Javascript. If it makes a difference (not sure it does), I'm running this in WordPress. Below is what I see in the console.

enter image description here

What is causing paramName to return null?


Solution

  • Here is a working version

    I had to mock the URL and the localStorage parts. You can change

    const loc = "https://bla.com/page?utm_source=source&utm_medium=medium&utm_campaign=campaign"; 
    const url = new URL(loc || window.location.href)
    

    to

    const url = new URL(window.location.href)
    

    when on your server, change

    var lsUtm = "{}"; // localStorage.getItem(utmName);
    

    to

    var lsUtm = localStorage.getItem(utmName); 
    

    and uncomment

    // localStorage.setItem(utmName, JSON.stringify(utmRecord));
    

    const loc = "https://bla.com/page?utm_source=source&utm_medium=medium&utm_campaign=campaign"; 
    const url = new URL(loc || window.location.href)
    function getParam(p) {
      return url.searchParams.get(p)
    }
    
    function getExpiryRecord(value) {
      var expiryPeriod = 90 * 24 * 60 * 60 * 1000; // 90 day expiry in milliseconds
    
      var expiryDate = new Date().getTime() + expiryPeriod;
      console.log("ex", {
        value: value,
        expiryDate: expiryDate
      })
      return {
        value: value,
        expiryDate: expiryDate
      };
    }
    
    var paramsJSON = [{
        paramName: "utm_source",
        id: "00N6g00000NiGFS"
      },
      {
        paramName: "utm_medium",
        id: "00N6g00000NiGFQ"
      },
      {
        paramName: "utm_campaign",
        id: "00N6g00000NiGFN"
      }
    ]
    
    function addUtm() {
      for (let i = 0; i < paramsJSON.length; i++) {
        console.log("pname",paramsJSON[i].paramName)
        var utmName = getParam(paramsJSON[i].paramName); 
        var utmId = paramsJSON[i].id;
        console.log('UTM name:', utmName,'UTM id:', utmId);
        var utmRecord = null;
        var currUtmFormField = document.getElementById(utmId);
    
        var gclsrcParam = getParam('gclsrc');
        var isGclsrcValid = !gclsrcParam || gclsrcParam.indexOf('aw') !== -1;
    
        if (utmName && isGclsrcValid) {
          utmRecord = getExpiryRecord(utmName);
          console.log(utmRecord)
         // localStorage.setItem(utmName, JSON.stringify(utmRecord));
         console.log("LS",utmName, JSON.stringify(utmRecord)); // SO does not like localStorage
        }
        var lsUtm = "{}"; // localStorage.getItem(utmName)
        var utm = utmRecord || JSON.parse(lsUtm); 
        console.log('UTM: ', utm);
        var isUtmValid = utm && new Date().getTime() < utm.expiryDate;
    console.log(isUtmValid)
        if (currUtmFormField && isUtmValid) {
          currUtmFormField.value = utm.value;
          console.log('UTM value: ' + utm.value);
        }
      }
    }
    
    window.addEventListener('load', addUtm);
    <input id="00N6g00000NiGFS" value="">
    <input id="00N6g00000NiGFQ" value="">
    <input id="00N6g00000NiGFN" value="">