Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observables and how to use them correctly in Angular2

So I had a question answered yesterday, and I feel like I was copying code and not fully understanding what I was doing until I started diving down deep into Observables. My problem is I've always had a bit of a hard time applying and finding documentation for my needs. Which means I still rely fairly heavily on seeing how other people have used code so I can get a better grasp of the concepts.

I have spent most of the night reading about it in the fairly excellent documentation here https://github.com/Reactive-Extensions/RxJS/tree/master/doc

I am starting to understand the ideas and power behind observables over promises. I have three-ish questions thus far about them;

  1. What are some good online resources where I can start digging down deeper?

My other questions do involve how to use them more effectively within my code.

  1. How can I get the last updated value of my observable out and hold it within a variable? Also is there any good way to persist the variable on page reload?

I am going to post my code for the next couple questions

@Component({
    selector: 'my-app',
    providers: [FORM_PROVIDERS, RoleService, UserService],
    inputs: ['loggedIn'],
    directives: [ROUTER_DIRECTIVES, CORE_DIRECTIVES, LoggedInRouterOutlet],
    template: `<body>
                <div *ngIf="loggedIn[0]=== 'true'">
                    <nav class="navbar navbar-inverse navbar-top" role="navigation">

                                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                                    <ul class = "nav navbar-nav">
                                        <li>
                                            <a [routerLink] = "['/RolesList']">Roles</a>
                                        </li>
                                        <li>
                                            <a [routerLink] = "['/UserList']">Users</a>
                                        </li>
                                        <li>
                                            <a [routerLink] = "['/UserRolesList']">User Roles</a>
                                        </li>
                                    </ul>
                                    <ul class="nav navbar-nav navbar-right">
                                    <li>
                                        <a [routerLink] = "['/Login']" (click)="logout()">Logout</a>
                                    </li>
                                    </ul>
                                </div>
                         </div>
                    </nav>
                </div>
                    <div class="container">
                        <router-outlet></router-outlet>
                    </div>
                  </body>`
})
export class AppComponent{

    public loggedIn: Array<string> = new Array<string>();
    public localStorage: Array<string> = new Array<string>();

    constructor(private _localStorage: LocalStorage){
    }

    ngOnInit(){
        this._localStorage.collection$.subscribe(login_trigger => {
            this.localStorage = login_trigger;
        });

        this._localStorage.loggedIn$.subscribe(to_be_or_not_to_be => {
            this.loggedIn = to_be_or_not_to_be;
        });

        this._localStorage.load();
    }

    logout(){
        localStorage.removeItem('jwt');
        this._localStorage.logout('false');
    }
}

Here is my LocalStorage class:

export class LocalStorage {
  public collection$: Observable<Array<string>>;
  private _collectionObserver: any;
  private _collection: Array<string>;

  public loggedIn$ :Observable<boolean>;
  private _loggedinObserver: any;
  private _loggedIn: Array<string>;

  constructor() {
    this._collection = new Array<string>;

    this._loggedIn = new Array<string>;

    this.loggedIn$ = new Observable(observer => {
      this._loggedinObserver = observer;
    }).share();

    this.collection$ = new Observable(observer => {
      this._collectionObserver = observer;
    }).share();
  }

  add(value: string) {
    this._collection.push(value);
    this._collectionObserver.next(this._collection);
  }

  logIn(value: string){
    this._loggedIn.unshift(value);
    this._loggedinObserver.next(this._loggedIn);
  }

  logout(value: string){
    this._loggedIn.unshift(value);
    this._loggedinObserver.next(this._loggedIn);
  }

  load() {
    this._collectionObserver.next(this._collection);
    this._loggedinObserver.next(this._loggedIn);
  }
}

Now when this loads my first does trigger correctly, but if I refresh the page the variable holding loggedIn has nothing in it, so the menu disappears. There is 2 problems with this, one is I would really like to dynamically change a variable on update to only hold one value instead of having to use the observable forced array. Can I only use an observable as an array?

  1. I understand from reading that Angular2 does not work a $watch event to watch for changes to the observables to fire events/functions with. Is there another way to watch for a change to an observable to fire a function or event off?

I would absolutely love to have my answers questioned for my code and how to use it better and hopefully in a less hacky way. But I would like even more to get a good understanding on Observables/Subjects and good resources. I know this is a long and broad post, I just don't have anyone that I can go to or ask for help with any of this and many of you angular2 guys that answer questions here have been fantastically helpful and made it much easier for me to understand the concepts.

Thanks!

like image 581
Morgan G Avatar asked Feb 15 '16 17:02

Morgan G


1 Answers

1) I think the best resources I read about reactive programming and observables are there ones:

  • https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
  • http://slides.com/robwormald/everything-is-a-stream

The key concept is how to create asynchronous data flow using operators. The two previous links give great explanations about this.

2) In fact, you will be notified when events occur through the callback you registered using the subscribe method. If you want to store the value associated with the event, it's up to you...

3) Regarding the equivalent of the $watch feature. Following answers could help you:

  • What is the Angular2 equivalent to an AngularJS $watch?
  • How to watch for form changes in Angular 2?

You have the ngOnChanges hook that allows you to be notified when bound elements are updated.

like image 157
Thierry Templier Avatar answered Sep 20 '22 15:09

Thierry Templier