import {
  Story,
  Meta,
  html,
} from '@open-wc/demoing-storybook';

import { ajax } from '../src/ajax.js';
import { AjaxClass } from '../src/AjaxClass.js';

<Meta title="Others/Ajax" parameters={{ component: 'lion-ajax' }} />

# Ajax

`lion-ajax` is the global manager for handling all ajax requests.
It is a promise based system for fetching data, based on <a href="https://github.com/axios/axios" target="_blank">
axios</a>

<Story name="Default">
  {html`
    <button
      @click=${() => {
        ajax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response.data);
          })
          .catch(error => {
            console.log(error);
          });
      }}
    >
      Execute Request to Action Logger
    </button>
  `}
</Story>

```js
ajax.get('./packages/ajax/stories/data.json').then(response => console.log(response.data));
```

## Features

- only JS functions, no (unnecessarily expensive) web components
- supports GET, POST, PUT, DELETE, REQUEST, PATCH and HEAD methods
- can be used with or without XSRF token

## How to use

### Installation

```sh
npm i --save @lion/ajax
```

```js
import { ajax, AjaxClass } from '@lion/ajax';
```

### Performing requests

Performing a `GET` request:

<Story name="GET">
  {html`
    <button
      @click=${() => {
        ajax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response.data);
          })
          .catch(error => {
            console.log(error);
          });
      }}
    >
      Execute Request to Action Logger
    </button>
  `}
</Story>

```js
ajax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });
```

To post data to the server, pass the data as the second attribute in the `POST` request:

```js
const body = {
  ant: {
    type: "insect",
    limbs: 6,
  }
};

ajax
  .post('zooApi/animals/addAnimal', body)
  .then(response => {
    console.log(`POST successful: ${response.status} ${response.statusText}`);
  })
  .catch(error => {
    console.log(error);
  });
```

## Configuration

### JSON prefix

The called API might add a JSON prefix to the response in order to prevent hijacking.
The prefix renders the string syntactically invalid as a script so that it cannot be hijacked.
This prefix should be stripped before parsing the string as JSON.
Pass the prefix with the `jsonPrefix` option.

```js
const myAjax = AjaxClass.getNewInstance({ jsonPrefix: ")]}'," });
myAjax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });
```

### Additional headers

Add additional headers to the requests with the `headers` option.

<Story name="Headers">
  {html`
    <button
      @click=${() => {
        const myAjax = AjaxClass.getNewInstance({ headers: { 'MY-HEADER': 'SOME-HEADER-VALUE' } });
        myAjax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response);
          })
          .catch(error => {
            console.log(error);
          });
      }}
    >
      Execute Request to Action Logger
    </button>
  `}
</Story>

```js
const myAjax = AjaxClass.getNewInstance({ headers: { 'X-CUSTOM-HEADER': 'SOME-HEADER-VALUE' } });
myAjax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
```

When executing the request above, check the Network tab in the Browser's dev tools and look for the Request Header on the GET call.

### Cancelable Request

It is possible to make an Ajax request cancelable, and then call `cancel()` to make the request provide a custom error once fired.

<Story name="Cancelable">
  {html`
    <button
      @click=${() => {
        const myAjax = AjaxClass.getNewInstance({ cancelable: true });
        requestAnimationFrame(() => {
          myAjax.cancel('too slow');
        });
        myAjax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response.data);
          })
          .catch(error => {
            console.log(error);
          });
      }}
    >
      Execute Request to Action Logger
    </button>
  `}
</Story>

```js
const myAjax = AjaxClass.getNewInstance({ cancelable: true });

requestAnimationFrame(() => {
  myAjax.cancel('too slow');
});

myAjax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error);
  });
```

### Cancel concurrent requests

You can cancel concurrent requests with the `cancelPreviousOnNewRequest` option.

<Story name="Cancel Previous on New Request">
  {html`
    <button
      @click=${() => {
        const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
        myAjax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response.data);
          })
          .catch(error => {
            console.log(error.message);
          });
        myAjax
          .get('./packages/ajax/stories/data.json')
          .then(response => {
            console.log(response.data);
          })
          .catch(error => {
            console.log(error.message);
          });
      }}
    >
      Execute Both Requests to Action Logger
    </button>
  `}
</Story>

```js
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });

myAjax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error.message);
  });

myAjax
  .get('./packages/ajax/stories/data.json')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.log(error.message);
  });
```

## Considerations

Due to a <a href="https://github.com/axios/axios/issues/385" target="_blank"> bug in axios</a> options may leak in to other instances.
So please avoid setting global options in axios. Interceptors have no issues.

## Future plans

- Eventually we want to remove axios and replace it with <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" target="_blank">
Fetch</a>
- This wrapper exist to prevent this switch from causing breaking changes for our users
