How can I load content into another component with on click event? (Angular 4)

aillense picture aillense · Jan 6, 2018 · Viewed 9.6k times · Source

I have the following problem:

in the sidebar is my menu and I would like if I click on the button kag three new buttons in the component header are loaded (see pic).

I do not know how I can implement it :( Can you give me a tip or example? I realize that this is done with event binding, but how to spend content with a click in another component, I do not know yet. ..

Best regards Andreas

Here is my Dashboard

Answer

Grégory Elhaimer picture Grégory Elhaimer · Jan 6, 2018

There are several available options to solve your problem. For the solution I'll provide, I'm assuming that your right menu and head menus have been both put in your root component.

What I would do is using a resolver which will be linked to your route. This resolver will then update your menu. This implies that your menu has been stored either in a service or in an app state with ngrx. Lets forget ngrx for the moment and lets assume you are using a plain angular service.

By storing your menu's items configuration within a service, you totally detached the control of it from other component. It makes the behavior easier to unit test. It also provides flexibility as your menu can be configured differently without changing an already implemented behavior.

Here is a suggested implementation. I have not tested it but it might bring you a starting path:

Here is the service

export type MenuItems = MenuItem[];

export interface MenuItem {
    label: string;
}

@Injectable()
export class MenuItemsService {

     private $menuItems = new BehaviorSubject([]);

     set menuItems(menuItems: MenuItems){
         this.$menuItems.next(menuItems);
     }

     get menuItemsChanges() {
         return this.$menuItems;
     }
}

Here is the resolver. Don't forget to link it to your route in order to make it executed. Of course, if you want to do it from any other location than a Resolver, then you can call your MenuItemsService the same way.

@Injectable()
export class KAGDetailsResolve implements Resolve<MenuItems[]> {

    menuItems: MenuItems = [
        {
            label: 'My first button'
        },
        {
            label: 'My second button'
        },
    ];

    constructor(private menuItemService: MenuItemsService) {}

    resolve(route: ActivatedRouteSnapshot) {

        this.menuItemService.menuItems = this.menuItems;

        return this.menuItems; // we return it as it is mandatory but that's actually not used in this example
    }
}

And here is the component which will be responsible for displaying the dynamic menu:

// the  component which will render your menu
@Component({
    selector: 'my-dynamic-menu',
    template: `<ul>
                <li *ngFor="menuItem in menuItems | async"> {{ menuItem.label }}</li>
               </ul>`
})
export class MyDynamicMenuComponent implements OnInit{

    $menuItems: Observable<MenuItems>;

    constructor(private menuItemService: MenuItemsService) {}

    ngOnInit(): void {
        this.$menuItems = this.menuItemService.menuItemsChanges;
    }
}

As you can see, it relies on Observable. Moreover, the MenuItem class is very poor but allows you to describes more properties on your item (color, css class, function to trigger on click, any url, etc)