0

I am using angular 6 to develop my email application, I have a list of mail boxes for users who can click on the link to go to each mail box.

However, when I use component version A to render the list, nothing will happen when click on the router link (no route will be triggered). But version B works as expected. Both version A and version B render the UI properly. I wonder what is happening under the hood, it this is the correct behaviour of getter accessor? Or this is a bug of angular?

Angular version: 6.1.8
Browser: Chrome (desktop) version 69
Node version: v10.7.0
Platform: Mac

component (version A)

import { Component } from '@angular/core';
import { EmailService } from '~/email/services/email.service';

@Component({
    templateUrl: '../views/email.view.html',
})
export class EmailComponent {

    public constructor(private emailService: EmailService) {}

    public get mailboxes(): Mailbox[] {
        return this.emailService.mailboxes;
    }
}

component (version B)

import { Component, OnInit } from '@angular/core';
import { EmailService } from '~/email/services/email.service';

@Component({
    templateUrl: '../views/email.view.html',
})
export class EmailComponent implements OnInit {

    public mailboxes: Mailbox[];

    public constructor(private emailService: EmailService) {}

    public async ngOnInit(): Promise<void> {
        this.mailboxes = this.emailService.mailboxes;
    }
}

service

@Injectable()
export class EmailService {

    public get mailboxes(): Mailbox[] {
        return [
            { name: 'Inbox', icon: 'inbox', link: 'inbox' },
            { name: 'Sent', icon: 'send', link: 'sent' },
            { name: 'Drafts', icon: 'drafts', link: 'drafts' },
            { name: 'Spam', icon: 'report', link: 'spam' },
            { name: 'Trash', icon: 'delete', link: 'trash' },
            { name: 'Archive', icon: 'archive', link: 'archive' },
        ];
    }
}

template

<mat-nav-list>
    <a mat-list-item *ngFor="let mailbox of mailboxes"
        [routerLink]="['mailboxes', mailbox.link]">
        <mat-icon matListIcon>{{mailbox.icon}}</mat-icon>
        <h4 matLine>{{mailbox.name}}</h4>
    </a>
</mat-nav-list>

updates

demo link: https://stackblitz.com/edit/angular-gitter-clsw1d

Jean M.C.
  • 33
  • 6
  • Why not `[routerLink]="['mailboxes', mailbox.link]"`? – jonrsharpe Sep 23 '18 at 14:32
  • @jonrsharpe I have another list similar to this, it works. The only difference of these 2 list is where the data comes from (one is using `getter`, another is not) – Jean M.C. Sep 23 '18 at 14:35
  • Could you expand on what exactly goes wrong - do you see error messages when building or in the console, what markup gets rendered, ...? – jonrsharpe Sep 23 '18 at 14:36
  • @jonrsharpe the point is why `getter` behave differently – Jean M.C. Sep 23 '18 at 14:36
  • @jonrsharpe no any errors on build nor console, event the DOM element is exactly the same. Just nothing is happening when clicking on routerlink. – Jean M.C. Sep 23 '18 at 14:37
  • I tried to reproduce the bug with the getter. But it work as expected..., can you show your router definition ? – xrobert35 Sep 23 '18 at 15:42
  • @xrobert35 I've make a sample https://stackblitz.com/edit/angular-gitter-clsw1d if you click on links, the url won't change. But if you uncomment other code to not using `getter`, the links work. – Jean M.C. Sep 24 '18 at 02:16

1 Answers1

0

Could seem strange at the beginning, but here you are linking 2 getter together and in your service you always return a new Array, so when angular is doing is checking to see if value change it start to go in some infinite loop because values at "never fix" since your array always change reference (this is not the case in the first way you do it). Try to change your service by :

@Injectable()
export class EmailService {

    mailbox = [
            { name: 'Inbox', icon: 'inbox', link: 'inbox' },
            { name: 'Sent', icon: 'send', link: 'sent' },
            { name: 'Drafts', icon: 'drafts', link: 'drafts' },
            { name: 'Spam', icon: 'report', link: 'spam' },
            { name: 'Trash', icon: 'delete', link: 'trash' },
            { name: 'Archive', icon: 'archive', link: 'archive' },
        ];

    public get mailboxes(): Mailbox[] {
        return this.mailbox;
    }
}

And it will work as expected.

xrobert35
  • 2,488
  • 1
  • 16
  • 15