Issue encountered when retrieving the ID of the active tab in a Google Chrome extension using Manifest V3: Uncaught TypeError - Unable to access properties of undefined while trying to read 'id'

Currently, I am facing a persistent error while creating a Google Chrome extension in Manifest V3:

Error: Uncaught TypeError: Cannot read properties of undefined (reading 'id')

Despite extensive research, I keep running into different errors with every solution I attempt. As I am relatively new to Javascript, I suspect this issue might be due to a beginner mistake on my part. Here is the code I have so far:

index.html

<html>
    <head>
        <link rel="stylesheet" href="styles.css">
        <link rel="chart" href="Chart/setup.js">

        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap">
        <link rel="stylesheet"
            href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="70372231343042405e5e4448">[email protected]</a>,100..700,0..1,-50..200" />
        <script type="js/main.js" src="https://www.gstatic.com/charts/loader.js"></script>
    </head>
    <body>
        <div id="donutchart" style="width: 900px; height: 500px;"></div>
        <h4>GOOGLE CALENDAR</h4>
        <h5>Time Tracker</h5>
        <hr></hr>
    </body>
</html>

manifest.json

{
    "manifest_version": 3,
    "name": "Google Calendar Time Tracker",
    "description": "Base Level Extension",
    "version": "1.0",
    "action": {
        "default_popup": "index.html",
        "default_icon": "hello_extensions.png"
    },
    "background": {
        "service_worker": "js/main.js"
    },
    "permissions": [
        "scripting",
        "tabs",
        "https://*/*",
        "http://*/*"
    ]
}

main.js

function getTabId() {
    let tabs = chrome.tabs.query({currentWindow: true, active : true});
    return tabs[0].tabId;
}

chrome.scripting.executeScript({
    target: {tabId: getTabId()},
    files : ["chart.js"],
})
.then(() => console.log("Script injected"));

chart.js

google.charts.load("current", { packages: ["corechart"] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
    var data = google.visualization.arrayToDataTable([
        ['Task', 'Hours per Day'],
        ['Work', 11],
        ['Eat', 2],
        ['Commute', 2],
        ['Watch TV', 2],
        ['Sleep', 7]
    ]);

    var options = {
        title: 'My Daily Activities',
        pieHole: 0.4,
    };

    var chart = new google.visualization.PieChart(document.getElementById('donutchart'));
    chart.draw(data, options);
}

If you have any suggestions for improvements or solutions, kindly share them as I aim to successfully import and display a pi chart using the Google Charts library in my extension.

I've attempted changing 'id' to 'tabId' and experimented with promises, yet none of these approaches worked. The variable 'id'/'tabId' appears unrecognized despite online guides utilizing it. What could I possibly be missing?

Answer №1

The key issue at hand is the unnecessary usage of main.js and executeScript, as they are meant to inject scripts into a web page. However, in the case of the action popup, which is a separate entity with its own URL like chrome-extension://id/popup.html, there is no need for such injection.

To load scripts in the popup, simply include them using script tags with the src attribute:

<script src="chart.js"></script>
<script src="popup.js" defer></script>
  • Exclude background from manifest.json.
  • Delete the main.js file.
  • Create popup.js to manage clicks within the popup.

Additional issues to address:

  • Relocate site patterns from permissions in manifest.json to host_permissions.
  • Eliminate the
    https://www.gstatic.com/charts/loader.js
    script due to limitations in ManifestV3 extensions regarding external script execution. If this functionality is still required, it must be implemented within a sandboxed page or frame.

Problems present in the now obsolete main.js:

  • A tab object obtained through chrome.tabs.query does not possess a tabId property; only an id property.
  • The getTabId function returns a Promise, hence it cannot be directly used as a parameter for executeScript. It needs to be awaited or utilized within a then block.
  • The background script triggers immediately upon extension installation, whether on the chrome://extensions tab for unpacked extensions or on the web store page – both of which prohibit script injection. Generally, if the background script does not subscribe to chrome events like chrome.tabs.onUpdated or chrome.runtime.onMessage, the background script may be dispensable.
  • Distinct scripts should be employed for the background script, popup script, and content script since these contexts differ considerably.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to utilize a single AngularJS 1.5 component multiple times within a single view?

While working on a project using AngularJS 1.5's new components, I encountered an issue with widget isolation. It seems that when I use the same widget multiple times, they end up sharing their controller or scope. I was under the impression that comp ...

Passing an object in Vue.js during a redirect

i currently have two components named projectListComponent and projectSingleComponent. I want to pass an object from component 1 to component 2 during redirection. Here is my code: projectListComponent.vue <template> <div class="row justify ...

Creating various layouts in Ember.js allows for flexibility and customization in

Currently working on an emberjs project and aiming to incorporate two distinct layouts - one for the main application template and another for specific templates. I prefer not to have all views rendered within the application template, similar to how you ...

Make an oblong shape from a circle by applying a transform in CSS or utilizing another efficient method

I am attempting to transform a circle into an obround using transform: scaleX(2), but it ends up becoming an ellipse instead. Increasing the width of the obround causes a jittery transition in my application. Is there a more efficient way to achieve this t ...

The JavaScript function prints the variable using `console.log(var)`, however, it does not assign `var2` to

I've been following a tutorial on implementing push notifications in VueJS from this link. After running the register function on the created hook, I encountered an issue: register() { if ("serviceWorker" in navigator && "PushManager" in window ...

Updating View in Angular 2 ngClass Issue

I'm encountering some challenges with updating my view using ngClass despite the back end updating correctly. Below is my controller: @Component({ selector: 'show-hide-table', template: ' <table> <thead> ...

Integrating new components into JSON data

I started by creating a JSON document in my code using the following syntax: let jsonData = []; To populate this document, I utilized the '.push()' method to add elements in this manner: jsonData.push({type: "example", value: "123"}); Eventua ...

The functionality of the combobox in Vuetify differs from that of an input field

I have implemented Vuetify and am using its combobox component for search functionality on my website. However, I have noticed that the text value in the combobox only gets added to the watcher when the mouse exits the field. This behavior is not ideal f ...

Hover over to reveal the text

Would it be feasible to implement JavaScript so that when hovering over or clicking on a word on a webpage, the word can be captured in a variable? I am interested in creating a Firefox extension with this functionality. ...

Ways to display a default view in React

I am working on a React website that has three different routes. My goal is to have the first route, named Home, automatically displayed when a user lands on the site. Below is the code snippet from my App.js: <Router> <Navigation /> <Sw ...

Why is it that every time I install an npm package, it triggers a re-installation of all

Whenever I attempt to install a new package using npm, I face a frustrating problem where it also starts to install all of my other packages, leading to potential breakage and the need to reinstall my node modules. I am puzzled by this behavior and unsure ...

What is the origin of this MouseEvent attribute?

In my jsfiddle project, there is a white square that can be moved around by the mouse. When the mouse button is released, it displays the x and y coordinates of the square. To see the project in action, visit: http://jsfiddle.net/35z4J/115/ One part of t ...

cookie-parser: blank cookie data

I'm having trouble accessing browser cookies upon form submission. Even though there are several cookies set in my browser, the cookie-parser module returns an empty cookie object. Here is the code snippet I am using: const express = require("express ...

Looking to transform a nested JSON structure into a visually appealing HTML table with merged rows?

My JSON structure appears as follows: $scope.data = [ { "type":"Internal", "count": 3, "library" : [ { "type":"Library 123", "count": 2, "version" ...

How can I stop the li item from swiping right in JQuery mobile?

I've been implementing this code from https://github.com/ksloan/jquery-mobile-swipe-list and I've made some modifications to it. It's been working well for me so far. However, the code includes two buttons - one on the right and one on the l ...

Obtaining the complete JSON array in string format

I am currently using Fine Uploader to pass parameters in this way callbacks: { onSubmit: function(id, fileName) { this.setParams({ a: 'adm', b: '126', c: { fileID: id, ...

Having issues transferring values from one page to another. Any suggestions to make it work correctly?

I currently have two pages within my website, one is called details.page and the other is maps.page. In the details page, I have set up a search input as shown below : <form method="get" id="form-search" data-ajax="true" action="maps.page"> ...

Seeking clarity on which specific section of this Node.js code is overseeing the routing of my POST request to the mongoose/mongodb server

Hey everyone, I'm diving into the world of programming and currently enrolled in a Udemy course on web development. As I progress through the lessons, there's one aspect of the code that's leaving me confused. I've got my MongoDB databa ...

How can CKEditor ensure that there is a paragraph tag within a div element?

Working on my current CMS, I have the need to include some custom HTML (which is functioning as expected): var element = CKEDITOR.dom.element.createFromHtml("<div class='sidebar'>Edit Sidebar Text</div>"); The issue arises when atte ...

Unspecified binding in knockout.js

As a newcomer to JS app development, I am currently focused on studying existing code and attempting to replicate it while playing around with variable names to test my understanding. I have been working on this JS quiz code built with KO.js... Here is my ...