Shane Loveland
Shane Loveland

Reputation: 527

In Angular 2 how does a component view get updated via a service

I am new to Angular2 and am struggling to get a component view to update via a service.

I want two different page types within my application. One that shows a header with a small logo, and another that doesn't show a header and has a bigger logo.

I have an app-header component directly under the root app component. The app-header component checks an array in the service and uses *ngIf to change what it is showing. I am attaching to route changes so it checks on NavigationStart and updates the value accordingly using a service.

If I hit refresh the view displays correctly, but if I change routes within the application the view app-header component does not update. When I console.log the values I see that the service values and the component class attributes are changing correctly, but within the component view nothing is getting updated. I though maybe I had multiple instances of the service, but I added a random number on the service to check and it's all the same instance.

Here is the Template service:

import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/switchMap';

import { Injectable } from '@angular/core';
import { Template } from './template'

//HANDLE TEMPLATES IN AN ORGANIZED WAY
@Injectable()
export class TemplateService  {

    template: Template = {
        showHeader: true,
        imagePath: "",
        name: Math.random()
    };

    public setShowHeader(value:boolean){
        this.template.showHeader = value;
        console.log(value, this.template.showHeader);//CHECK TO MAKE SURE VALUES MATCH
        console.log("name", this.template.name);//CHECK TO MAKE SURE SAME INSTANCE
    }

    //ALLOW BACKGROUND TO BE MANUALLY SET IF DESIRED - NOT USED FOR NOW
    public setImage(url){
        this.template.imagePath = url;
    }

    //WHEREVER A ROUTE IS DEFINED A PAGE CAN CALL THIS SERVICE AND ADD SPECIFY AS THIS TEMPLATE
    public noHeadRoutes = [];

    public setRandomImage(){
        this.template.imagePath = this.availableImagePaths[Math.floor(Math.random() * this.availableImagePaths.length)];
    }

    //USE THESE IF NO MANUAL IMAGE IS SET
    private availableImagePaths:[string] = [
        "images/home/globe.jpg",
        "images/home/typing.jpg"
    ];

    constructor() {
        this.setRandomImage();
    }

}

Here is the app-header component:

import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { TemplateService, Template } from '../services/template';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-header',
  styles: [
    require('./app-header.scss')
  ],
  template: `
    {{ [(template.showHeader)] }} -- {{ template.name }}
    <header class="header" *ngIf="template.showHeader">
      <nav class="navbar navbar-fixed-top bg-inverse navbar-dark">
        <a class="navbar-brand" Routerlink="/" RouterLinkActive="/">
            <img src="../../images/logo.svg" class="app-logo" />
        </a>
        
        <ul class="nav navbar-nav pull-right">
            <li class="nav-item" *ngIf="authenticated">
                <a class="nav-link" (click)="signOut.emit()" href="#">
                    Sign out
                </a>
            </li>
            <li class="nav-item" *ngIf="!authenticated">
                <a class="nav-link" Routerlink="/login" RouterLinkActive="active">
                    Login
                </a>
            </li>
        </ul>
        
      </nav>
    </header>
    
    <!-- PUT IN A BACKGROUND IMAGE AND ADJUST SPACING -->
    <div *ngIf="!template.showHeader">
        <style type="text/css">
            .hey{font-size:10px;}
            
        </style>
        <div class="big-logo">
            <img src="images/logo.svg" />
        </div>
    </div>
  `
})

export class AppHeaderComponent implements OnInit{

  @Input() authenticated: boolean;
  @Output() signOut = new EventEmitter(false);
  template: Template;

  constructor(private _router: Router, private _ts: TemplateService) {

    this.template = _ts.template;

  }

  ngOnInit(){
    //ALL VIEWS CAN SET A NO HEAD TEMPLATE IF NEEDED. THIS CHECKS AT NAVIGATION START AND SETS THE HEADER
    this._router.events.subscribe( (event) =>{

      if(event instanceof NavigationStart) {

        if(this._ts.noHeadRoutes.includes(event.url)){
          this._ts.setShowHeader(false);
        }

        else{
          this._ts.setShowHeader(true);
        }

      }

    });

  }

}

Upvotes: 0

Views: 336

Answers (1)

Shane Loveland
Shane Loveland

Reputation: 527

So in writing this out and asking this I saw my obvious error, but I haven't seen any other answers about this so I'll still post an answer.

My problem was that the changeDetection was using OnPush and I had not noticed that before. Once that was set to default it behaves as expected.

Upvotes: 1

Related Questions