1

In Angular2 hows best to show and hide child components?

I have one parent component and three child components.

By default onInit all child components need to be hidden. And childComponentA needs to show onclick of a button in the parent component.

The flow:

I have a button in childComponentA that needs to show childComponentB on click and childComponentB component has a button that needs to show childComponentC. So like a flow of show and hides.

Hows best to do this?

Possible solution?

I was thinking of creating a service that all the child components subscribe to show and hide. But not sure if its the best solution.

Parent Component HTML:

<section>
   <button (click)="showChildComponentA()"></button>

   <childComponentA></childComponentA>
   <childComponentB></childComponentB>
   <childComponentC></childComponentC>
</section>

2 Answers 2

2

If you want to keep your code clean and maintainable, and not have boolean flags all over the place, it would be best to use a service (maybe called ToggleService) which handles the toggling and checking of whether or not something should be shown.

For instance, here is a simple ToggleService that gives you the ability to create new items, remove the items, and toggle the visibility of the items with show/hide methods (keep in mind nothing below is tested, I literally just wrote it all on the fly for this question -- but it all seems logical and should work):

@Injectable()
export class ToggleService {
    toggleMap: {[uniqueKey: string]: any} = {};

    create(key: string) {
        this.toggleMap[key] = null;
    }

    remove(key: string) {
        delete this.toggleMap[key];
    }

    isShown(key: string): boolean {
        return this.toggleMap[key];
    }

    show(key: string) {
        this.toggleMap[key] = true;
    }

    hide(key: string) {
        this.toggleMap[key] = false;
    }
}

Now in your component, you can leverage the service:

@Component({...})
export class MyComponent implements OnInit, OnDestroy {
    constructor(public toggleService: ToggleService) {}

    ngOnInit() {
        this.toggleService.create('componentOne');
        this.toggleService.create('componentTwo');
        this.toggleService.create('componentThree');
    }

    // Clean up when parent component is destroyed to save memory
    ngOnDestroy() {
        this.toggleService.remove('componentOne');
        this.toggleService.remove('componentTwo');
        this.toggleService.remove('componentThree');
    }
}

In the template:

<button (click)="toggleService.show('componentOne')">Show component 1</button>
<button (click)="toggleService.show('componentTwo')">Show component 2</button>
<button (click)="toggleService.show('componentThree')">Show component 3</button>

<componentOne *ngIf="toggleService.isShown('componentOne')"></componentOne>
<componentTwo *ngIf="toggleService.isShown('componentTwo')"></componentTwo>
<componentThree *ngIf="toggleService.isShown('componentThree')"></componentThree>

Bear in mind that clicking one of the buttons will not hide another button. For that, you may want to create a toggle method which will loop through the entire toggleMap in the service and make everything false, and then set only one thing to true.

I'll leave that last bit as an exercise for you ;)

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

2 Comments

Hi Lansana, I was thinking an observable subject would be better in a service with an object like this {childAVisible: true, etc }
An observable subject in the ToggleService would work equally as well here.
1

I'd go with component based design. In my opinion, event driven design is not cool since it is hard to trace which component interacts with which event publisher.

Stackblitz example

<button (click)="changeFlag(CompFlags.Comp1)">Show comp1 </button>
<br>
<comp1 *ngIf="checkState(CompFlags.Comp1)"  (clicked)="changeFlag(CompFlags.Comp2)"></comp1>
<br>
<comp2  *ngIf="checkState(CompFlags.Comp2)" (clicked)="changeFlag(CompFlags.Comp3)"></comp2>
<br>
<comp3  *ngIf="checkState(CompFlags.Comp3)"></comp3>

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
}) 
export class AppComponent  {
  CompFlags = CompFlags;
  state = CompFlags.None;

  changeFlag(flag:CompFlags){
    (this.state & flag) ? this.state &= ~flag : this.state |= flag;
  }

  checkState(flag:CompFlags){
    return !!(this.state & flag);
  }
}

export enum CompFlags{
  None = 0,
  Comp1 = 1 << 0,
  Comp2 = 1 << 1,
  Comp3 = 1 << 2
}

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.