0

Ok, here's yet another question about how to get a view to reflect data changes.

I have a service and a related component (page-message) which is hosted in the main app component template.

The service exposes an array. Initial data in the array displays, but any changes to the array are not recognized by the view.

I suspect that it may be required to use rx Observable in order to make this work, but I'm not clear on when that is required.

Edit: Here is a working Plunker demonstrating that Observable is not required: https://plnkr.co/edit/2iK9YOwLFfY3EylJn6At?p=preview

What am I missing to get the page-message component HTML view to recognize and render changes to the messageService.pageErrorMessages array?

app.component.html

<page-message></page-message>

app.component.ts snippet to demonstrate I'm providing the services in the app component

@Component({
    moduleId: __moduleName,   // fully resolved filename; defined at module load time
    selector: 'my-app',
    directives: [ROUTER_DIRECTIVES, NavbarComponent, PageMessageComponent],
    templateUrl: "app.component.html",
    providers: [ApiService, MessageService]
})

export class AppComponent {
    ...

message.service.ts

I am using message.service to provide an interface to add/remove messages

import {Injectable} from '@angular/core';

@Injectable()
export class MessageService {
    constructor() {
    }

    pageErrorMessages: Array<string> = new Array();

    addPageError(message: string) {
        this.pageErrorMessages.push(message);
    }
}

page-message.component.html

*This is the component HTML that is not updating correctly *

<div *ngFor="#message of messageService.pageErrorMessages">
    <div class="alert alert-danger">{{message}}</div>
</div>

page-message.component.ts

import {Component} from '@angular/core';
import {MessageService} from "./../services/message.service";

@Component({
    moduleId: __moduleName, 
    selector: __moduleName,
    templateUrl: "page-message.component.html",
    providers: []
})

export class PageMessageComponent {
    constructor(public messageService: MessageService) { }
}

some-other-component.ts

This is where I add an entry to the messages array

submit() {
    this.messageService.addPageError("this is an error");
}
7
  • 1
    Does some-other-component.ts have providers: [MessageService]? If so, then that is your problem... you have two instances of your service. Provide the service once, somewhere higher in your component tree. Commented Aug 12, 2016 at 2:57
  • that's a good question. The original code in the question showed me also providing it in page-message, but I have since removed that, and am only providing the service in app.component.ts. Commented Aug 12, 2016 at 3:19
  • What code calls submit()? If the event that triggers that eventually results in calling submit() is not monkey-patched by Angular, then change detection won't run, hence your view won't update. (You shouldn't need an Observable to get this to work... NgFor will check each item of the array for changes, each time Angular change detection is executed.) Commented Aug 12, 2016 at 15:13
  • Thanks, that's what I was wondering on the observable. Let me dig into this, and maybe I'll create a plnkr to demonstrate. Currently, my submit() was called by a button click so it should be fine in that regard, but maybe there's something else. Commented Aug 12, 2016 at 16:13
  • Thanks again. You are correct - Observable not needed. Here's a plunker: plnkr.co/edit/cXSXVIayCAKQzmZMFCoU?p=preview Bottom line - I'm doing something wrong :) Commented Aug 12, 2016 at 17:05

1 Answer 1

2

Thanks to @Mark Rajcok, who asserted that it is not necessary to use Observable in this case.

I created an updated plunker that demonstrates the scenario in my question working correctly without the use of Observable

View the plunker here: https://plnkr.co/edit/2iK9YOwLFfY3EylJn6At?p=preview

This is the component that displays the messages:

import {Component} from '@angular/core'

import {MessageService} from './messageService'

@Component({
  selector: 'my-messagebar'
  template: `
    <div *ngFor="#message of messageService.messages">{{message}}</div>
  `
})

export class MessagebarComponent {

  constructor(public messageService:MessageService) {
  }

}

I also have this working correctly in my application now, although, unfortunately I can't cite a specific cause. More than likely it's the accumulation of newbie mistakes that confused the situation. I'll leave this question and answer up - maybe the plunker will help someone else.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.