platform icon indicating copy to clipboard operation
platform copied to clipboard

Observable updates aren't reflected in templates

Open paztis opened this issue 5 years ago • 5 comments

This is a...

  • [ ] feature request
  • [x] bug report
  • [ ] usage question

What toolchain are you using for transpilation/bundling?

  • [x] @angular/cli
  • [ ] Custom @ngTools/webpack
  • [ ] Raw ngc
  • [ ] SystemJS
  • [ ] Rollup
  • [ ] Other

Environment

NodeJS Version: 12.13.1 Typescript Version: 3.7.5 Angular Version: 9.0.1 @angular-redux/store version: 10.0.0 @angular/cli version: (if applicable) rxjs: 6.5.4 OS: Windows

Link to repo showing the issus

(optional, but helps a lot)

Expected Behaviour:

In below sample, redux observable updates are not displayed in the templates. state.loader.counter is a number that is increased each second. The console log well display the new value each second.

We only see the first value on the screen

import {Component, OnInit} from '@angular/core';
import {select} from '@angular-redux/store';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-loader',
  template: `<div>Counter: {{ loaderCounter$ | async }}</div>`,
})
export class LoaderComponent implements OnInit {
  ngOnInit() {
    this.loaderCounter$.subscribe((counter) => {
      console.log('----counter', counter)
    })
  }

  @select((state) => {return state.loader.counter}) loaderCounter$: Observable<number>;
}

If I replace the select decorator with a classic selector in the ngOnInit, result is the same

If I put a classic Observable, rendering is working correctly

import {Component, OnInit} from '@angular/core';
import {select} from '@angular-redux/store';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-loader',
  template: `<div>Counter: {{ classicObservable$ | async }}</div>`,
})
export class LoaderComponent implements OnInit {
  ngOnInit() {
  }

  classicObservable$ = new Observable<number>(observer => {
    let counter = 0;
    observer.next(counter);

    setInterval(() => {
      counter++;
      observer.next(counter);
    }, 1000);
  });
}

paztis avatar Feb 19 '20 22:02 paztis

I'm using a library that provide an already created redux store I attached it to my angular app through ngRedux.provideStore(myStore);

But this means there's 2 instances of Redux in my app:

  • 1 provided in the lib I use
  • 1 tracked by @angular-redux/store

Isn't it a conflict here ? I mean angular-redux listen on methods of the bad redux ? How to support this case ?

paztis avatar Feb 20 '20 09:02 paztis

It start to be really crazy. If I create 2 Observers:

  • 1 from @select as in hte 1st example
  • 1 manual, that subscribe from the select, log and update teh value

Even in this case the rendering is failed...

Noone already envounter this problem ?

import {Component, OnInit} from '@angular/core';
import {select} from '@angular-redux/store';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-loader',
  template: `<div>Counter: {{ classicObservable$ | async }}</div>`,
})
export class LoaderComponent implements OnInit {
  ngOnInit() {
  }

  @select((state) => {return state.loader.counter}) loaderCounter$: Observable<number>;

  classicObservable$ = new Observable<number>(observer => {
    this.loaderCounter$.subscribe((counter) => {
      console.log('----counter', counter)
      observer.next(counter);
    })
  });
}

paztis avatar Feb 20 '20 12:02 paztis

OK after loooong search I found the problem, and it seems a pure angular issue

This code is working:

import {Component, OnInit} from '@angular/core';
import {select} from '@angular-redux/store';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-loader',
  template: `<div>Counter: {{ loaderCounter$ | async }}</div>`,
})
export class LoaderComponent implements OnInit {
  ngOnInit() {
        setInterval(() => {
        }, 100)
  }

  @select((state) => {return state.loader.counter}) loaderCounter$: Observable<number>;
}

The reason is that the action origin is out of angular application. I just create an empty interval method in my component, and the angular application will understand there an activity in the app, then will update corresponding rendering... Really crazy.

Will open a defect in angular and close this one.

paztis avatar Feb 20 '20 13:02 paztis

It seems the reason is I provide to angular-redux an externally created store. In this case this store is not wrapped by zonejs. How can we support it properly ?

paztis avatar Feb 21 '20 06:02 paztis

@paztis That's quite the journey you had. I think the bigger question is how to get more people managing this repository because it seems pretty dead at the moment.

maplion avatar Feb 23 '20 03:02 maplion