2

I'm trying to disable/enable a button in a component based on property status false/true. This status changes in the service based on an if-statement.

*.service.ts:

public connectionRetry(
    initialDelay,
    maxRetry,
    errorWhiteList,
    triggerBtn,

  ) {
    return (errors) => errors.scan((retryAttempts, error) => {
        if ( retryAttempts < maxRetry ) {
            triggerBtn = true;
        }
        if ( !errorWhiteList.includes(error.status ) || retryAttempts > maxRetry) {
            triggerBtn = false;
            throw error;
        }
        return retryAttempts + 1;
    }, 0).switchMap((retryAttempts) => {
          let delay = Math.pow(2, retryAttempts - 1) * initialDelay;
          return Observable.timer(delay);
    });
}

*.component.ts:

public isBtnDisabled = false;
constructor ( public mainService: MainService, public mainUtils: MainUtils ) {}

public storeData(paramX, paramY) {
     this.mainService.addUser(paramX, paramY)
     .retryWhen(
         this.mainUtils.connectionRetry(
         xxx, 
         xxx, 
         [xxx], 
         this.isBtnDisabled,
    ))
    .subscribe(
       res => {....},
       error = > {...}

    );
} 

*.component.html:

<button [disabled]="!form.valid || isBtnDisabled">button text</button>

The issue is that I just can't make this concept working... the property isBtnDisabled keeps always the status: false in the component ts and html.

If I implement the function: connectionRetry() directly in the *.component.ts, it works straight forward, but not via the service. Has it to do with the angular digest cycle?

I have been searching (also here in SOF) and trying different approach as, but unfortunately without success. It seems to be simple actually.

k.vincent
  • 3,743
  • 8
  • 37
  • 74

1 Answers1

1

You can also do the usual way - through Subject or BehaviorSubject

Service:

public $btnSubject = new BehaviorSubject<boolean>();

Now whenever you need to change false to true and vise versa, just next(//true or false):

return (errors) => errors.scan((retryAttempts, error) => {
   if ( retryAttempts < maxRetry ) {
       this.$btnSubject.next(true)
   }

And in component subscribe to that Subject:

ngOnInit() {
  this.mainService.$btnSubject.subscribe(val => this.isBtnDisabled = val)
}

p.s. usual is better to keep Subject private to class scope and create another instance - public btnSubject$ = this.$btnSubject.asObservable() and subscribe to it.


OLD POST:

When you pass this.isBtnDisabled to retryWhen() you just pass a value of it, not the reference of an object.

I am not sure at what time you want to set isBtnDisabled to true, so maybe there is a better way, but this also, i assume is OK - you can simply reference to that isBtnDisabled:

.subscribe(
  res => {this.triggerBtn = this.mainService.triggerBtn }
Julius Dzidzevičius
  • 10,775
  • 11
  • 36
  • 81
  • Yes, you are right... in tis case I'm passing just the status/value in this case without reference to the element. Have been also trying `@ViewChild('mainBtn') mainBtn: ElementRef;` and then changing the status, but it didn't help.The button should be disabled as long as request is try to connect to the server. When the retry ends e.g. with a failed connection (can't reach the server), then should be back to enabled in order the let the user clicks once again. – k.vincent May 03 '18 at 15:13
  • Yes, thats confusing at first, but later it makes sense. – Julius Dzidzevičius May 03 '18 at 15:14
  • ...in this case your suggestion won't work as expected, as both cases must happen before `subscribe() {...}` – k.vincent May 03 '18 at 15:20
  • Ok, I added another option – Julius Dzidzevičius May 03 '18 at 15:50
  • Good idea. I was right now looking at this [question](https://stackoverflow.com/questions/35869406/angular2-detect-change-in-service). I'll give it a try. – k.vincent May 03 '18 at 15:52
  • In that question's answer they use EventEmitter - its another way to pass data, but its best for parent-component - child-component relation – Julius Dzidzevičius May 03 '18 at 15:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170303/discussion-between-k-vincent-and-from-zero-to-hero). – k.vincent May 03 '18 at 15:57
  • It works implementing the second option... Just one small thing has to change/be updated. The construction function `BehaviorSubject()` expects a parameter, so therefore I changed it to: `public $btnSubject = new BehaviorSubject(false);` – k.vincent May 03 '18 at 16:07