Trygve
Trygve

Reputation: 621

Updating a template with a component input

Preface: I'm new to Meteor, Angular, and Typescript, so there is a very real possibility of an XY problem somewhere in here.

I'm working on a simple project management app using Meteor and Angular 2 (using the angular2-meteor package) where the structure (for now) consists of projects which have events. One view is a list of projects. Clicking on a project shows a modal of the project's details, including a list of the project's events. So, three components: ProjectList, ProjectDetails, and ProjectEventsList. ProjectDetails uses a Session variable to know which project to show, and that works. However, the list of events in the modal doesn't update after it is created for the first project clicked on.

ProjectEventsList.ts

import {Component, View} from 'angular2/core';
import {MeteorComponent} from 'angular2-meteor';

import {ProjectEvents} from 'collections/ProjectEvents';


@Component({
    selector: 'projectEventsList',
    inputs: ['projectId']
})

@View({
    templateUrl: '/client/projectEventsList/projectEventsList.html'
})

export class ProjectEventsList extends MeteorComponent {
    projectEvents: Mongo.Cursor<ProjectEvent>;

    projectId: string;

    constructor() {
        super();

        this.subscribe('projectEvents', this.projectId, () => {
            this.autorun(() => {
                this.projectEvents = ProjectEvents.find({projectId: this.projectId});
            }, true);
        });
    }
}

As I understand it (though I may be way off here), I'm having difficulty getting autorun to, well, automatically run. I've tried putting a getter and setter on projectId and it does get updated when I click on a project, but the code inside autorun doesn't run after the first click. Things I've tried:

If this all seems like it should work, I'll create a small test case to post, but I am hoping that something in here will be obviously wrong to those who know. Thanks!

Upvotes: 1

Views: 128

Answers (2)

Trygve
Trygve

Reputation: 621

I eventually got the setter method working, as shown below. It feels clunky, so I'm hoping there's a cleaner way to do this, but the below is working for me now (i.e., the list of events is updated when the parent component (ProjectList) sends a new projectId to the input.

ProjectEventsList.ts

import {Component, View} from 'angular2/core';
import {MeteorComponent} from 'angular2-meteor';

import {ProjectEvents} from 'collections/ProjectEvents';


@Component({
    selector: 'projectEventsList',
    inputs: ['projectId']
})

@View({
    templateUrl: '/client/projectEventsList/projectEventsList.html'
})

export class ProjectEventsList extends MeteorComponent {
    projectEvents: Mongo.Cursor<ProjectEvent>;

    set projectId(id: string) {
    this._projectId = id;

    this.projectEventsSub = this.subscribe('projectEvents', this._projectId, () => {
        this.projectEvents = ProjectEvents.find({projectId: this._projectId}, {sort: { startDate: 1 }});
    }, true);
}

get projectId() {
    return this._projectId;
}

    constructor() {
        super();

        this.subscribe('projectEvents', this.projectId, () => {
            this.projectEvents = ProjectEvents.find({projectId: this.projectId});
        }, true);
    }
}

Upvotes: 0

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657308

this.subscribe() and this.autorun() doesn't seem to be part of the Angular component class. If this is an external library you might need to explicitly run it in an Angular zone for change detection to work:

constructor(private zone: NgZone) {
  this.subscribe('projectEvents', this.projectId, () => {
        this.autorun(() => {
            zone.run(() => {
              this.projectEvents = ProjectEvents.find({projectId: this.projectId});
            });
        }, true);
    });
 }

If you want to subscribe to events fired from the component itself use host-binding

@Component(
  {selector: 'some-selector',
  host: {'projectEvents': 'projectsEventHandler($event)'}
export class SomeComponent {
  projectsEventHandler(event) {
    // do something
  }
}

Upvotes: 1

Related Questions