Flowrouter Subscriptions - meteor

This is how my flowrouter looks like,
I tried all three options shown below: but unable to subscribe
import {CompanySettings} from '../imports/api/companysettingsMaster.js';
// And imported the api also..
FlowRouter.route('/', {
name: 'home',
subscriptions: function() {
// 1.
return this.register('companySettings', Meteor.subscribe('companySettings'));
// 2.
this.register('CompanySettings', Meteor.subscribe('companySettings'));
// 3.
return Meteor.subscribe('companySettings');
},
action: function() {
var themeSettings = CompanySettings.findOne({
"companyId": 101
});
if (themeSettings) {
console.log(themeSettings);
var scaleProcess = themeSettings.generalSettings.scaleProcess;
if (scaleProcess == 'retail')
BlazeLayout.render("retailMainLayout", {
content: "homepages"
});
else {
BlazeLayout.render("WSEmainLayout", {
content: "homepages"
});
}
} else {
console.log('no themeSettings');
}
}
});
But, not getting document at the end .. Any suggestions.. Thanks in advance

I got the answer for subscription in flowrouter which is as follows:
FlowRouter.route('/', {
waitOn: function () {
return Meteor.subscribe('companySettings');
},
});
Here companySettings is a name of collection in mongodb

Related

Meteor subscribe is not loading data from the server

I am having difficulties with meteor 1.6. First, I have created a database instance and tried to subscribe in the client. through form, I am able to input the data into my database. But could not retrieve it through the subscribe. can anybody tell me what wrong have I done in my code?
import { Template } from "meteor/templating";
import { Notes } from "../lib/collection";
import { Meteor } from "meteor/meteor";
// import { ReactiveDict } from 'meteor/reactive-dict';
import "./main.html";
/*
Template.body.onCreated(function bodyOnCreated() {
this.state = new ReactiveDict();
Meteor.subscribe("db1");
}); */
Template.Display.helpers({
notes() {
Meteor.subscribe("db1");
return Meteor.call('data');
}
});
Template.body.events({
"click .delete": function() {
Notes.remove(this._id);
},
"submit .formSubmit": function(event) {
event.preventDefault();
let target = event.target;
let name = target.name.value;
Meteor.call("inputs", name);
target.name.value = "";
return false;
},
"click .userDetail": function() {
if (confirm("Delete the user Detail ?")) {
Notes.remove(this._id);
}
}
});
here is the code for publication :
import { Mongo } from 'meteor/mongo';
export const Notes = new Mongo.Collection('notes');
Meteor.methods({
inputs:(name)=> {
if (!Meteor.user()) {
throw Meteor.Error("Logged in");
}
Notes.insert({
name: name,
createdAt: new Date()
});
},
data:()=>{
return Notes.find({});
}
});
Meteor.subscribe("notes"); should be in Template.body.onCreated lifycycle method. you need to write a
publish code seperately and not inside the Meteor.method. see below format,
Meteor.publish('notes', function tasksPublication() {
return Notes.find({});
});
Inside the helper just call the subscribed Collection a below,
Template.Display.helpers({
notes() {
return Notes.find({});
}
});
**NOTE: ** Never use Meteor.call inside the helper method. helpers are reactive and real time.

how to waitOn data ready using iron-router and publish-composite

I have the following route :
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = Meteor.users.find({_id : {$in: group.memberIds}}); ******** ISSUE HERE******
return {
group: group,
members: members,
}; }});
and the following publication :
Meteor.publishComposite('groupPage', function(groupId, sortOrder, limit) {
return {
// return the group
find: function() {
if(this.userId){
var selector = {_id: groupId};
var options = {limit: 1};
return Groups.find(selector, options);
}
else{
return ;
}
},
children: [
{ // return the members
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
}
]}}) ;
Now my issue is that : when the related page renders for the first there is no problems but when i actualize the group Page view the line : var members = Meteor.users.find({_id : {$in: group.memberIds}}); gives me the error : undefined object don't have memberIds property. i guess it's because the subscription is not yet ready when doing group.memberIds , isn't it ? Please a hint.
Thanks.
The data function doesn't wait for the subscription to be ready. Further more, subscriptions in the router are considered an anti-pattern for the most part, and should be done in the template: https://www.discovermeteor.com/blog/template-level-subscriptions/
I would pass to the template the groupId, and then get the group and members in the template, like so:
this.route('groupPage', {
path: '/group/:_groupId',
data: function() {
return {
_groupId: this.params._groupId,
}
}
});
and then in the template file:
Template.groupPage.onCreated(function(){
this.subscribe("groupPage", this.data._groupId);
})
Template.groupPage.helpers({
members(function(){
tempInst = Template.instance()
var group = Groups.findOne({_id: tempInst.data._groupId});
return Meteor.users.find({_id : {$in: group.memberIds}});
})
})
The general pattern of your route and publication are all solid. I suspect it's something simple such as:
There is no group with the _id you're using
You're not logged in when you load the route
Here's a version of your code that guards against the error. Note that the publication executes this.ready() instead of just returning if the user is not logged in.
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = group && Meteor.users.find({_id : {$in: group.memberIds}});
return { group: group, members: members };
}
});
Meteor.publishComposite('groupPage', function(groupId,sortOrder,limit) {
return {
find: function() {
if (this.userId) return Groups.find(groupId);
this.ready()
}
},
children: [
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
]
});

Reactive Data Source in METEOR#1.3-modules-beta.6 and React

I am building a Chat app in Meteor 1.3, ES6 and React.
I have 3 collections:
1. People: Who has an array of conversations that the person are involved.
2. Conversations: That also have the people that are involved.
3. Messages: That has a conversation_id field to relate to second collection.
So I am using reywood:publish-composite package, to manage the reactive joins:
=> Get Conversations for this People (user)
=> Get the Messages of all the Conversations of this user
=> Filter messages according to the conversation selected (a react state)
I am also using the package React-Komposer from Kadira.
This is my code:
// publications.js
Meteor.publishComposite('compositeChat', function (people_id) {
return {
find() {
return Collections.People.find({_id: people_id});
},
children: [
{
find(people) {
return Collections.Conversations.find(
{_id: {$in: people.conversations }},
{sort: {'lastMessage.date': -1}}
);
}
},
{
find(people) {
return Collections.Messages.find(
{conversation_id: {$in: people.conversations }},
{sort: {date: 1}}
);
}
},
{
find(people) {
return Collections.People.find(
{_id: {$in: people.contacts }}
);
}
}
]
};
});
// AppContainer.js
import {composeAll, composeWithTracker} from 'react-komposer';
import AppWrapper from '../AppWrapper.jsx';
import * as Collections from '../../../../lib/collections/collections.js';
function composeChat(props, onData) {
let user;
if (!Meteor.userId()) {
user = 'qXSWv64qKaEPAu5yp';
} else {
user = Meteor.userId();
//console.log('Meteor.userId()', Meteor.userId());
}
const
chatSub = Meteor.subscribe('compositeChat', user);
if (chatSub.ready()) {
const chatData = {
chatLoading:
!chatSub.ready(),
myUserData:
Collections.People.findOne({_id: user}),
myContacts:
Collections.People.find(
{_id: { $ne: user}}, { sort: { name: 1 } }
).fetch(),
myConversations:
Collections.Conversations.find(
{}, { sort: { date: -1 } }
).fetch(),
noConversationContacts:
(function () {
return myFunctions.chat.noConversationContacts(
Collections.People.find(
{_id: { $ne: user}}
).fetch(),
Collections.Conversations.find().fetch()
);
}()),
myMessages:
Collections.Messages.find(
{}, {sort: {'lastMessage.date': -1}}
).fetch(),
myOtherPeople:
(function () {
return myFunctions.chat.getTheOtherPeople(
Collections.Conversations.find().fetch(),
user
);
}()),
unreaded:
(function () {
return myFunctions.chat.countUnreadedMessages(
user,
Collections.Conversations.find().fetch(),
Collections.Messages.find().fetch()
);
}())
};
console.log('chatData', chatData);
onData(null, {chatData});
}
}
export default composeWithTracker(composeChat)(AppWrapper);
The problem is: When new message is added, I am not getting the update in the UI, but the data is there (in Mongo), so if I refresh the page, I get the new messages...
In my previous version of the app (Meteor 1.2) this reactive joins worked perfectly.
What could be wrong?
Does publish-composite package not work with Meteor 1.3?
Does publish-composite can't be used with React-Komposer?
Do I have to mix them in other way?
Is there another option (with or without this packages) to manage reactive joins in Meteor 1.3?
Thanks

iron-router except fails?

So i'm just getting started with iron-router, and I've been building a login system. It works via a .onBeforeAction hook before every route, checking if the user is logged in. However, there are a few routes I want public, so I've added an except option, as per the docs. Except the problem is it doesn't work :( can anybody see why?
Router.route('/new', function () {
name: 'new',
this.render('newComp');
});
Router.route('/c/:_id', {
name: 'compPage',
data: function() { return Comps.findOne(this.params._id); }
});
Router.route('/c/:_id/embed', function () {
name: 'embed',
this.layout('empty'),
this.render('compEmbed', {
data: function () {
return Comps.findOne({_id: this.params._id});
}
});
});
function loginFunction(){
// all properties available in the route function
// are also available here such as this.params
if (!Meteor.user()) {
// if the user is not logged in, render the Login template
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.layout('empty');
this.render('login');
}
} else {
// otherwise don't hold up the rest of hooks or our route/action function
this.next();
}
}
Router.onBeforeAction( loginFunction, {
except: ['embed'] // this aint working
});
The problem seems to be in your route definition, the name param should be in the third param of Router.route(), like this (so your route actually didn't have a name, thus the except:['route.name'] doesn't work):
Router.route('/c/:_id/embed', function () {
this.layout('empty'),
this.render('compEmbed', {
data: function () {
return Comps.findOne({_id: this.params._id});
}
});
}, {
name: 'embed',
});
More info about named routes here: http://eventedmind.github.io/iron-router/#named-routes

Meteor + Iron-Router - how do I update my template's data context in response to events the user generates in my template?

So I have a route that sets my template
Router.route('audit', {
path: '/audit/:audit_id/',
template: 'audit',
data: function() {
if (this.ready()) {
audit_obj = Audits.findOne({_id: this.params.audit_id});
lineitems = LineItems.find(JSON.parse(audit.query));
return {
audit_obj: audit_obj,
lineitems: lineitems
}
}
},
waitOn: function () {
return [
Meteor.subscribe('lineitems', this.params.audit_id),
Meteor.subscribe('audits')
]
}
}
Now, when my user takes certain actions on the page rendered by the audit template, I would like to update the audit object and also update the data context that the page is running with. Is this possible?
Something like:
Template.audit.events({
'click .something-button': function() {
// update the data context for the current audit template.
current_context.audit_obj.something = 'new something';
}
});
Yes:
Router.route('audit', {
path: '/audit/:audit_id/',
template: 'audit',
onRun: function() {
Session.set('audit', Audits.findOne(this.params.audit_id));
Session.set('lineitems', LineItems.find(JSON.parse(audit.query)).fetch());
}
data: function() {
if (this.ready()) {
return {
audit_obj: Session.get('audit'),
lineitems: Session.get('lineitems')
}
}
},
waitOn: function () {
return [
Meteor.subscribe('lineitems', this.params.audit_id),
Meteor.subscribe('audits')
]
}
}
and
Template.audit.events({
'click .something-button': function() {
// update the data context for the current audit template.
Session.set('audit', {..});
}
});
But you'll need to decide how to handle changes that come from the server, and may interfere with changes on the front end. So a better approach might be to leave the first part of the code (router) as is:
Router.route('audit', {
path: '/audit/:audit_id/',
template: 'audit',
data: function() {
if (this.ready()) {
return {
audit_obj: Audits.findOne(this.params.audit_id),
lineitems: LineItems.find(JSON.parse(audit.query))
}
}
},
waitOn: function () {
return [
Meteor.subscribe('lineitems', this.params.audit_id),
Meteor.subscribe('audits')
]
}
}
and just change the front end to update the collection:
Template.audit.events({
'click .something-button': function() {
// update the data context for the current audit template.
Audits.update( this.data.audit_obj._id, {..} );
}
});
Of course, that will update the data on the server, too.

Resources