4

I am trying to create a dynamic menu using a json response from server but I am getting this error:

MenuComponent.html:4 ERROR TypeError: Cannot read property 'subscribe' of undefined at MatMenuTrigger.push../node_modules/@angular/material/esm5/menu.es5.js.MatMenuTrigger.ngAfterContentInit

and when I click the buttons it says this:

ERROR TypeError: Cannot read property 'createEmbeddedView' of undefined at ViewContainerRef_.push../node_modules/@angular/core/fesm5/core.js.ViewContainerRef_.createEmbeddedView

I am guessing that buttons can't created because json response is not ready but I don't know how to fix it.

Component.ts

export class MenuComponent implements OnInit {
  branchList: Branches = new Branches(); //read somewhere that I need to initialize, not sure

  ngOnInit(): void {
    this.http.get('http://demo8635782.mockable.io/branches').subscribe((data: any) => {
      if (data === null) {
        console.log('api request returns empty!');
      }
      this.branchList = data;
    });
  }

  constructor(private breakpointObserver: BreakpointObserver, private http: HttpClient) {
  }
}

Template.html

<button mat-button [matMenuTriggerFor]="branchesMenu">Branches</button>
<mat-menu #branchesMenu="matMenu">
  <div *ngFor="let branch of branchList?.branches">
    <button mat-menu-item [matMenuTriggerFor]="branch?.name">{{branch.name}}</button>
  </div>
</mat-menu>

Stackblitz

5
  • the line you're unsure about.. what about changing from branchList: Branches = new Branches(); to branchList: Branches; ? does it change the error? ... also I've never seen a type declared for ngOnInit- there is no need Commented Jul 3, 2018 at 18:59
  • nope, it doesn't change anything, I saw it from here: link Commented Jul 3, 2018 at 19:00
  • Please create an minimal reproducible example, I recommend stackblitz.com Commented Jul 3, 2018 at 19:02
  • @Igor I added the example Commented Jul 3, 2018 at 19:46
  • Interface of returned data must not be similar to interface of branchList, and that is creating error. Commented Jul 3, 2018 at 21:38

3 Answers 3

3

I solved it in this stackblitz I use the correct version of material and angular updating the dependencies, use the observable in the template wrapping the button in a ngIf, also deleted the matMenuTriggerFor of the mat-menu-item and import the BrowserAnimationsModule in the app.module.

Edit for adding subMenu, for it you must create the submenu inside the ngFor iteration.

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

2 Comments

thanks but I need matMenuTriggerFor because I will just create a menu from that json response.
Edit the response adding subMenu
3

You're overcomplicating it. It's just a matter of the return type of HttpClient.get. Apparently it's not returning an Observable, and you'll need to read the docs for the library to see why.

You could also simplify the code a great deal:

export class AppComponent  {
  readonly branches = this.http
    .get('https://demo8635782.mockable.io/branches')
    .pipe(
    map((data) => data as Branches),
    map(({branches}) =>branches),
    shareReplay(),
  );    
  constructor(private http: HttpClient) {}
}


<button mat-button [matMenuTriggerFor]="branchesMenu">Branches</button>
<mat-menu #branchesMenu="matMenu">
 <button mat-menu-item *ngFor="let branch of (branches | async)">{{branch.name}}</button>
</mat-menu>

EDIT: nope, totally wrong. As Daniel Caldera pointed out below, the actual problem was the matMenuTriggerFor of the mat-menu-item.

Other problems:

  1. You need to import BrowserAnimationsModule
  2. You need to import the operators (map, shareReplay)
  3. You need to include the theme in CSS
  4. You shouldn't de-reference an async, as I originally suggested

Here is my working version.

6 Comments

I tried your code but it gives me error about map: Function implementation missing. even though I added "target": "es6", and "lib": [ "es6", "es2017", "es2015", "dom", "esnext" ] to tsconfig.I am new to Typescript and Angular so I don't know how to fix it.
@Cagurtay -- does that mean you figured out your get() problem? I was missing a parenthesis after the word pipe (fixed now), maybe that was doing it.
nope, it give errors for map and replay. stackblitz
Updated the answer.
Thanks, it is working but now I need to find a way to parse that JSON and create nested menu from it, that's why I was using matMenuTriggerFor
|
0

I had similar problem. Made a login to refresh my token. The backend expects token so the request has to be made with a valid token.

Make sure you've valid token in your request.

Review your backend.

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.