0

I have 2 components which are unrelated, navbar and edit-page

In the navbar component I get a list of page titles from a collection, and I use the edit-page component to edit a page title, but since I can always see all the page titles from the navbar component, I want it to be updated as soon as I edit a page title.

How to achieve this without @input and @output ? As far as I understand I should creating some kind of a shared service but I am not sure how to go about it exactly?

pages.service.ts

import { Http } from '@angular/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';

@Injectable()
export class PagesService {

    constructor(private http: Http) { }

    getPages() {
        return this.http.get('http://localhost:3000/pages')
            .map(res => res.json());
    }

    getEditPage(id) {
        return this.http.get('http://localhost:3000/pages/edit-page/' + id)
            .map(res => res.json());
    }

    postEditPage(value) {
        return this.http.post('http://localhost:3000/pages/edit-page/' + value.id, value)
            .map(res => res.json());
    }

}

navbar component

pages: any[];
ngOnInit() {
        this.pagesService.getPages().subscribe(pages => {
            this.pages = pages;
        });
    }

edit-page component

editPage({ value, valid }) {
        if (valid) {
            this.pagesService.postEditPage(value).subscribe(res => {
                if (res == "ok") {
                    this.successMsg = true;
                }

            });
        } else {
            console.log('Form is not valid');
        }
    }

So after the editPage method is executed in the edit-page component I would like the pages property in the navbar component to be updated automatically.

Vojislav Kovacevic
  • 1,385
  • 2
  • 17
  • 28

2 Answers2

1

Use Observables like this.

import { BehaviorSubject } from "rxjs/BehaviorSubject";

export class MyService(){
public someProp  = new BehaviorSubject<string(null);

 }
 
 export class ComponentOne implements OnInit{
     constructor(private service:MyService){
    }
    ngOnInit(){
    //this will set the value of someProp
      this.service.someProp.next('some value')
    }
 
 }
 export class ComponentTwo implements OnInit{
    constructor(private service:MyService){
    }
    ngOnInit(){
        //this will get latest value from someProp
        // also will update when it changes
      this.service.someProp.subscribe(res=>{
      console.log('this is the current value',res)
      })
    
    }
 
 }
 
  • I am using http.get to get the values from a database, can it be used with this approach? I have pasted my current pagesService.ts in my question. – Vojislav Kovacevic Oct 02 '17 at 07:27
  • Ye just add a BehaviorSubject like i showed you call it mode or editMode or w/e make sense to you. subscribe to it and it will change automatically. – Ray Luxembourg Oct 02 '17 at 09:28
  • ok kinda getting there. in my pages.service.ts i have this `public someProp = new BehaviorSubject(null);` . I have kept the name `someProp` so it is easily spotted. Now i am SETTING it in navbar.component.ts inside nginit like so `this.pagesService.getPages().subscribe(pages => { this.pagesService.someProp.next(pages); this.pages = this.pagesService.someProp; });` That works because now to iterate thru it I have to use `pages.value` and not just `pages`, so so far so good. But how do I update it when I update the page title in another component? – Vojislav Kovacevic Oct 02 '17 at 12:27
  • You can see how I am doing the update in the `edit-page` component in my question. – Vojislav Kovacevic Oct 02 '17 at 12:28
  • you just call someProp.next() everytime you want to update it that's all if (res == "ok") { this.successMsg = true;this.service.someProp.next('update...'). } – Ray Luxembourg Oct 02 '17 at 12:32
0

Create a service which returns pages and emit the event using EventEmitter when the pages array is changed. Inject PagesService to both of your NavbarComponent and EditPageComponent.

Make changes in EditPageComponent and update the pages in the PageService and emit the pagesChanged event. Then subscribe to pagesChanged event in your NavbarComponent.

import { EventEmitter } from '@angular/core';
import { pages} from './../shared/pages.model';


export class PageService {

    pagesChanged = new EventEmitter<Pages[]>();

    private pages: Page[] = [
        new Page('PageName1'),
        new Page('PageName2'),
      ];    

      getPages() {
          return this.pages.slice();
      }

      editPage(page: Page) {
        // write you logic to edit the page or pages array.
        // Emit the pagesChanged event.
        this.pagesChanged.emit(this.pages.slice());
      }
}

And Subscribe to pagesChanged event in the NavabarComponent like this.

import { Page} from './../shared/pages.model';
import { PagesService } from './pages.service';
import { Component, OnInit } from '@angular/core';


@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  pages: Page[];

  constructor(private pageService: PagesService) { }

  ngOnInit() {
    this.pages= this.pageService.getPages();
    this.pageService.pagesChanged
      .subscribe(
        (pages: Page[]) => {
          this.pages= pages;
        } 
      )
  }

}

Hope this will solve your problem.

Gavishiddappa Gadagi
  • 1,120
  • 1
  • 16
  • 34