---
description: >-
  Here we will allow the graphic to animate between titles and cover how to
  handle the remove function.
---

# Advancing & Removal

### Dealing with Asynchronous Animations

To begin with, let's find a bug in our current graphic. If you run the `play` function then the `stop` function in quick succession, the animation will break. To solve this, we will utilize a new JS feature called [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). Promises allow us to delay the the execution of code until an asynchronous function, or function that happens in parallel to our other code, completes. A more technical breakdown of [asynchronous code](https://developer.mozilla.org/en-US/docs/Glossary/Asynchronous) can be found on MDN's. For now, we just need to know that our GSAP animation happens asynchronously so we want to wait until it completes to continue executing our code. Let's wrap our `animateIn` function inside of a new Promise.

```javascript
function animateIn() {
    return new Promise((resolve, reject) => {
        const graphic = document.querySelector('.lt-style-one .graphic');
        /* Other Element Variable Definitions */
        
        const tl = new gsap.timeline({
            duration: 1, 
            ease: 'power1.out',
            onComplete: resolve // Will resolve when the animation is complete
        });
        /* Timeline animation */
    });
}
```

We will return the new Promise so we can chain multiple animation together. Our Animate In Promise will allow the next Promise to execute once the `resolve` function is called. In this case, we `resolve` the Promise when the timeline completes all it's animations. Let's wrap out`animateOut` function in a Promise as well. &#x20;

```javascript
function animateOut() {
    return new Promise((resolve, reject) => {
        const graphic = document.querySelector('.lt-style-one .graphic');
        /* Other Element Variable Definitions */
        
        const tl = new gsap.timeline({
            duration: 1, 
            ease: 'power1.out',
            onComplete: resolve // Will resolve when the animation is complete
        });
        /* Timeline animation */
    });
}
```

Wrapping the `animateOut` function in a Promise works the same was as the `aniamteIn` function.&#x20;

#### Running Animations in Succession

We are going to need a function that handles executing and waiting for our animations to complete. Right below our inner IIFE, or knock-off constructor function, let's add an `executePlayOutCommand` function and a `addPlayOutCommand`function.

```javascript
const _graphic = (function() {
    (function() {
        /* Play Out commands attached to window object */
    })();
    
    function executePlayOutCommand() {
        
    }
    
    function addPlayOutCommand(prom) {
    
    }
    
    function applyStyles() { }
    // Other function definitions
}
```

The `appPlayOutCommand` function will take a Promise as an argument and add it to an array of Promises to execute. We will need to store the array somewhere and we will also want to throttle the number of animations being ran in succession. The amount of throttling needed for each graphic will vary but, for our example, three animations in the queue should be plenty. Let's add an `animationQueue` and `animationThreshold` variables to out graphic.

```javascript
const _graphic = (function() {
    let state = 0;
    let activeStep = 0;
    let currentStep = 0;
    let data = [];
    let style;
    const animationQueue = [];
    const animationThreshold = 3;

    (function() {
        /* CasparCG commands attached to window object */
    })();
    
    function executePlayOutCommand(prom) { }
    
    function addPlayOutCommand(prom) { }
    
    function applyStyles() { }
    // Other function definitions
}
```

We can now write the logic for how our animations will be executed in `executePlayOutCommand` function and adding the Promise to our list in `addPlayOutCommand` function.

```javascript
function executePlayOutCommand() {
    // Run the first Promise
    animationQueue[0]().then(() => {
        animationQueue.splice(0, 1);
        // If there are more, run them
        if(animationQueue.length) executePlayOutCommand();
    }).catch(e => HandleError(e));
}

function addPlayOutCommand(prom) {
    if(animationQueue.length < aniamtionThreshold) 
        animationQueue.push(prom);
    // Warn user about threshold
    if(animationQueue.length === aniamtionThreshold)
        handleWarning('Animation threshold met');
    // If there is only one comamnd, run it
    if(animationQueue.length === 1) executePlayOutCommand();
}
```

The `addPlayOutCommand` function simply takes our Promise and adds it to the list of commands to execute. Then if there is only the one command we just added, we will run it in `executePlayOutCommand`. We will also log a warning when we meet the animation threshold. This will help with debugging errors. The `executePlayOutCommand` function will then run the first Promise in the array and when it is complete, we will check for another Promise. If there is one, call the `executePlayOutCommand` function again. This process will repeat until there are now more Promises.&#x20;

### Handling an Advance Command

Now that we are handling our asynchronous animations, let's take advantage of those Promises to create an advance animation. We will add the code to update the title and subtitle between the `animateOut` and `animateIn` functions by using a [`then` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then). `then` functions are chained onto Promises and represent the next portion of script to be run. Let's create our `next` function and break it down.

```javascript
function next() {
    if(state === 1) { // Graphic can be played
        play();
    } else if(state === 2) { // Graphic can be advanced
        if(data.length > currentStep + 1) { // There is another title to show
            currentStep++;
            const animation = () => animateOut().then(() => {
                activeStep++;
                applyData();
                return;
            }).then(animateIn);
            addPlayOutCommand(animation);
        } else {
            handleError('Graphic is out of titles to display');
        }
    } else {
        handleError('Graphic cannot be advanced while in state ' + state);
    }
}
```

We begin by checking which state the graphic is in. If we are in state `1` then we can simply play the graphic. Although the `play` command should be used, we will give the graphics operators a bit of wiggle room. If the graphic is in state `2` we can advance it but, we need to check and see if there is some data to advance to. We check that by making sure the `data`variable has a length greater than what `currentStep` we are on. Remember, `currentStep` is what title we are going to see once all the animations are complete. When we add the `reset` function, this will become more important because we could advance, reset, then advance again in once animation queue before reaching our threshold. We would want to know that after all of that, if we run another next command, we will be out of titles.&#x20;

If the data is an array and meets our `currentStep` rule, we will increment the `currentStep` variable and create a Promise chain that will animate out our graphic, change the data, increment the `activeStep`, and then animate the graphic back in. Finally we call `addPlayOutCommand` with our Promise chain to allow the graphic to run the advance animation with our other animations.&#x20;

### Removing the Graphic

Thankfully we do not have any clean up to do in our `remove` function. This is typically where you would make any API calls or store some temporary data in local storage. Both of those concepts are for more advanced graphics but we would recommend reading MDN's page on[ Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) for more info. For now, we will just check if the graphic has been played and if so, run the `stop` function. This will allow our graphic to gracefully animate off if `remove` is called.&#x20;

```javascript
function stop() { /* Stop function script */ }

async function remove() {
    if(state === 2) await animateOut(); // Wait here until animateOut resolves
}

function handleError(e) {console.error(e)}
```

There is one additional trick we will use in our `remove` function to make the code cleaner and that is `async` and `await`. `async` and `await` are used to make Promises act like synchronous functions. We tell the JS engine that a function contains some asynchronous code by labeling the function with `async`. Then when we want to run a Promise and pause our code execution, we use `await`. The example above states that the `remove` function contains some asynchronous code and we want to stop the code execution when the `animateOut` function runs. Any other code, if there was some, after the `animateOut` function would then run.

#### Resources

* [Promises ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)on MDN's website.
* [Then](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then), [Catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch), and [Finally](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally) promise methods on MDN's website.
* [Async & Await](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) on MDN's website.
* [Asynchronous overview](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous) on MDN's website.
* [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) on MDN's website.
