I'm following a video tutorial building a contact manager app on Angular Material Design that was designed for version 5 of Angular and Angular Material but I'm using Angular 7.0.4 and Material 7.2.0.
I'm implementing Material tabs with two tabs separating the bio of contacts from notes for those contacts. The first tab properly pulls the correct bio for each but the second tab, the notes tab, doesn't refresh. The second tab will maintain the notes from the last contact of when the browser refreshed no matter which contact is shown. Since it defaults to the first contact, the first contact's notes are shown for every contact.s notes.
Change of Contact & bio is controlled by the following SidNav component:
sidenav.component.ts
import { Component, OnInit, NgZone, ViewChild } from '@angular/core';
import { UserService } from '../../services/user.service';
import { Observable } from 'rxjs/Observable';
import { User } from '../../models/user';
import { Router } from '@angular/router';
import { MatSidenav } from '@angular/material';
const SMALL_WIDTH_BREAKPOINT = 720;
@Component({
selector: 'app-sidenav',
templateUrl: './sidenav.component.html',
styleUrls: ['./sidenav.component.scss']
})
export class SidenavComponent implements OnInit {
private mediaMatcher: MediaQueryList =
matchMedia(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`);
users: Observable<User[]>;
constructor(
zone: NgZone,
private userService: UserService,
private router: Router) {
this.mediaMatcher.addListener(mql =>
zone.run(() => this.mediaMatcher = matchMedia(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`)));
}
@ViewChild(MatSidenav) sidenav: MatSidenav;
ngOnInit() {
this.users = this.userService.users;
this.userService.loadAll();
this.users.subscribe(data => {
if (data.length > 0) this.router.navigate(['contactmanager', data[0].id]);
});
this.router.events.subscribe(() => {
// tslint:disable-next-line:curly
if (this.isScreenSmall())
this.sidenav.close();
})
}
isScreenSmall(): boolean {
return this.mediaMatcher.matches;
}
}
notes.component.ts:
import { Component, OnInit, Input } from '@angular/core';
import { Note } from '../../models/note';
import { MatTableDataSource } from '@angular/material';
@Component({
selector: 'app-notes',
templateUrl: './notes.component.html',
styleUrls: ['./notes.component.scss']
})
export class NotesComponent implements OnInit {
@Input() notes: Note[];
displayedColumns = ['position', 'title', 'date'];
dataSource: MatTableDataSource<Note>;
constructor() { }
ngOnInit() {
this.dataSource = new MatTableDataSource<Note>(this.notes);
}
}
user.service.ts:
import { Injectable } from '@angular/core';
import { User } from '../models/user';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class UserService {
private _users: BehaviorSubject<User[]>;
private dataStore: {
users: User[]
};
constructor(private http: HttpClient) {
this.dataStore = { users: [] };
this._users = new BehaviorSubject<User[]>([]);
}
get users(): Observable<User[]> {
return this._users.asObservable();
}
userById(id: number) {
return this.dataStore.users.find(x => x.id == id);
}
loadAll() {
const usersUrl = 'https://angular-material-api.azurewebsites.net/users';
return this.http.get<User[]>(usersUrl)
.subscribe(data => {
this.dataStore.users = data;
this._users.next(Object.assign({}, this.dataStore).users);
}, error => {
// tslint:disable-next-line:quotemark
console.log("Failed to fetch users");
});
}
}