Block a State Transition with a Guard

Isaac Mann
InstructorIsaac Mann
Share this video with your friends

Social Share Links

Send Tweet

If a network call returns an empty list, that should be rendered differently than a list with elements in it. We’ll create two substates of the http success state (withData and withoutData) and choose which substate to transition to based on the http response using an automatic transition and a guard.

Instructor: [00:00] We have this app that loads Star Wars characters and planets. We've handled the case where the server responds with an error, but what if the server responds with an empty array? It was a successful response, but there's still nothing to show. Our UI should do something smarter than just display nothing.

[00:19] Let's add a couple of new states inside of the successful state. We'll call them with data and without data. We'll define them here with states. Let's see what this looks like in the Visualizer.

[00:37] When we're in the pending state and the fetch data service returns a done response, we need to decide at that point whether to transition to the with data state or the without data state, depending on the value that comes back from the server.

[00:51] Let's do this by making an array of possible transitions here and change the target from the first one to successful.withData. Now you see our done transition goes directly to successful.withData, instead of staying on the successful state.

[01:07] We can add a second transition. Now our visualizer shows that we could transition to either with data or without data. What would actually happen is the first transition would always take place. We need to add something called a condition to this transition that will check a guard called has data.

[01:30] If has data returns true, it'll go to with data and if has data returns false, it will go to the next transition, which will send us to without data. We can define the has data guard in this second object down here in the guards object. Has data, it takes a context and event parameter.

[01:52] In our case, we'll just return true. When the done event fires, it always goes to with data. If we change our guard to return falls, when the done event fires, it always goes to without data. Let's use this code in our application.

[02:09] I've place it in this array of transitions on the on done event and we'll define the has data guard and we'll return event.data and event.data.length > 0Let's update our UI to account for this new state. This state should be successful.withData and for without data, we'll say no data available. When we fetch our data and there's no data available, it will display a message.

[02:54] The way we set up the state machine, the pending state has to know about all the sub-states inside of successful and ease to route the appropriate one. We could rewrite this machine so that the successful state is in charge of its own sub-states. We'll let a third state to successful called unknown.

[03:18] When we create this state, we'll set it up with a special kind of transition called an automatic or transient transition. It's denoted by this empty string. This automatic transition will be executed as soon as you enter this state and keeping executed every time an event happens if for some reason you stay inside of this state.

[03:40] Now we can take this logic here and move it into our transient transition. We can remove successful. from these transitions since we're already inside of the successful state. We need to tell successful that its initial state is unknown.

[03:55] On done can set its target directly to successful and it still needs the set results action. Set results can be removed from these transitions down here. Let's see what this looks like in the visualizer. Now the done event transition directly to successful, then the unknown state transitions to with data, since the has data guard always returns true. If we change this to false, unknown will always transition to without data.

[04:27] Both of these state machine designs exhibited the same behavior in the application.