78

The message from popup.js is being posted twice to background.js, but I get absolutely nothing from background.js.

background.js

function login(username,password){

    console.log(username);
var xhr = new XMLHttpRequest();

xhr.open("POST", "http://localhost:3000/login/", true);
xhr.setRequestHeader('Content-type','application/json; charset=utf-8');
data = {"username":username,"password":password};
console.log(JSON.stringify(data));
xhr.send(JSON.stringify(data));
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // JSON.parse does not evaluate the attacker's scripts.
    var resp = JSON.parse(xhr.responseText);
    console.log(resp);
    var lStorage = localStorage;
    localStorage.setItem("username",resp["username"]);
    localStorage.setItem("apiKey",resp["apiKey"]);
    localStorage.setItem("password",resp["password"]);
    console.log(localStorage.getItem("username"));



  }
};


}


chrome.extension.onRequest.addListener(
    function(request, sender, sendResponse){
        console.log("hello");
        if(request.msg == "login") {
            //alert(request.password);
            login(request.username,request.password);}
    }
);

  chrome.extension.onConnect.addListener(function(port) {
  console.log("Connected .....");
  port.onMessage.addListener(function(msg) {
        console.log("message recieved "+ msg);
        port.postMessage("Hi Popup.js");
  });
});

popup.js:

function login(){
alert(document.login.username.value);
chrome.extension.sendRequest({ msg: "login",username:document.login.username.value,password:document.login.password.value});
document.getElementById('openBackgroundWindow').visbility = "hidden";

}

$(document).ready(function (){

checkUserAuth();
console.log("Inside");
$("#openBackgroundWindow").click(login);

});


function checkUserAuth(){
console.log(localStorage.getItem("apiKey"));
if(localStorage.getItem("apiKey") != null)
    {
        $("#openBackgroundWindow").visbility ="hidden";
    }
}


var port = chrome.extension.connect({name: "Sample Communication"});
port.postMessage("Hi BackGround");
port.onMessage.addListener(function(msg) {
        console.log("message recieved"+ msg);
});
Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
Hick
  • 35,524
  • 46
  • 151
  • 243

5 Answers5

139

Method - A :
Using Long Lived Connections you can communicate from background.js to popup.js of extension page for any activities( Here i have included popup.html and only initiated sample communication from popup.js as a sample)

background.js

 chrome.extension.onConnect.addListener(function(port) {
      console.log("Connected .....");
      port.onMessage.addListener(function(msg) {
           console.log("message recieved" + msg);
           port.postMessage("Hi Popup.js");
      });
 })

popup.js

 var port = chrome.extension.connect({
      name: "Sample Communication"
 });
 port.postMessage("Hi BackGround");
 port.onMessage.addListener(function(msg) {
      console.log("message recieved" + msg);
 });

Method - B :
Direct Manipulation of DOM* if your end result is modification of DOM, you can achieve with this

popup.html

<html>
    <head>
        <script src="popup.js"></script>
    </head>
    <body>
        <div id="x" value="m">Some thing</div>
    </body>
</html>

background.js

var views = chrome.extension.getViews({
    type: "popup"
});
for (var i = 0; i < views.length; i++) {
    views[i].document.getElementById('x').innerHTML = "My Custom Value";
}

Method - C :

Using Long Lived Connections you can communicate from background.js to popup.js of extension page for any activities( Here i have not included popup.html and initiated sample communication from background.js;

background.js

chrome.browserAction.onClicked.addListener(function(tab) {

    var port = chrome.extension.connect({
        name: "Sample Communication"
    });
    port.postMessage("Hi BackGround");
    port.onMessage.addListener(function(msg) {
        console.log("message recieved" + msg);
    });

});

I have changed your code and made it running after eliminating some stuff and making it a simple version. Add your code for AJAX requests and HTML DOM on this skeleton( Make sure you add <script> tag in head section and put chrome.extension.onConnect.addListener out of (xhr.readyState == 4) code;)

popup.html

<html >
    <head>
        <script src="popup.js"></script>
    </head>
    <body></body>
</html>

manifest.json

{
    "name": "Demo",
    "version": "1.0",
    "manifest_version": 2,
    "description": "This is a demo",
    "browser_action": {
        "default_popup": "popup.html"
    },
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": ["<all_urls>",
        "storage",
        "tabs"
    ]
}

background.js

chrome.extension.onConnect.addListener(function(port) {
    console.log("Connected .....");
    port.onMessage.addListener(function(msg) {
        console.log("message recieved " + msg);
        port.postMessage("Hi Popup.js");
    });
});

popup.js

var port = chrome.extension.connect({
    name: "Sample Communication"
});
port.postMessage("Hi BackGround");
port.onMessage.addListener(function(msg) {
    console.log("message recieved" + msg);
});
Morteza Tourani
  • 3,506
  • 5
  • 41
  • 48
Sudarshan
  • 18,140
  • 7
  • 53
  • 61
  • 1
    I am able to communicate with the background page from popup.js but not the other way around. – Hick Nov 25 '12 at 12:18
  • 1
    @Puck : The code port.postMessage("Hi Popup.js"); in background.js is doing the communication from background.js to popup.js – Sudarshan Nov 25 '12 at 15:53
  • Yes. I did that but still nothing on the console saying Hi Popup.js – Hick Nov 25 '12 at 16:14
  • @Puck: It is perfectly working here: If you are using `chrome.browserAction.onClicked.addListener(` you can not have popup.html here, try using the code with a vaild manifest.json; it will work, if not update your problem with all content you are using for test, will pick it from there – Sudarshan Nov 25 '12 at 16:17
  • have edited the question with popup.js, background.js and manifest.json – Hick Nov 25 '12 at 16:29
  • @Puck : add popup.html also – Sudarshan Nov 25 '12 at 16:46
  • Check the new edit. Still not working. Rather message from popup.js is being posted twice. Thank you for your help till now. – Hick Nov 25 '12 at 19:04
  • 10
    I wasn't even inspecting popup.js. Horrible! Pardon my stupidity. – Hick Nov 25 '12 at 23:17
  • What would popup.js look like in method C? I noticed this code is 4 years old and might not work anymore given changes in the APIs. Can someone confirm or deny? – Rudolf Real Oct 16 '16 at 09:26
  • 1
    This doesn't work. If you want to initiate communication from the background page, this will not work. Your code clearly shows that the background is dependent on the popup.js script first making the connection. Your code assumes that the user has already clicked on the popup button. If the popup.js is not running, the background script will not communicate with it. – Johann Jan 15 '17 at 22:18
22

This can be used in 2 way communication. Same code goes in both the files.

popup.js & background.js

//for sending a message
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {

});

//for listening any message which comes from runtime
chrome.runtime.onMessage.addListener(messageReceived);

function messageReceived(msg) {
   // Do your work here
}

Ref: https://developer.chrome.com/extensions/runtime#method-sendMessage

Kishan Rajdev
  • 1,919
  • 3
  • 18
  • 24
4

Full Duplex Communication

Call background.js methods asynchronously from popup.js and get response back:

Popup.js:

// wrapper method 
function getContent() {
    callEventPageMethod('getContent', 'some parameter', function (response) {
        doSomethingWith(response);
    });

}

//generic method
function callEventPageMethod(method, data, callback) {
    chrome.runtime.sendMessage({ method: method, data: data }, function (response) {
        if(typeof callback === "function") callback(response);
    });
}

Background.js/eventPage.js:

chrome.runtime.onMessage.addListener(callback);
function callback(obj, sender, sendResponse) {
    if (obj) {
        if (obj.method == 'getContent') {
            getContent(sendResponse);
        } else if (obj.method == 'othermethod') {

        }
    }
    return true; // remove this line to make the call sync!
}


//some async method
function getContent(sendResponse) {
    chrome.storage.local.get(["mydata"], function (obj) {
        var mydata = $.trim(obj["mydata"]);
        sendResponse(mydata);
    });
}

If need to call popup.js methods from background.js then swap the above code in files.


Method 2: You can load the reference of background page in a variable and access all methods.

var bgPage = chrome.extension.getBackgroundPage();
 var response =  bgPage.someMethodInBGPage();
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
1

What I understand from answers is: The problem is that if bg.js is trying to communicate with Popup.js, if it is not active it will return error that "no suitable endpoint".

Therefore one can do either of the following.

  1. STORAGE - Save the shared message temporarily using chrome Storage
  2. DOM MANIPULATION - Save the message permanently in DOM itself (if wanted to manipulate DOM) as end result.
  3. LONG LIVE CONNECTION - Create a long term connection with popup. (using chrome onConnect method)
  4. FULL DUPLEX - Use handshake method by double function call from each side and using response callback to pass the answer.
1

Manifest Version 3

Example for sending message from popup.js to background.js:

manifest.json:

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "./popup.html"
  },
  "background": {
    "service_worker": "./background.js"
  }
}

popup.html:

<html>
  <head>
    <title>Title</title>
  </head>
  <body>
    <button id="btn">Trigger BG</button>
    <script src="popup.js"></script>
  </body>
</html>

popup.js:

document.getElementById('btn').addEventListener('click', () => {
  // how we send data:
  chrome.runtime.sendMessage({ greeting: 'hello' });
});

background.js:

// how we receive data:
chrome.runtime.onMessage.addListener((msg, sender, res) => {
  console.log(msg);
});

You can swap the content of popup and background js files to send data from background.js to popup.js

Docs: Message passing, chrome.runtime

sha'an
  • 1,032
  • 1
  • 11
  • 24
  • I couldn't get them to work switched. Can you include an example where you're sending a message from background.js to popup.js? thanks – A4_TS Aug 16 '23 at 19:19