How to restart subscription?

Hello everyone,

I have quite painful issue which can’t solve for few days, so hope that community can give me some advice.

I have interface that that allow user to build configuration for pivot table. This configuration is stored in collection which then used by server to generate final report and deliver it back to the client. The problem is to make it work reactive.

I’ve tried few ways to achieve that but nothing works.

The first way was to use custom publication. Which works fine except that I haven’t figured out how to resubscribe to the same publication. In subscription I pass only ID of configuration object that should be used.

The second method was to use Method.call to request new data and manually insert it in local collection, but that doesn’t work either. The createContainer stuck in loop.

I’m sure I’m missing something simple, but if required, I’ll provide some code.

BTW I’m using React and Meteor 1.3

Either of those approaches should work - please provide some code.

Thank you for quick reply.

Here is the first method that use publication:

Publication method:

Meteor.publish('report.data', function (reportId) {
    const report = Reports.findOne(reportId);

    const table = reportGenerator(report);
    if (!table) {
        this.ready();
    }

    // Publish report data
    _.each(table.getAggregatedData(), (row, rowId) => {
        _.each(row, (cell, columnId) => {
            if (cell) {
                this.added('reports.data', Random.id(), {
                    ...cell,
                    report: report._id,
                    rowId,
                    columnId,
                });
            }
        });
    });

    // Publish report demension
    this.added('reports.dimensions', Random.id(), {
        report: report._id,
        maxX: table.maxX,
        maxY: table.maxY,
    });

    this.ready();
});

Container:

export default createContainer(({ report }) => {
    const subscription = Meteor.subscribe('report.data', report._id);

    const data = ReportsData.find({ report: report._id }, {});
    const dimensions = ReportsDimensions.findOne({ report: report._id });

    const loading = !subscription.ready();
    const isEmpty = !loading && _.isEmpty(data);

    return {
        data: loading ? [] : data.fetch(),
        dimensions: loading ? null : dimensions,
        loading,
        isEmpty,
    };
}, Table);

Just to clarify, each time the Report object is changing I need to re-subscribe on the data and re-render table.

This package should help you do what you want.

Not sure if what you want to do is possible without an extension like that but this has worked for me in the past.

2 Likes

Thank you!

I saw this packaged, and I’m little bit worried that it makes all queries reactive by default. I’m not sure how that will affect on the system, but would prefer if only specific queries will be reactive. Did you had any issues with that?

@dimitry How is ‘report’ as passed into this container being updated on the client? Can you provide the parent component to this container and also the relevant code that updates report?

For this pattern in the simplest of examples you need 3 basic components (from outer to inner):
Component 1 - Holds state that feeds a subscription’s arguments
Component 2 - Actually subscribes to the data after being fed Component 1’s state as props
Component 3 - Use the data to render html

Often Component 3 will then be in charge of updating component 1’s state based on user action. What worries me in your code snippet (which is of component 2) is that I see no function passed into ‘Table’ (component 3) that would allow the user to modify the report prop that is passed into component 2.

As far as I can tell, it only makes queries reactive if you wrap them within an autorun within the subscription.