Home > OS >  Chrome Extension gives two errors: Uncaught TypeError and Unchecked runtime.lastError
Chrome Extension gives two errors: Uncaught TypeError and Unchecked runtime.lastError

Time:02-26

I am facing two errors on Chrome extension that I am building:

Error 1:

Uncaught TypeError: Cannot set properties of null (setting 'onclick') Context _generated_background_page.html Stack Trace popup.js:3 (anonymous function)

Error 2:

Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist. Context _generated_background_page.html Stack Trace _generated_background_page.html:0 (anonymous function)

I have already checked the questions on this site that address these two errors and I tried the solutions provided in them, but I am still facing the two errors.

My original code:-

popup.js (tried changing from onclick to onClicked for error 1, tried putting this code in window.onload for error 2)

let populateBtn = document.getElementById('populateBtn');
let textArea = document.getElementById('productList');
populateBtn.onclick = function(element) {
    let color = element.target.value;
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        if(!textArea.value) 
        {
            chrome.tabs.executeScript(
                tabs[0].id,
                {code: 'alert("Please, populate the order list!");'});
            return;
        }
        chrome.tabs.sendMessage(tabs[0].id, {data: textArea.value.replace(/\t/g,'').split("\n")}, function(response) {
        });
    });
};

background.html (tried putting <script> after </body> tag for error 1)

<body>
    <p>Gina's Bakery Bulk Order</p>
    <textarea id="productList"></textarea>
    <button id="populateBtn">Create Order</button>
    <script src="popup.js"></script>
</body>

app.js (tried chrome.runtime.connect for error 2)

chrome.runtime.onInstalled.addListener(function() {
});

inject.js (tried chrome.runtime.onConnect.addListener for error 2)

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
    let failed = [];
    request.data.forEach(element => { // itterate over all products
        if(element.includes('-')){
            let data = element.split('-');
            let quantity = data[0].toLowerCase().replace("gb", "").trim();
            let ID = data[1].trim();
            let elementName = 'pid_'   ID.replace(".", "_");
            if(document.getElementsByName(elementName).length > 0) 
                document.getElementsByName(elementName)[0].value = quantity;
            else        
                failed.push("<td>GB-"  ID  "</td><td>"   quantity   "</td>");
        }
     });   
    if(failed.length > 0){
        //alert("Order unsuccessful! One or more products are not ordered: "   failed.join(", "));
        let modal = document.createElement("div");
        modal.setAttribute("id", "failedOrderModal");
        modal.setAttribute("style", "position:fixed;width:250px;left:50%;top:100px;background-color:#fff;border-radius:10px;padding:10px;z-index:10000;color:#000;border: 1px solid red;text-align:center;");
        let head = document.createElement("h2");
        head.innerText = "Order unsuccessful! One or more products were not found!";
        modal.appendChild(head);
        let table = document.createElement("table");
        let tbody = document.createElement("tbody");
        table.appendChild(tbody);
        let tr = document.createElement("tr");
        tr.innerHTML = "<td>ITEM</td><td>QTY</td>";
        tbody.appendChild(tr);
        failed.forEach(failedItem => {
            tr = document.createElement("tr");
            tr.innerHTML = failedItem;
            tbody.appendChild(tr);
        });
        modal.appendChild(table);
        let closeBtn = document.createElement("button");
        closeBtn.setAttribute("type", "button");
        closeBtn.innerText = "Close";
        closeBtn.onclick = function(){
            document.getElementById("failedOrderModal").remove();
        }
        modal.appendChild(closeBtn);
        document.body.appendChild(modal);
    }
    else
    {
        alert("All products were successfuly populated!");  
    }   
    sendResponse({result: "ok"})
    return true;
});

manifest.json

{
    "name": "Gina's Bakery Order",
    "version": "1.0",
    "description": "Helps automate orders from ginas-bakery.com.au",
    "permissions": ["activeTab", "declarativeContent", "storage"],
    "background": {
        "scripts": ["app.js", "popup.js"],
        "persistent": false
      },
    "icons": {
        "16": "images/ginas-bakery_16.png",
        "32": "images/ginas-bakery_32.png",
        "48": "images/ginas-bakery_48.png",
        "128": "images/ginas-bakery_128.png"
      },
    "browser_action": {
        "default_popup": "background.html"
      },
      "content_scripts": [
        {
            "matches": ["*://www.ginas-bakery.com.au/order/"],
            "js": ["inject.js"]
        }
    ],
    "manifest_version": 2
}

None of the above mentioned solutions worked.

CodePudding user response:

The background script page is an invisible hidden page, so running visible scripts like app.js or popup.js there is meaningless. Remove background section from manifest.json and rename your background.html to popup.html both on the disk and in manifest.json.

manifest.json:

{
  "name": "Gina's Bakery Order",
  "version": "1.0",
  "permissions": ["activeTab", "declarativeContent", "storage"],
  "browser_action": {"default_popup": "popup.html"},
  "manifest_version": 2
}

Content scripts run only when the page loads, so if you just reloaded or installed/updated the extension without reloading the tab, the content scripts won't run there.

Although you can inject them explicitly, it's much better to switch to programmatic injection on demand (use executeScript instead of content_scripts) because you can do it without requiring any host permissions when installing the extension.

popup.js:

const textArea = document.getElementById('productList');
const btn = document.getElementById('populateBtn');
btn.onclick = () => {
  const data = textArea.value.replace(/\t/g, '').split('\n');
  chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
    chrome.tabs.sendMessage(tab.id, {data}, () => {
      if (chrome.runtime.lastError) {
        chrome.tabs.executeScript({file: 'inject.js'}, () => {
          chrome.tabs.sendMessage(tab.id, {data});
        });
      }
    });
  });
};

Since you're not using the response in sendMessage, don't send it in the first place, i.e. remove sendResponse({result: "ok"}); return true; from inject.js.

  • Related