4

The problem

I have a component with a subscription to an Observable. The value of myValue gets updated in the template only after I move the mouse over the browser window.

The strangest thing is that the two console.log work fine.

  • I reload the page keeping the mouse static
  • I can see the updated value in the console
  • The template still shows the 'defaultValue' value
  • I move the mouse, and the template shows the updated value I was already seeing in the console.

I managed to make it work with ChangeDetectorRef and .detectChanges(), but it seems as wrong as using $scope.apply() in AngularJS when you don't know where's the problem.

my-component.component.ts

import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { HelperService } from 'path';

@Component({
    selector: 'my-selector',
    templateUrl: 'my-component.component.html'
})
export class MyComponent implements OnDestroy, OnInit {
    myValue: string;

    private subscription: Subscription;

    constructor(
        private helperService: HelperService
    ) {
        //
    }

    ngOnInit() {
        this.myValue = 'defaultValue';

        this.subscription = this.helperService.getNewValue$().subscribe((newValue) => {
            console.log('pre', this.myValue);
            this.myValue = newValue;
            console.log('post', this.myValue);
        });
    }

    ngOnDestroy() {
        if (this.subscription !== undefined ) {
            this.subscription.unsubscribe();
        }
    }
}

helper.service.ts

    getNewValue$(): Observable<string> {
        return Observable.fromPromise(this.methodCallingAThirdPartyLibrary());
    }

my-component.component.html

debug: {{ myValue }}
William Ghelfi
  • 427
  • 7
  • 17

3 Answers3

1

Here's an interesting point: https://stackoverflow.com/a/41241646/1030207

this.methodCallingAThirdPartyLibrary() is returning the Promise returned by a call to a third-party library's method so maybe everything is happening outside Angular's control.

Tomorrow morning (23.44 here) I'll try wrapping that inner call into a zone.run

Community
  • 1
  • 1
William Ghelfi
  • 427
  • 7
  • 17
0

As I can't implement your service I have done below code to log when any change occurs in the component using ngDoCheck and ChangeDetectionStrategy as below

import {Component, NgModule ,ChangeDetectionStrategy,ngDoCheck} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser'
import {FormsModule} from '@angular/forms';
@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
        <input [(ngModel)]="someValue" />
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements ngDoCheck {
  someValue:any;
  name:string;
  constructor() {
    this.name = 'Welcome to Change Detection Demo'
  }
  ngDoCheck(){
    console.log(this.someValue);

    }
}

I have used a text box to detect changes in the component.

LIVE DEMO

Aravind
  • 40,391
  • 16
  • 91
  • 110
  • Thanks, I'm not sure this can be a good example though: typing with the keyboard seems likely to have the same effect as moving the mouse thus invalidating the test. – William Ghelfi Jan 26 '17 at 22:33
  • not exactly. try with some asynchronous method by calling with a set time out. it will also be logging – Aravind Jan 26 '17 at 22:51
0

You should change the detection strategy for your component. I had a similar case what resolved my issue was to put add changeDetection variable to Default instead of OnPush. Like the following.

@Component({
    selector   : 'mycomponent',
    templateUrl: './mycomponent.html',
    changeDetection: ChangeDetectionStrategy.Default
})
David Innocent
  • 606
  • 5
  • 16