Meteor with query on publication is not reactive

I have a problem with a meteor publication not being reactive when using a query inside it.

Let's say I have many files, and each file has many projects, so I can go to the route:

http://localhost:3000/file/:file_id/projects

And I would like to both display the projects of the selected file and add new projects to it.

I am currently using angularjs, so the controller would look something like this:

class ProjectsCtrl {
  //some setup
  constructor($scope, $reactive, $stateParams){
  'ngInject'
  $reactive(this).attach($scope)
  let ctrl = this

  //retrieve current file id
  ctrl.file_id = Number($stateParams.file)

  //get info from DB and save it in a property of the controller
  ctrl.subscribe('projects', function(){return [ctrl.file_id]}, function(){
    ctrl.projects = Projects.find({file_id: ctrl.file_id}).fetch()
  })

  //function to add a new project
  ctrl.addProject = function(){
    if(ctrl.projectName){
      Meteor.call('projects.insert', {name: ctrl.projectName, file_id: ctrl.file_id }, function(error, result){
      if(error){
        console.log(error)
      }else{
        console.log(result)
      }
    })
  }
}

} }

The publication looks something like this:

Meteor.publish('projects', function(file_id){
  return Projects.find({file_id: file_id})
})

The problem is that, if I insert a new project to the DB the subscription doesn't run again, I mean the array stays the same instead of displaying the new projects I am adding.

I got many problems with this as I thought that meteor would work something like: "Oh there is a new project, let's re run the query and see if the publication change, if it does, let's return the new matching documents"... but no.

I have not found a problem similar to mine as every question regardind querys inside the publication is about how to reactively change the query (the file_id in this case) but that is not the problem here as I don't change the file_id unless I go to another route, and that triggers a new subscription.

My current solution is to expose the complete collection of projects and make the query using minimongo, but I don't know if it is a good workaround (many projects exposed uses too much memory of the browser, minimongo is not as fast as mongo... etc, I don't really know).

Upvotes: 3

Views: 79

Answers (1)

Ankur Soni
Ankur Soni

Reputation: 6018

Your issue is that the Meteor.subscribe call doesn't know that file_id has changed. There's no reactive relationship between that argument and executing the subscription.

To fix this, whenever you are passing criteria in publish-subscribe, you must write a subscription of Collection inside a tracker.

To know more about trackers, Click here.

While I'm unsure how to do this in Angular, consider this simple Blaze template as an example:

Template.Name.onCreated(function(){
  this.autorun(() => {
    Meteor.subscribe('projects', file_id);
  });
});

Whenever file_id changes, a new subscription is triggered, giving you the desired effect of auto pub-sub utility.

I hope this will give you some insight. It could be easily achieved via Angular JS as well.

Upvotes: 3

Related Questions