Search code examples
angularangular2-changedetection

change detection in angular2 using shared service


i am having a parent function ngOnInit() which gets the value from google maps as follow

instance.input = document.getElementById('google_places_ac');
        autocomplete = new google.maps.places.Autocomplete(instance.input, { types: ['(cities)']});
        google.maps.event.addListener(autocomplete, 'place_changed', function () {
            var place = autocomplete.getPlace();
            instance.setValue(place.address_components[3].long_name, place.address_components[2].long_name, place.address_components[1].long_name);

        });

setValue() is function which shares value with shared service and on html page i have same thing as follow on parent and child <input id="google_places_ac" [(attr.state)]="state" [(attr.country)]="coutnry" name="google_places_ac" type="text" value="{{city}}" class="form-control" />

in parent component class i fire changedetection on setValue() function

   setValue(a, b, c) {
        this.coutnry = a;
        this.state = b;
        this.city = c;
        this.sharedService.country = this.coutnry;
        this.sharedService.city = this.city;
        this.sharedService.state = this.state;
        this.cdr.detectChanges();
      //  console.log(this.coutnry, this.state, this.city);
    }

this works well on parent but change is not happening on child , i created a click function which fires the changedetection on child which works too but i want it to fire automaticaly from parent is there any workaround for it?


Solution

  • When it comes to sharing a global object between components, it is better to use global shared service combined with Rxjs observable design pattern. Here is the code, You should configure it according to yours:

    First, your global shared service should look like this:

    import {Injectable} from "angular2/core";
    import {Subject} from "rxjs/Subject";
    @Injectable()
    export class SearchService {
    
    private _searchText = new Subject<string>();
    
    public searchTextStream$ = this._searchText.asObservable();
    
    broadcastTextChange(text:string) {
        this._searchText.next(text);
        }
    }
    

    Second,you inject your service into your parent component

    ...
    constructor(private _searchService:SearchService) {
    ...
    

    Third, add to the providers list of your parent component or higher component the service, because this service should the same instance between subscribed components, This part is very important:

    providers: [SearchService,...]
    

    Then when you want to broadcast new change you call broadcastTextChange with a new value as follows:

    ...
    this._searchService.broadcastTextChange("newTextHere");
    ...
    

    Then inside your the child component you inject the same service and subscribe to it:

    this._searchService.searchTextStream$.subscribe(
            text => {
                // This text is a new text from parent component.
                this.localText = text;
                //Add your own logic here if you need.
            }
        )