0

i need help in making this "view detail function" work. First, i had the users component which i want to imitate on how it worked. Like you have to access its service when you try to get the specific thing. But the users component is its not from coming from an api. Now, i want to imitate it in my news component which the details is coming from an api. How can i access the specific things details of the news component? I've put the code below both on the users component and news component.Thanks for the help.

user.service.ts

import { User } from './user.model';
import { Subject } from 'rxjs/Subject';
export class UserService {

usersChanged = new Subject<User[]>();

  private users: User[]= [
    new User('Harry', 'James', 99999889),
    new User('Thomas', 'Baker', 99638798)
  ];

  getUsers() {
    return this.users.slice();
  }

  getUser(index: number) {
    return this.users[index];
  }

user-list.component

import { Component, OnInit } from '@angular/core';
import { User } from '../user.model';
import { UserService } from '../user.service';
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {

  users: User[];
  index: number;

  constructor(private userService: UserService, private router: Router, private route: ActivatedRoute) { }

  ngOnInit() {
      this.users = this.userService.getUsers();
      this.userService.usersChanged
      .subscribe(
        (users: User[]) => {
          this.users = users;
        }
      );
  }

  onViewUserDetail(index: number){
    this.router.navigate(['users', index]);
  }

news.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders} from '@angular/common/http';
import 'rxjs/add/operator/map';

@Injectable()
export class NewsService {
    constructor(private httpClient: HttpClient) {
  }

getNews() {
    const authToken = localStorage.getItem('auth_token'); 
    const headers = new HttpHeaders() 
    .set('Content-Type', 'application/json') 
    .set('Authorization', `Bearer ${authToken}`);

    return this.httpClient
      .get('sample/news', { headers: headers })
      .map(
        (response => response));
}


getNewsDetail(index: number) {
    //
  }

news-list.component.ts

import { Component, OnInit } from '@angular/core';
import { NewsService } from '../news.service';
import { Router, ActivatedRoute } from '@angular/router';


@Component({
  selector: 'app-news-list',
  templateUrl: './news-list.component.html',
  styleUrls: ['./news-list.component.css']
})
export class NewsListComponent implements OnInit {
  newslists: any;
  constructor(private newsService: NewsService, private router: Router, private route: ActivatedRoute) { }

  ngOnInit() {

    this.newsService.getNews()
      .subscribe(
        (data:any) => {
          console.log(data);
          this.newslists = data.data.data;
          console.log(this.newslists);
        },
        error => {
          alert("ERROR");
        });
  }

  onViewNewsDetail(id: number){
    console.log(id);
    this.router.navigate(['news', id]);
  }

}
Joseph
  • 7,042
  • 23
  • 83
  • 181

2 Answers2

1

Didn't quite understand what the issue is. You are navigating to detail view onView***Detail() method. If you have defined your routes right, it should go to the respective component. And in that detail component ngOnInit() you can subscribe to the paramMap of the activated route and call the api or get the value from the store, however you want.

ngOnInit() {
        this.paramSubscription = this.route.paramMap
            .switchMap((params: ParamMap) => this.userService.getUser(+params.get('id')))
            .subscribe(
            res => {
                this.user= <User>res;
            },
            err => console.log('error retreiving user detail')
            )

    }

you will have the details in the user property in your detail component, and you can display it however you want it to be.

Update

To get detail for your news, you can create a news store with a behavior subject that will call you service to get all news - the list. your component can call this store as well. This store will expose getter of your private behavior subject which expose it as Observable.

Then you can access the subjects value at ny time by getValue() and don't have to call the api again for any view detail call. See example below:

    @Injectable()
    export class NewsStore {
        private _news: BehaviorSubject<List<News>> = new BehaviorSubject(List([]));

        constructor(
            private newsService: NewsService) {
            this.loadInititalData();
        }

        get news() {
            return this._news.asObservable();
        }

    getNews(id: number): any {
            return this._news.getValue().filter(news=> news.id == id);
        }

loadInititalData() {
        this.newsService.getAll()
            .subscribe(
            res => {
                let news= res;
                this._news.next(List(news))
            },
            err => this.handleError(err, "loadinitialdata")
            );
    }
    }
JayDeeEss
  • 1,075
  • 9
  • 14
  • I don't have issues with the user component. The user is an example which i want to follow. The User doesnt have an api. It just disappears after you refresh the page. my problem is on the news component. It works like this, if you click the news, it displays the news lists. In each newslists, there's a button called "View" which after clicked will display the details of that specific news. The Newslist is from api – Joseph Sep 07 '17 at 13:43
  • so issue is in viewDetail() in the service? – JayDeeEss Sep 07 '17 at 13:45
  • Yes. ViewDetail() of the news component – Joseph Sep 07 '17 at 13:49
  • So can i call the newslist from this NewsStore also because i'm calling the list of news from the service? – Joseph Sep 07 '17 at 13:57
  • yes thats recommended. only store should call the service, rest all components should call the store. You can subscrive to **news** from the store as it's an observable. You can easily use it with async pipe. Just do newsStore.news | async in your component.html, make sure you inject the store in your component.ts http://blog.angular-university.io/how-to-build-angular2-apps-using-rxjs-observable-data-services-pitfalls-to-avoid/ this is a good tutorial – JayDeeEss Sep 07 '17 at 14:00
  • I'll try this. Thanks for this. – Joseph Sep 07 '17 at 14:02
  • sure... how far did you get? whats the issue..? – JayDeeEss Sep 11 '17 at 11:50
  • Sorry i didnt follow what youve said. I didnt have store.ts. I just have service.ts. And i've used subscribe in getting data and cache it in the service file – Joseph Sep 11 '17 at 12:04
  • ok and then you can filter your cached data with the required id for that activated route news id. not sure how are you caching your data in service. thats why i recommended using behavior subjects as they store value on the client and you can get the current value at any time – JayDeeEss Sep 11 '17 at 13:58
0

I did this.

getAllNews() {

    if(this.newslist != null) {
      return Observable.of(this.newslist);
    } 

    else {
      const authToken = localStorage.getItem('auth_token'); 
      const headers = new HttpHeaders() 
      .set('Content-Type', 'application/json') 
      .set('Authorization', `Bearer ${authToken}`);

      return this.httpClient
        .get('samplei/news/', { headers: headers })
        .map((response => response))
        .do(newslist => this.newslist = newslist)
        .catch(e => {
            if (e.status === 401) {
                return Observable.throw('Unauthorized');           
            }

        });
    }
  }


  getNews(id: number) { 
    return this.getAllNews().map((data:any)=> data.data.data.find(news => news.id === id)) 
  }
Joseph
  • 7,042
  • 23
  • 83
  • 181