So, I have an popup.html in popup.html. If you enter data, popup.js sends data to content.js and it already changes something on the page. But after the update, the changes on the page disappear. How can one make it so that they remain and change only if new data were entered into the input?

popup.html и popup.js

 var input = document.querySelector('#inp'); var text = document.querySelector("#text"); var button = document.querySelector("#btn"); btn.addEventListener('click', function() { var inp = input.value; chrome.tabs.query({active: true, currentWindow: true}, function(foundTabs) { const activeTab = foundTabs[0]; chrome.tabs.sendMessage(activeTab.id, {text: inp});//отправка значения инпута }) }); 
 <input type="text" id="inp"> <button id="btn">Send</button> 

content.js :

 chrome.runtime.onMessage.addListener(function(request) { const txt = request.text; //пришло значение инпута chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { //вставка в html }); }); 

And I enter some number in the input, press a button, but I get an error in the console (see screen)

enter image description here

  • Save changes to the database and / or store on the server. - NetL
  • Use localStorage - Alexander

2 answers 2

Suppose that you use a similar solution to send data from a popup to a content-script .

In this case, it can be slightly modified. Below is the self-contained extension code.

For tracking tab updates and storing the data structure, I suggest adding a background script to the extension. Then everything becomes simple enough:

manifest.json

 { "manifest_version": 2, "name": "Test", "version": "1.0", "description": "", "browser_action": { "default_popup": "popup.html" }, "content_scripts": [ { "matches": [ "<all_urls>" ], "js": [ "content-script.js" ], "run_at": "document_end" } ], "background": { "scripts": ["background.js"] } } 

popup.html

 <input type="text" id="data"> <button id="go">Send</button> <script src="popup.js"></script> 

popup.js

 const btn = document.querySelector('#go'); const input = document.querySelector('#data'); btn.addEventListener('click', function() { const text = input.value; chrome.tabs.query({active: true, currentWindow: true}, function(foundTabs) { const activeTab = foundTabs[0]; // Отправка текста в content-script chrome.tabs.sendMessage(activeTab.id, {text: text}); // Отправка данных в background-скрипт для сохранения chrome.runtime.sendMessage({ tabId: activeTab.id, text: text }); }) }); 

content-script.js

 const input = document.querySelector('#lst-ib'); // для примера используется поле ввода Google.com chrome.runtime.onMessage.addListener(function(request) { input.value = request.text; }); 

background.js

 // Структура вида "id таба -> какой текст вставить" const observedTabs = new Map(); // Слушаем сообщения из popup.js chrome.runtime.onMessage.addListener(function(request) { const tabId = request.tabId; const text = request.text; // Сохраняет text для таба по id observedTabs.set(tabId, text); }); // Отслеживаем изменения в табах chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) { // Если id таба находится в списке отслеживаемых и вкладка завершила загрузку... if(observedTabs.has(tabId) && changeInfo.status === 'complete') { const text = observedTabs.get(tabId); // ..то отправляем в content-script сообщение с текстом (такое же как и в popup) chrome.tabs.sendMessage(tabId, {text: text}); } }); // Удаляем таб из память в случае, если вкладка закрылась chrome.tabs.onRemoved.addListener(function(tabId) { observedTabs.delete(tabId); }); 

Note that the data in observedTabs exists before the extension or browser is reloaded. In case you need to have permanent access to the saved data, you can use localStorage or chrome.storage.local .

  • Thanks, but could you tell me how to do this so that it would work with several inputs? That is, is it possible in the Map to record, for example, in addition to Text, something else, with which id and how then to send it? - Maxim Buyakov
  • @MaximBuyakov, you can put a structure of any complexity in Map : for example { id: [ {selector1: text1}, {selector2: text2} ]} - Deliaz
  • observedTabs.set({tabId : [{selector1: text1}, {selector2: text2} ]); Is the record in the Map supposed to be like this? - Maxim Buyakov
  • @MaximBuyakov, no, this is just an abstract entry. Look at an example of using Map : the first argument is the ID of the tab, and the second is an array with objects. The structure is arbitrary, but probably should contain a selector for the element and text to insert. - Deliaz

Example:

 var input = document.querySelector('#inp'); var text = document.querySelector("#text"); var button = document.querySelector("#btn"); btn.addEventListener('click', function() { var inp = input.value; text.innerHTML = inp; localStorage.setItem('dataForMyInput', inp); }); window.onload = function() { text.innerHTML = localStorage.getItem('dataForMyInput') || ''; } 
  • Tell me, how can I do this if the values ​​of these inputs are sent first to another js file and there the script places the values ​​in html . Added a bit of code to the question - Maxim Buyakov
  • Your code does not solve the voiced problem. I guess you did not take into account that the question was asked in the context of browser extensions. However, suppose you give an example for the popup.html page, and when it is updated, the data will actually be in the input field of this page (popup). However, the question is to restore the data entered on a third-party site using the content-script 'a. - Deliaz