11

If I pass a service into my main.ts I can access it anywhere without having to call a new provider within my child components. In that service, I have variables that are changing.

Would it be better to send those variables to each child component, grandchild component, ..etc or just call the service in my component to get those variables when I need them?

codef0rmer
  • 10,284
  • 9
  • 53
  • 76
Adam j
  • 391
  • 5
  • 18
  • https://stackoverflow.com/questions/42546443/providing-services-vs-passing-inputs-to-components a duplicate which has a great answer – JFFIGK Oct 21 '18 at 12:54

3 Answers3

10

  • @Input API is used when you have parent-child-grandchild scenario. When you have routing and sibling components , @Input API will not help you everywhere. You have to manage in parent and child, if you want two way communication. Later, over the time it becomes complex to manage.
  • When you have routing and parent-child-grandchild / sibling components, you can go with shared service. If variables are changing in service, you can update component using RXjs library. You have to manage everything in one place and subscribe to observable in component where you plan to use service.
  • So, I according to me shared service is a good solution with Rxjs library. You can make service singleton by injecting it into bootstrap function.

    micronyks
    • 54,797
    • 15
    • 112
    • 146
    • I also used observables in the components. Then I advanced to one shared service holding all data + behavior. I never had to use observables + shared service because anything you update in the shared service is bound to the html like: [routerLink]="['/projects/' + service.id + '/campaign']". Where have you had the need for singleton service + observable??? other sample: when a shared service holds a list of items and all components are bound to this list you just do items.push(item) and every component will right now reflect that change. No observable needed. Its total overhead. – Pascal Feb 06 '18 at 21:19
    • I would also include, that you should **use services**, wherever both, child and parent components **must make changes** to the data **OR** the **data lifetime** should be bigger than the parent and child component. **otherwise, use Inputs** for better **data flow visibility and decoupling** of the child component. – Nicollas Braga May 07 '19 at 09:33
    6

    If I understood the question correctly, we might also need to think of 2 diff aspects associated with these decisions.

    @Input/@Output - Helps make your components independent and Not Tied to any particular service. Assuming it is a pure component, that relies completely on the Input received to produce Output; which is definitive, easily testable, very loosely coupled to the other portions of the application; hence high re-usability is encouraged and easily possible.

    Changing Data of Variables - UI State Management is of supreme importance and is probably very core for Angular 2 apps, to my understanding till date. ngrx/store is the Redux in Reactive world and does this well. In this way we can keep data transformations predictive, testable and the data can be referred back anytime by any service/container components as needed and can be passed in the component chain.

    Divs
    • 1,578
    • 2
    • 24
    • 51
    5

    The @Input and @Output decorators are mainly to share data from parent-child and child-parent respectively - nested components.

    With a shared service and an RxJS, non-nested components can also subscribe to the property and act accordingly when changed. Below is the simple example that emits a new value when this.myService.update() method is called from anywhere within an application:

    // myservice.ts
    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs/Subject';
    
    @Injectable()
    export class MyService {
      wat$: Subject<any>;
    
      constructor() {
        this.wat$ = new Subject();
      }
    
      update() {
        this.wat$.next(new Date().getTime());
      }
    }
    

    Then the component relied on the service can subscribe to and act.

    // mycomponent.ts
    export class MyComponent {
      constructor(private myService: MyService) {
        this.myService.wat$.subscribe((value) => {
           // do something with the new value
        });
      }
    }
    
    codef0rmer
    • 10,284
    • 9
    • 53
    • 76
    • 1
      `EventEmitter` is **only** for `@Output()`s in components and is **not** supposed to be used in services or anywhere else except `@Outputs()`s. Use `Observable` or `Subject` instead. See also http://stackoverflow.com/questions/34376854/delegation-eventemitter-or-observable-in-angular2/34402436#34402436 – Günter Zöchbauer Jul 18 '16 at 05:00
    • @GünterZöchbauer: Thanks for letting me know. I've updated the example above to use RxJS Subject. – codef0rmer Jul 19 '16 at 11:51