user2010955
user2010955

Reputation: 4011

Angular 4 how can a directive listen for changes of a property in injected service

i'm building an application using Angular 4, I have a component with the following template:

<input
    [value]="myService.myValue"
    >

where myService is a service injected into the component:

@Injectable()
    export class MyService {

    public myValue: string; // I could use an RxJS observable/Subject here
}

I need to add a directive (or something) who is listening for changes of myValue and change the color of the input text.

How can I do it? Any ideas?

Thanks!

Upvotes: 1

Views: 3102

Answers (4)

Aluan Haddad
Aluan Haddad

Reputation: 31833

A subject is way overkill for what you're talking about. In general, are reactive subject should be used sparingly.

You can accomplish what you want with a simple get accessor

export class MyService {
  myValue_: string;
  get myValue() {
    return this.myValue_;
  }
}

If you want the value to flow in the other direction as well you can add a set accessor although that would be best avoided since having a view right into your service class would be bit nasty.

Upvotes: 0

user2010955
user2010955

Reputation: 4011

I found a solution:

<input [myDirective]="myService.parameter" myServiceValue="{{myService.value}}" ... >


@Directive({
  selector: '[myDirective]'
})
export class parameterDirective implements OnInit, OnChanges {
  @Input('myDirective') parameter: parameter;
  @Input() myServiceValue: string;

  constructor(private el: ElementRef, private renderer: Renderer) {
  }

  ngOnInit(): void {
  }

  ngOnChanges(changes: SimpleChanges): void {
    switch (this.parameter) {
      case parameter.EnumValue:
        this.renderer.setElementClass(this.el.nativeElement, "my-class", changes.myServiceValue.currentValue > 100);
        break;
      default:
    }

  }
}

Upvotes: 0

Bunyamin Coskuner
Bunyamin Coskuner

Reputation: 8859

You can use ngClass or ngStyle as following

<input [value]="myService.myValue" 
       [ngStyle]="{'color': myService.myValue === 1 ? 'red' : 'blue'}">

or with ngClass

<input [value]="myService.myValue" 
       [ngClass]="{'color-red': myService.myValue === 1, 'color-blue' : myService.myValue === 2}">

Check this plnkr

https://plnkr.co/edit/2IAxwnXOaWS4TUL7aov0?p=preview

Upvotes: 0

SrAxi
SrAxi

Reputation: 20005

Create a shared service so when myValue changes you listen to it and you apply whatever logic you want.

Service:

@Injectable()
export class MyService {
    updateMyValue$: Observable<any>;

    private updateMyValueSubject = new Subject<any>();

    constructor() {
        this.updateMyValue$ = this.updateMyValueSubject.asObservable();
    }

    updateVal(newVal) {
        this.updateMyValueSubject.next(newVal);
    }
}

Component that changes the value:

this.myService.updateVal('new value');

Component that listens to the value's change:

this.myService.updateMyValue$.subscribe(
        (newVal) => {
              this.inputValue = newVal; // I called `inputValue` to the variable that will contain the value of the input. It should be initialized.
              // Here we can apply our own logic such as change color, hide some DOM elements or whatever we need to do
        }
    );

Explanation:

The first component is sending the new value to the service, in our case "new value".

The second component is subscribed to this Subject and as soon as next() is triggered it will receieve the new data. In other words, this component is listening to updateVal() function and as soon as it's triggered it will receive the data.

It's a very solid and practical way to communicate between components.

Upvotes: 1

Related Questions