5

I have a simple Meteor subscription, and I display a loading message while the data is being loaded. But I don't know how to display error message if subscription failed.

export const MyAwesomeComponent = createContainer(() => {
  let sub = Meteor.subscribe('some-data');
  if (!sub.ready()) return { message: 'Loading...'};
  if (sub.failed()) return { message: 'Failed.' }; // How to do this?
  return {
    data: Data.find().fetch()
  }
}, MyInternalRenderComponent);

Problem is, the subscription object doesn't have a failed() method, only a ready() query. How to pass the failure of a subscription as props in a createContainer() method?

I know the Meteor.subscribe method has an onStop callback for this case, but I don't know how to glue it toghether that to pass a property.

aedm
  • 5,596
  • 2
  • 32
  • 36
  • Subscriptions don't have a failed state, they just provide a data set for client database copy. I guess you want to only provide the data if a certain condition is met. If that's the case, check for the condition independently, for example by creating a method. – Hubert OG Apr 15 '16 at 14:43
  • They must have a failed state. What if I mistype the publication name, and there is no such publication? – aedm Apr 15 '16 at 14:58
  • Then the `onStop` callback is called with an error object. – Hubert OG Apr 15 '16 at 15:00
  • Also, if I provide a callback for the subscription, I can catch this error. But since the props depend on the return value of the createComponent function's callback, I can't change the props in the subscribe's callback. – aedm Apr 15 '16 at 15:03

1 Answers1

0

After a lot of researching I managed to get this working and I think it answers your question.

Bear in mind I'm using Meteor 1.6, but it should give you the info to get it working on your side.

On the publication/publish:

  try {
    // get the data and add it to the publication
    ...
    self.ready();
  } catch (exception) {
    logger.error(exception);
    // send the exception to the client through the publication
    this.error(new Meteor.Error('500', 'Error getting data from API', exception));
  }

On the UI Component:

const errorFromApi = new ReactiveVar();

export default withTracker(({ match }) => {
  const companyId = match.params._id;
  let subscription;

  if (!errorFromApi.get()) {
    subscription = Meteor.subscribe('company.view', companyId, {
      onStop: function (e) {
        errorFromApi.set(e);
      }
    });
  } else {
    subscription = {
      ready: () => {
        return false;
      }
    };
  }

  return {
    loading: !subscription.ready(),
    company: Companies.findOne(companyId),
    error: errorFromApi.get()
  };
})(CompanyView);

From here all you need to do is get the error prop and render the component as desired.

This is the structure of the error prop (received on the onStop callback from subscribe):

{
  error: String,
  reason: String,
  details: String
}

[Edit]

The reason there is a conditional around Meteor.subscribe() is to avoid an annoying infinite loop you'd get from the natural withTracker() updates, which would cause new subscriptions / new errors from the publication and so on.

Rafael Leite
  • 147
  • 1
  • 1
  • 13