# Create onboarding and its guard

**URL:** <https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604>\
**Category:** Ionic Angular\
**Created:** [September 20, 2020, 10:05am UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604 "2020-09-20T10:05:06Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 23, 2020, 8:55pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/21 "2020-09-23T20:55:03Z")

</div>

> [@UnknownInnocent](#):
>
> Since I try to build a little Game it is important to know, if the data sent to the Storage is really stored, which then means I need to declare all Methods to return a Promise and check it then.

I would push back on this.

Think of it this way. Let’s say you’re playing Hangman, and the game can be paused and resumed. What you would need to write to and read back from `Storage` is really just:

- the target word
- what guesses have been made so far

Everything else can be deduced from that. Now imagine that you have a service that keeps track of guesses. Every time it hears of a new one it adds it to its list, and writes that out to `Storage`.

The key part: **even before that write finishes, the service still has up-to-date data**. So as long as everybody else in the app is just asking _the service_ what’s been guessed, you have no problems.

The trouble starts to happen when other parts of the app bypass the service and read directly from `Storage`. I think this is a categorically bad choice for a myriad of reasons: it makes changing storage methods harder, it makes testing and maintenance harder, the code is harder to follow, etc. So as long as you are disciplined about not either reading or writing to `Storage` outside of your services, you can avoid bugs like this, even without waiting on `Storage` writes.

> [@UnknownInnocent](#):
>
> I don’t get how to use it in a resolver for example

I’m not familiar with the term “resolver” in this context. I’m guessing it’s from some object mapping library. I can’t really improve on the TypeScript documentation I linked earlier, but you can use arrays as generic parameters:

```auto
interface Spieler { ... }
class NamenseingabeResolver implements Resolve<Spieler[]> {
  resolve(): Promise<Spieler[]> {...}
}

```

…or (I’m having a tough time thinking of a real-world situation in which I would do something this abstract, but…):

```auto
class NamenseingabeResolver<T> implements Resolve<T[]> {
  resolve(): Promise<T[]> {...}
}

```

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 23, 2020, 9:04pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/22 "2020-09-23T21:04:35Z")

</div>

You made a good point with not accessing storage outside a service, I dindn’t think about this yet. This means that services are kind of static so everything else can access it and changes are saved globally.

Resolvers are used to load data for a page/component before it is actually loaded. They are added in the routing module:

```auto
{
  path: 'index-namenseingabe',
  loadChildren: () => import('../pages/namenseingabe/namenseingabe.module').then( m => m.NamenseingabePageModule),
  resolve: {
   spieler: NamenseingabeResolver
  }
},

```

And if I use this:

```auto
export class NamenseingabeResolver<T> implements Resolve<T[]> {

  constructor(private storageService: StorageService) { }

  resolve>(): Promise<T[]> {
    return this.storageService.get(Constants.SPIELER)
    .then(res => {
      if(res)
        return res;
      else
        return [];
    }).catch(() => {
      return [];
    });   
  }

```

I get this error:

````auto
ERROR in src/app/resolvers/namenseingabe.resolver.ts:14:5 - error TS2322: Type 'Promise<unknown>' is not assignable to type 'Promise<T[]>'.
[ng] Type '{}' is missing the following properties from type 'T[]': length, pop, push, concat, and 26 more.```
````

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 23, 2020, 9:10pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/23 "2020-09-23T21:10:00Z")

</div>

I found the solution for the error: I had to change

```auto
if(res)

```

to

```auto
if(res && Array.isArray(res))

```

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 23, 2020, 9:10pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/24 "2020-09-23T21:10:53Z")

</div>

> [@UnknownInnocent](#):
>
> services are kind of static so everything else can access it and changes are saved globally

Exactly.

> [@UnknownInnocent](#):
>
> Resolvers are used to load data for a page/component before it is actually loaded.

Ah, OK. I have not found lazy loading anywhere near worth the mountain of hassle, so I don’t bother with it.

I think the first example (using a concrete `Spieler[T]` parameter) is much more readable, anyway. The example [here](https://angular.io/api/router/Resolve#description) of a `Resolve<Hero>` could just as easily be a `Resolve<Hero[]>` to return an array of `Hero`s.

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 23, 2020, 9:16pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/25 "2020-09-23T21:16:01Z")

</div>

> I found the solution for the error: I had to change
> 
> ```auto
> if(res)
> 
> ```
> 
> to
> 
> ```auto
> if(res && Array.isArray(res))
> 
> ```

Is This also a good solution or should I create my own data-type `Spieler` for that?

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 23, 2020, 10:18pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/26 "2020-09-23T22:18:19Z")

</div>

I think what you have is fine.

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 24, 2020, 12:45pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/27 "2020-09-24T12:45:25Z")

</div>

So I now updatet my system so that storage service is only accessed by the services. I created Behaviour Subjects for my data and here comes the next problem: My guards need access to the data in these subjects but they don’t wait until this data is there. Before, I got the data directly from the storage so it was no problem.

```auto
spieler$ = new BehaviorSubject<any>('');

  constructor(private storageService: StorageService) { }

  init() {
    this.storageService.get(Constants.SPIELER).then( async res => {
      if(Array.isArray(res)) {
        this.spieler$.next(res);
        this.spieler = res;
      } else {
        this.spieler$.next([]);
      }
    });
  }

```

init is called in a resolver, right at the begiining, but still my guard does not wait for the data:

```auto
canActivate(): boolean {
    this.spielerService.spieler$.subscribe(async res => {
      if(res && Array.isArray(res) && res.length > 1) {
        this.router.navigate(['/home/spieleauswahl']);
        return false;
      } else {
        return true;
      }
    }).unsubscribe();
  }

```

Moreover, there is an error, because there is no return-path outside the subscription

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 24, 2020, 11:59pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/28 "2020-09-24T23:59:19Z")

</div>

> [@UnknownInnocent](#):
>
> `spieler$ = new BehaviorSubject<any>('');`

Two big problems here, and I bet you know what the first one is going to be: get rid of that `any`.

The larger one is that the contract of `BehaviorSubject` says that it is always valid, so your subscription will be called as soon as it is registered. If that’s a problem, don’t use `BehaviorSubject`. It is possible to have a `BehaviorSubject<Spieler[] | undefined>`, and then a check for truthiness in the subscription will tell you whether there is a valid `Spieler[]` there.

Finally, especially given that you’re relatively new to all of this, I would urge you to avoid `async` and `await` like the plague. They obscure what is actually happening, and should only be used when you understand _completely_ what they do (and, frankly, I would argue, not even then).

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 25, 2020, 7:04pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/29 "2020-09-25T19:04:13Z")

</div>

Okay I did all that and to make it easier I get the data in my guards directly from the storage - there I know how to do it

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 25, 2020, 7:06pm UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/30 "2020-09-25T19:06:17Z")

</div>

> [@UnknownInnocent](#):
>
> to make it easier I get the data in my guards directly from the storage

You’re in charge, but I still think that is going to be a decision you will regret, because of everything I said earlier about how you have introduced a breeding ground for race conditions.

---

<div class="post-metadata">

**Author:** ![UnknownInnocent](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/unknowninnocent/32/133712_2.png) [@UnknownInnocent](https://forum.ionicframework.com/u/UnknownInnocent)\
**Post date:** [September 26, 2020, 9:21am UTC](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604/31 "2020-09-26T09:21:44Z")

</div>

mhm… Do you have a tutorial for me where I can learn all of this in combination? So using the IonicStorage, connceting it with my services and using this data then in guards?

[Previous page](https://forum.ionicframework.com/t/create-onboarding-and-its-guard/196604.md?page=1)
