4

I have two components on one page: Component1 and Component2. Inside each of those is Component3. Obviously each Component 3 is its own instantiation of the component. However, I would like a global variable between the two. I'm creating a side-by-side comparison of some data, and would like an accordion to work, so when I click to expand the accordion on one Component 3, the other one also opens. I have been searching for hours and cannot find a resolution to this.

What I want is, for instance:

(click) = "changeGlobalVar()"

to change the global variable. Then I would like to have

*ngIf="globalVar"

That way, the ngIf works on both Component 3, no matter which one I click on.

Could someone please help me out? I've been searching for an answer to this for hours.

Here's what my service code looks like but doesn't seem to be working:

import {Injectable} from '@angular/core';

@Injectable()
export class DropDownService {

  public _acDropDownToggle: boolean;

  setValue(val) {
    this._acDropDownToggle = val;
  }

  getValue() {
    return this._acDropDownToggle;
  }

}
3
  • Use a service and inject it in the components. They are singletons so the value will be the same across components. Commented Jul 15, 2016 at 22:10
  • When I use a service, it seems to not be the same variable. I'll update my question with my code in my service. Commented Jul 15, 2016 at 22:11
  • You are probably providing your DropDownService in multiple places, hence you are getting multiple instances of your service (in Angular 2, services are not necessarily singletons). Try only putting DropDownService into the providers array in the component that is above Component1 and Component2. Then each Component3 instance should get a reference to the same/single instance of your service. Commented Jul 15, 2016 at 22:43

4 Answers 4

9

So you are half way there and you need just a few clarifications on how to leverage a service. The service you create should only be inserted as a "provider" in your main component. All child components will use the service as a "Dependency injection", this means the child components will request the service in their constructor method arguments.

For example your primary component will look like this

import {componentStateService} from './componentState.service'
import {ComponentOne} from './component1'
import {ComponentTwo} from './component2'
@Component({
    selector: 'test-app',
    template : `...`,
    providers: [componentStateService],<----
    directives: [ComponentOne,ComponentTwo]
})
export class AppComponent {
    constructor(){}
}

Then the child components (component-one,component-two in my plunker example. For your code you would only apply this to your third component), will have the service injected in through their constructors.

import {componentStateService} from './componentState.service'
@Component({
    selector: 'component-one',
    template : `...`
})
export class ComponentOne extends OnInit {
    private _componentVisible:boolean;
    constructor(private _componentStateService:componentStateService){<----
        this._componentVisible = true;
    }
}

This will ensure that only one instance of your service is created.


The next step is to add an "observable" to your service and then "subscribe" to that observable in your child components.

Here is a plunker that demonstrates exactly what you are looking for. You will need to use the RxJS modules. The plunker shows you how to add this if you are using SystemJS. If you are using the TypeScript compiler to transpile your .ts to .js, you will also need to install RxJS through npm(In the plunker example SystemJS is using a module to transpile).

A good tutorial on Angular 2 Observables can be found here. The tutorial leverages a lot more features than what I use in the plunker but that should be enough to get you started.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! This plnkr really helped me figure it all out.
2

Since the variable ind DropDownService is to be shared between two instances of component 3, the best place to instantiate it would be in the page component.Page Component will be the lowest common ancestor of the two component3 instances

Assuming your component tree is like this :-

             PageComponent
             /          \
            /            \
     Component1          Component2
        /                    \
       /                      \
   Component3                Component3

The best place to provide DropDownService in the providers array will be in the Component Decorator of PageComponent. You should then just inject it in the constructor of Component3. If you specify the service in provider of any of the child components of the Pagecomponent, a new instance will be created again.

Comments

1

Where are you providing the service?

What you really want to do is provide it in app.component.ts That way the same instance is available to all sub componennts.

Are you providing it in both components? If you provide it in both component1 and component2 you will get different instances

Comments

1

try to inject those service in app.component.ts or main.ts only once.

If you inject those in providers of each component , it will create a new scope that is limited to only those component and global variable will not work as expected.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.