# AlpineJS component store

Within AlpineJS, you could create a data store with `Alpine.store()` and then allow components to use the data within. It is a scoped alternative to global variables. The LokiCheckout uses this to create two stores: `LokiComponents` and `LokiCheckout` - actually the `LokiCheckout` store extends upon the `LokiComponents` store.

> We strongly recommend to use the Alpine.js devtools or the Alpine.js Pro DevTools to preview what is the Alpine stores.

## Components store
The `LokiComponents` store is defined in the PHTML template `Loki_Components::script/components-store.phtml`.
Every time that a LokiComponent is created, it *registers* itself in the `LokiComponents` store:

```js
Alpine.store('LokiComponents').add(this);
```

And thanks to this registration, one component is able to make a connection to another component via the store - provided you know the name of that component. Each LokiComponent has a unique `id` (which is actually based upon the Magento block name, turned into camelcase) which becomes the name in the store.

```js
Alpine.store('LokiComponents').get(componentName);
```

To list all components, we can do the following:
```js
Alpine.store('LokiComponents').getComponents();
```

This returns an array of all Alpine components. However, you should note that in AlpineJS, each component is actually an object with a `Proxy` in front of it. In other words, each entry in the `getComponents()` is a `Proxy`. To list all component IDs instead, you can use the following:

```js
Alpine.store('LokiComponents').getComponentIds();
```

## Adding global messages
Following from this, we can add global messages via Alpine like so:
```js
const globalMessageComponent = Alpine.store('LokiComponents').get('LokiComponentsGlobalMessages');
globalMessageComponent.messages.push({
    type: 'notice',
    text: 'Hello World'
});
```

## Checkout store
The `LokiCheckout` store is defined in the PHTML template `Loki_Components::script/components-store.phtml`. The `LokiCheckout` store acts as a decorator upon the `LokiComponents` store. The following calls are identical:
```js
Alpine.store('LokiComponents').getComponentIds();
Alpine.store('LokiCheckout').getComponentIds();
```

On top of this, the `LokiCheckout` store adds various additional methods that are handy in the checkout specifically. For instance, most LokiComponents in the checkout also have a `step` identifier and field name. And we can retrieve specific components by step and field name like so:

```js
Alpine.store('LokiCheckout').getComponentByFieldNameAndStep('country_id', 'shipping').id;
```

The current step is fetched like so:
```js
Alpine.store('LokiCheckout').currentStep;
```

## Listing invalid components
In a similar way, the LokiCheckout adds validation to each field (`component.valid`). And this could be used again to fetch all AlpineJS component that are invalid (`component.valid = false`):
 
```js
Object.values(Alpine.store('LokiCheckout').getInvalidComponents('shipping')).forEach(component => console.log(component.id));
```
