51

All! I've this component where when I click on the href it is supposed to set a variable as Root Scope if it was Angular 1 like this:

selector: 'my-component'
template : `
            <div (click)="addTag(1, 'abc')">`

constructor() {
    this.addTag = function(id, desc){
        myGlobalVar = { a: id, b: desc};
    };

Then in my parent component, the page itself (in fact) I should be doing something like:

<my-component></my-component>
<p>My Component is returning me {{ ?????? }}

What is the best approach to do such a thing?

danday74
  • 52,471
  • 49
  • 232
  • 283
Marco Jr
  • 6,496
  • 11
  • 47
  • 86
  • 1
    Adding variables to the root scope is a bad practice. Instead Thiery's approach. You create a Repository or Store or Entity service to store your values in. This approach should be followed with AngularJS or Angular2. – Martin Mar 14 '16 at 10:45
  • look at this answer https://stackoverflow.com/a/44266176/4356754 – Mohamed Ali May 30 '17 at 15:26

3 Answers3

64

To implement global variable, you could implement a shared service. You will be able to save data it and all components could have access to them.

For this, simply implement a service and set its provider when boostrapping your application:

bootstrap(AppComponent, [ MySharedService ]);

Be careful not to define it again within the providers attribute of components where you want to use it.

Sample

The service:

export class MySharedService {
  data: any;
  dataChange: Observable<any>;

  constructor() {
    this.dataChange = new Observable((observer:Observer) {
      this.dataChangeObserver = observer;
    });
  }

  setData(data:any) {
    this.data = data;
    this.dataChangeObserver.next(this.data);
  }
}

Use it into a component:

@Component({
  (...)
})
export class MyComponent {
  constructor(private service:MySharedService) {
  }

  setData() {
    this.service.setData({ attr: 'some value' });
  }
}

If you want to notify components that the data were updated you can leverage observable fields into the shared service:

@Component({
  (...)
})
export class MyComponent {
  constructor(private service:MySharedService) {
    this.service.dataChange.subscribe((data) => {
      this.data = data;
    });
  }
}

See this question for more details:

This page on the angular.io website could also interest you:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • I made this ways: my-component and parent component imports/providers/constructor the SharedService. my-component do the setData like you suggested. my parent component had this as constructor: private _shared: SharedlService. To show the data on the parent component, I set this line after the export class statement: tst = this._shared.data; and on the template I placed this expecting to see the data : {{tst | json}} - But it's not showing results after invoke the setData :( SOmething missing in your example ? ty, Thierry ! – Marco Jr Mar 14 '16 at 11:54
  • I updated my answer to give you more details about the way to be notified when data are updated... Feel free to tell if this fixes your issue – Thierry Templier Mar 14 '16 at 14:27
  • This is not working for me. If i set the data through some backend call Kindly provide a plunker – atul mishra Oct 31 '17 at 17:53
  • 5
    What is "dataChangeObserver" a function? @ThierryTemplier – Rafael Reyes Mar 14 '18 at 14:42
  • Missing.., dataChangeObserver: any; – Sreekanth Karini Feb 20 '19 at 13:07
22

In Angular2, the concept of scope is now equivalent to member variables and @Input properties of a component or directive. When they refer to DOM elements, the bindable properties also include those attributes or properties of the DOM element itself.

In Angular1, you could define a scope variable on $rootScope and refer to it within a deeply nested child scope without explicitly passing it into directives because of the prototypical nature of scope inheritance. In Angular2, there is no scope inheritance. If you want to pass data from the parent component's scope to the immediate child scope, you have to do so explicitly though the directive's @Input bindings. For example, <directive [myBinding]="model"></directive>, a model property in the parent component scope is being passed into the child directive's scope through the directive's @Input property called myBinding.

The closest equivalent to $rootScope is @Thierry's answer: using a shared service to retrieve and mutate data, which can be injected into any component through DI. Unlike Angular1, which has a global injector, Angular2 introduces the concept of a hierarchal injector. Each component in the hierarchical chain of components can define it's own injector. In Angular2, the hierarchy of injectors participate in type resolution in a similar way that $scope variables were resolved in Angular1 using $scope inheritance.

Michael Kang
  • 52,003
  • 16
  • 103
  • 135
3

You can implement this by using angular BehaviorSubject and asObservable

Check below example code

Service file

@Injectable()
export class commonService {
    private data = new BehaviorSubject('');
    currentData = this.data.asObservable()

    constructor() { }

    updateMessage(item: any) {
        this.data.next(item);
    }

}

Component 1

Set the data from any component

 constructor(private _data: commonService) { }
 shareData() {
      this.currentValue = this.queryTerm;
      this._data.updateMessage(this.currentValue);
  }

Listen from any component

constructor(private _data: commonService) { }
ngOnInit() {
        this._data.currentData.subscribe(currentData => this.currentValue = currentData)
    }

You can communicate between any component using this way.

More Info and other 7 methods

Prashobh
  • 9,216
  • 15
  • 61
  • 91