Reputation: 1852
I want to update a simple list based on input into a form field. Right now I have some dummy data setup:
protected comments: any = [
{
"id": "123",
"date": "1511545812",
"author": "rockwcl1",
"message": "This is a message"
},
{
"id": "1232",
"date": "1511545812",
"author": "rockwcl1",
"message": "This is another message"
}
]
getComments() {
return this.comments;
}
addComment(comment: any) {
this.comments.push(comment);
console.log(this.comments);
}
My parent component:
import {Component} from '@angular/core';
import {IonicPage, NavController, NavParams} from 'ionic-angular';
import {Comment} from "../../comments/comment.service";
@IonicPage()
@Component({
selector: 'page-event-discussion',
templateUrl: 'event-discussion.html',
providers: [
Comment
]
})
export class EventDiscussionPage {
event: any;
comments: any;
constructor(public navCtrl: NavController, public navParams: NavParams, private _commentApi: Comment) {
this.event = this.navParams.data.event;
this.comments = this._commentApi.getComments();
}
}
event-discussion.html
<!-- removed some header stuff -->
<ion-content padding>
<comment-thread [comments]="comments"></comment-thread>
</ion-content>
<ion-footer>
<ion-toolbar>
<comment-form></comment-form>
</ion-toolbar>
</ion-footer>
In my parent component, I pull in that dummy data and then pass it to a child:
<comment-thread [comments]="comments"></comment-thread>
comments-thread.ts
import {Component, Input} from '@angular/core';
@Component({
selector: 'comment-thread',
templateUrl: 'comments-thread.html'
})
export class CommentsThreadComponent {
@Input() comments: any[];
constructor () {}
}
comments-thread.html
<ion-item *ngFor="let comment of comments">
<comment [comment]="comment"></comment>
</ion-item>
comment.component.ts
import {Component, Input} from '@angular/core';
import { Comment } from '../comment.service'
@Component({
selector: 'comment',
template: '{{ comment.message }}'
})
export class CommentComponent {
@Input() comment: any;
}
comment-form.ts
import {Component} from '@angular/core';
import {Comment} from '../comment.service';
import {Validators, FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'comment-form',
providers: [
Comment
],
template: `
<form [formGroup]="_commentForm" (ngSubmit)="addComment()" (ngModel)="comments">
<ion-item>
<ion-input
type="text"
placeholder="Write a comment"
formControlName="message"
[(ngModel)]="newComment"></ion-input>
</ion-item>
<button ion-button type="submit" [disabled]="!_commentForm.valid">Submit</button>
</form>
`
})
export class CommentForm {
private _commentForm: FormGroup;
constructor ( private _formBuilder: FormBuilder, private _CommentApi: Comment) {
this._commentForm = this._formBuilder.group({
message: ['', Validators.required],
})
}
addComment() {
this._CommentApi.addComment({
"id": "adsfa",
"date": "1234455543",
"author": "rockwcl1",
"message": this._commentForm.value.message
});
}
}
I only recently started trying to figure out if [(ngModel)]
is what I needed.
So, what's happening right now:
push
ed (I see them using console.log()
I guess I just expected magic - I updated the data so the list would update. What about this do I need to change in order to update the list when I new item is pushed?
[Edit: a link to a youtube video showing the console.log
when a new comment is added: https://www.youtube.com/watch?v=NxHuDbcwvEE]
Upvotes: 0
Views: 87
Reputation: 23533
I've simulated your code (minus the form, since you say the new messages are logging to the console), but it works ok here: Plunker.
So, change detection is working ok as-is.
For reference, here's the Plunker code. Could you please post your complete components in case the problem is within them.
@Component({
selector: 'comment-thread',
template: `
<ul>
<li *ngFor="let comment of comments">
<comment [comment]="comment"></comment>
</li>
</ul>
`
})
export class CommentThreadComponent {
@Input() comments;
}
@Component({
selector: 'comment',
template: '{{ comment.message }}'
})
export class CommentComponent {
@Input() comment;
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="addSomeComment()">Add a message</button>
<comment-thread [comments]="comments"></comment-thread>
</div>
`,
})
export class App {
name:string;
comments: any;
constructor(private _commentApi: Comments) {
this.name = `Angular! v${VERSION.full}`;
this.comments = this._commentApi.getComments();
}
addSomeComment() {
this._commentApi.addComment({message: 'yet another comment'})
}
}
ComponentAPI isn't a singleton
The problem is caused by the provider section in the form component.
@Component({
selector: 'comment-form',
// providers: [
// Comment
// ],
template: `
Essentially, since CommentAPI is holding the data you need it to be a singleton. But, you provide it in EventDiscussionPage
and also in CommentForm
, so Angular makes two instances.
The trick is to provide it once at a higher level than either of it's client components. Generally, app.module.ts
is best.
Upvotes: 1
Reputation: 21
You need to use ChangeDetectorRef Module from @angular/core. You can have a look at the documentation for that here:
Upvotes: 0