# Sharing data

This section describes how we share data between graphical and non graphical components and classes.

Especialy, graphical components should not reference each other in order to **remain decoupled**.

Thats why we use **publish/subscribe** paradigm to addresse this issue.


## The Publisher

### Principle

* The **publisher** is a [JavaScript proxy](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that contains some data.<br>**
Example of data : `{foo:{hello:["world"]}, bar:"baz"}`

* if a property of the **publisher** (dot syntax / array access), it returns another **publisher**.
Using the previous example `myPublisher.foo.hello` is also a publisher containing `["world"]`

* If the property doesn't exist at the time of the request, a publisher is created. its internal data is set to `null`.<br>
The value that can then be provided later.

* **Subscribers** can subscribe to the publisher's modifications and be updated in different ways (see : onAssign, onInternalMutation, startTemplateFilling).

* Data inside the publisher is updated by modifying the publisher itself, for example `myPublisher.foo.hello = ["Joey", "Smith"]`
  
* The publisher publishes modifications to any of its **Subscribers**.


❇️ The order of data creation and subscription theoretically has no importance.

### Methods

* **set (complete replacement):** Assign/modifies the internal value of the publisher.
  <sonic-code language="javascript">
  <template>
  publisher.set({foo:{hello:["world"]}, bar:"baz"});  
  </template>
</sonic-code>
* **get:** Get the internal value of the publisher.
 <sonic-code language="javascript">
  <template>
  publisher.get() //{foo:{hello:["world"]}, bar:"baz"};
  </template>
</sonic-code>
* **onAssign/offAssign:** Subscribe/unsubscribe to value assignments (via `set`) of the publisher.
<sonic-code language="javascript">
  <template>
  publisher.a.b.onAssign(console.log);
  //indirect
  publisher.a = {b:"dramatic change"}; //log: "dramatic change"
  //via set
  publisher.a.b.set(["Hello"]) //log: ["Hello"]
  </template>
</sonic-code>
* **onInternalMutation/offInternalMutation:** Listen to any internal mutation regardless of its depth level.
<sonic-code language="javascript">
  <template>
  function save(){
  	console.log("Something has changed, let's save");
  }
  publisher.onInternalMutation(save);
  publisher.a.b[0] = "e";
  </template>
</sonic-code>
* **startTemplateFilling/stopTemplateFilling:** Fill an object model, a principle used with the Subscriber mixin on which most Concorde components rely.
<sonic-code language="javascript">
  <template>
  const fillableTemplate =  { title: "A title to be replaced"};
  publisher.startTemplateFilling(fillableTemplate);
  state.title = "Good morning";
  publisher.stopTemplateFilling(fillableTemplate);
  state.title = "Oops";
  console.log(fillableTemplate);
  </template>
</sonic-code>
* **invalidate:** Flag the data as invalid. Used by sonic-fetch and sonic-list to trigger data reloading.
<sonic-code language="javascript">
  <template>
publisher.invalidate();
  </template>
</sonic-code>
* **onInvalidate/offInvalidate:** Subscribe/unsubscribe to data invalidation of the publisher. Used by sonic-fetch and sonic-list to trigger data reloading.
<sonic-code language="javascript">
  <template>
function reloadData(){
  console.log("Reload data to inject it again into the publisher");
}
publisher.onInvalidate(reloadData);
  </template>
</sonic-code>

## DataProvider

Denotes the identifier of a publisher as referenced in the PublisherManager (see below).
Uses the dataProvider attribut in html tags to scop the content with some data.
see [Subscribers](#docs/_core-concept/subscriber.md/subscriber).


## PublisherManager

The **PublisherManager** is a utility class to get publishers

It plays a central role in the components, especially through the "subscriber" mixin.<br>
Automatic data communication between components in concorde uses this principle in conjunction with Lit's reactive properties. <br>
Refer to the documentation for [Subscriber](#docs/_core-concept/subscriber.md/subscriber).

<sonic-code language="javascript">
  <template>
import { PublisherManager } from "publisherproxy";
let dataProvider = "cart";
let publisher = PublisherManager.get(dataProvider);

  </template>
</sonic-code>

It is declared on the `window` object to allow usage in a web page, so the equivalent one-liner would be:

<sonic-code language="javascript">
  <template>
let dataProvider = "cart";
let publisher = SonicPublisherManager.get(dataProvider);

  </template>
</sonic-code>


## Basic Example

This example can be tested in a console when Concorde is loaded on the page (for example, in a ticketing system).
In a component, you will need to perform an `import` as explained earlier.

<sonic-code language="javascript">
  <template>
// Anywhere, anytime
SonicPublisherManager.get("mySubject").title.onAssign(console.log) 

  </template>
</sonic-code>

<sonic-code language="javascript">
  <template>
// Anywhere, anytime
let publisher = SonicPublisherManager.get("mySubject");
// ...
publisher.set({title: "A title"});
publisher.title.set("A second title");

  </template>
</sonic-code>