alexey
alexey

Reputation: 8480

JavaScript: sharing data between tabs

What is the best way to share data between open tabs in a browser?

Upvotes: 64

Views: 96454

Answers (13)

brillout
brillout

Reputation: 7474

For a more modern solution check out this answer quoted below:

I'm sticking to the shared local data solution mentioned in the question using localStorage. It seems to be the best solution in terms of reliability, efficiency, and browser compatibility.

localStorage is implemented in all modern browsers.

The storage event fires when other tabs makes changes to localStorage. This is quite handy for communication purposes.

Reference:
http://dev.w3.org/html5/webstorage/
http://dev.w3.org/html5/webstorage/#the-storage-event

Upvotes: 55

Jonas Frey
Jonas Frey

Reputation: 97

this creates an object on which you can set any properties, it will be set as a json string on the localStorage and then (if available) a BroadCast message will be sent, the other tab then loads the object from json and re-proxies it

let o_bc_o_localstorage = false; 
if("BroadcastChannel" in window){
    o_bc_o_localstorage = new BroadcastChannel('o_localstorage');
}
let f_o_localstorage_from_json_parse = function(){
    let o_localstorage = {}
    let s_o_localstorage = localStorage.getItem('o_localstorage');
    if(s_o_localstorage){
        o_localstorage = JSON.parse(s_o_localstorage)
    }
    return o_localstorage
}
let o_localstorage = f_o_localstorage_from_json_parse();
let f_update_localstorage = function(){
    if(o_bc_o_localstorage){
        o_bc_o_localstorage.postMessage('update')
    }
    localStorage.setItem('o_localstorage', JSON.stringify(o_localstorage))
}


let f_o_proxied_recursive = function(o, f_set, f_get){
    for(let s in o){
        if(typeof o[s] == 'object'){
            o[s] = f_o_proxied_recursive(o[s], f_set, f_get)
        }
    }
    o = new Proxy(o, {set: f_set, get: f_get});
    return o
}

let f_get = function(v_target, s_prop, v_receiver) {

    return Reflect.get(...arguments);
}

let f_set = function(v_target, s_prop, v_receiver) {
    console.log("setter called")
    if(typeof v_receiver == 'object'){
        
        v_receiver = f_o_proxied_recursive(v_receiver, f_set, f_get)
    }
    let o_res = Reflect.set(v_target, s_prop, v_receiver);
    f_update_localstorage()
    return o_res
}
let f_reproxy_o_localstorage = function(){
    o_localstorage = f_o_localstorage_from_json_parse()
    o_localstorage = f_o_proxied_recursive(o_localstorage, f_set, f_get)
}
if(o_bc_o_localstorage){
    o_bc_o_localstorage.onmessage = function(){
        console.log("reproxy")
        f_reproxy_o_localstorage()
    }
    f_reproxy_o_localstorage()
}
if(!o_bc_o_localstorage){
    let n_id = 0;
    let f_recursive = function(){
        n_id = window.requestAnimationFrame(f_recursive)
        f_reproxy_o_localstorage()
    }
    n_id = window.requestAnimationFrame(f_recursive)
}

//tab1 
o_localstorage.n = 420
o_localstorage.a = [1,2,3,4]
o_localstorage.o_s_o = {o_s_name_a_n:{a_1:[1,2,3], a_2:['a', 'b']}}
o_localstorage.o_s_o.o_s_name_a_n.a_1.push(420)
o_localstorage.o_s_o.o_s_name_a_n.a_2.push('fourtwenty')

//tab1 
o_localstorage.o1={o2:{o3:{n:4}}}
//tab2 
console.log(o_localstorage.o1.o2.o3.n) // 4
o_localstorage.o1.o2.o3.n = 5
//tab1 
console.log(o_localstorage.o1.o2.o3.n) // 5

Upvotes: 0

Ishan Fernando
Ishan Fernando

Reputation: 2868

This can be done using BroadcastChannel API in javascript. Let's say you have opened two different pages in a different tab and want to update the first page when the user changes some values in the second page you can do that like below.

First page

const ticketUpdateChannel = new BroadcastChannel('ticketUpdate');
ticketUpdateChannel.onmessage = function(e) {
     console.log('ticket updated')
 };

Second page

const ticketUpdateChannel = new BroadcastChannel('ticketUpdate');
ticketUpdateChannel.postMessage();

Now when you can postMessage it will trigger the onmessage on the first page.

Also, you can pass data like the below.

const ticketUpdateChannel = new BroadcastChannel('ticketUpdate');
ticketUpdateChannel.postMessage({message:'Updated'});


const ticketUpdateChannel = new BroadcastChannel('ticketUpdate');
ticketUpdateChannel.onmessage = function(e) {
     console.log('ticket updated',e.data)
 };

Upvotes: 1

Obaida Alhassan
Obaida Alhassan

Reputation: 601

The BroadcastChannel standard allows doing this. see MDN BroadcastChannel

// Connection to a broadcast channel
const bc = new BroadcastChannel('test_channel');

// Example of sending of a very simple message
bc.postMessage('This is a test message.');

// A handler that only logs the event to the console:
bc.onmessage = function (ev) { console.log(ev); }

// Disconnect the channel
bc.close();

enter image description here

Upvotes: 12

Timo Tijhof
Timo Tijhof

Reputation: 10307

See also another StackOverflow thread: Javascript communication between browser tabs/windows.

In my opinion there are two good methods. One may suit you better depending on what you need.

If any of these are true...

  • you can't store information server side,
  • you can't make many http requests,
  • you want to store only a little bit of information[1],
  • you want to be pure javascript / client side,
  • you only need it to work between tabs/windows in the same browser.

-> Then use cookies (setCookie for sending, getCookie/setTimeout for receiving). A good library that does this is http://theprivateland.com/bncconnector/index.htm

If any of these are true...

  • you want to store information server side
  • you want to store a lot of information or store it in a related matter (i.e. tables or multi-dimensional arrays[2])
  • you also need it to across different browsers (not just between tabs/windows in the same browser) or even different computers/users.

-> Then use Comet (long-held HTTP request allows a web server to basically push data to a browser) for receiving data. And short POST requests to send data.

Etherpad and Facebook Chat currently use the Comet technique.


[1] When using localStorage more data can be stored obviously, but since you'd fallback on cookies one can't rely on this yet. Unless you application is for modern browsers only in which case this is just fine.

[2] Complicated data can be stored in cookies as well (JSON encoded), but this is not very clean (and needs fallback methods for browsers without JSON.stringify/JSON.parse) and can fail in scenarios involving concurrency. It's not possible to update one property of a JSON cookie value. You have to parse it, change one property and overwrite the value. This means another edit could be undone theoretically. Again, when using localStorage this is less of a problem.

Upvotes: 5

Brian
Brian

Reputation: 37

I just took a look at how Facebook Chat does it and they keep a request to the server open for a little less then a minute. If data comes back to the server, the server then sends back the message to each open request. If no data comes back in a minute, it re-requests and continues to do this (for how long, I am not sure).

Upvotes: 2

Stephen Sorensen
Stephen Sorensen

Reputation: 11945

If the first tab opens the second tab automagically, you can do something like this:

First tab:

//open the first tab
var child_window = window.open( ...params... );

Second tab:

// get reference to first tab
var parent_window = window.opener;

Then, you can call functions and do all sorts of stuff between tabs:

// copy var from child window
var var_from_child = child_window.some_var;

// call function in child window
child_window.do_something( 'with', 'these', 'params' )

// copy var from parent window
var var_from_parent = parent_window.some_var;

// call function in child window
parent_window.do_something( 'with', 'these', 'params' )

Upvotes: 23

Chris
Chris

Reputation: 15651

How about to use a cookie to store data in one tab and poll it in another tab? i dont know yet if a cookie is shared between tabs but just an idea now ...

Upvotes: 3

DisgruntledGoat
DisgruntledGoat

Reputation: 72580

Depending on the requirements you can also use cookies/sessions. However, this means the data will only be accessible on the first page load of each tab.

If you already have two tabs open, changing something in one will not change the other unless you use some AJAX.

Upvotes: 0

Justin Johnson
Justin Johnson

Reputation: 31300

You could use AJAX (as everyone else is suggesting) or cookies if the data is small. See http://www.quirksmode.org/js/cookies.html for fun with cookies.

Upvotes: 1

Randell
Randell

Reputation: 6170

One way to do this is to not let the chat window be dependent on the tabs. Load the tabs as seperate AJAX components that when reloads doesn't affect the chat component.

Upvotes: 0

n1313
n1313

Reputation: 21431

Given that these tabs are open with the same site in them, you might consider building an ajax script that reports user actions to server and couple it with another ajax script that reads that reports and reflects them in current window.

Upvotes: 1

Alsciende
Alsciende

Reputation: 26981

The only way I can think of: constant ajax communication with the server to report any user action on the other tabs.

Upvotes: 2

Related Questions