I have the following route which is working:
Router.route('/', function () {
Meteor.call("get_country", function(error, result){
if(!error){
if(result === null)
Session.setDefault("country", "int");
else{
if(Countries[result] === null)
Session.setDefault("country", "int");
else
Session.setDefault("country", result);
}
Session.setDefault('category', Countries[Session.get("country")]);
Session.setDefault('sources', Categories[Session.get("country")][Session.get("category")]);
}
});
});
However in the console, I get
Route dispatch never rendered. Did you forget to call this.next() in an onBeforeAction?
I don't use onBeforeAction.
Should I pay attention to the warning? How do I fix it?
Pretty sure you need to specify a template to load/render:
Router.route('/', function () {
Meteor.call("get_country", function(error, result){
if(!error){
if(result === null)
Session.setDefault("country", "int");
else{
if(Countries[result] === null)
Session.setDefault("country", "int");
else
Session.setDefault("country", result);
}
Session.setDefault('category', Countries[Session.get("country")]);
Session.setDefault('sources', Categories[Session.get("country")][Session.get("category")]);
}
//Specify template to render
this.render('templateNameForHomeRoute');
});
});
Related
I have this code on my meteor app:
// client side
Template.lead.events({
'submit .insertExternalAccountForm': function (event) {
event.preventDefault();
Session.set('mcsStatus', 'Creating external account ...');
var target = {
code: event.target.code.value,
leadId: event.target.leadId.value,
name: event.target.name.value,
username: event.target.username.value,
password: event.target.password.value,
searchSourceId: event.target.searchSourceId.value,
clientId: event.target.clientId.value,
clientUserId: event.target.clientUserId.value
};
var noFormError = true;
if (target.username.length === 0) {
Session.set("username_error", "Field must not be empty");
noFormError = false;
} else {
Session.set("username_error", null);
}
if (target.password.length === 0) {
Session.set("password_error", "password must not be empty");
noFormError = false;
} else {
Session.set("password_error", null);
}
if (!noFormError) {
return noFormError;
}
Meteor.call('createExternalAccount', target, function (err, res) {
if (err) {
console.error(err);
}
console.log('in meteor call');
Router.go('/' + res.domain + '/' + res.externalId);
});
}
});
//server side
var createExternalAccountSync = function (query, external) {
return models.SearchSources.findOne(query).exec()
.then(function (searchsource) {
external.domain = searchsource.source;
var emr = searchsource.source.split('-');
return models.Organization.findOne({externalId: emr[2]}).exec();
}).then(function (org) {
console.log('after org');
external.organizationId = org._id;
return models.AppUser.findOne({clientId: external.clientId, externalId: external.clientUserId }).exec();
}).then(function (user) {
console.log('after app user');
external.userId = user._id;
external.userIds = [user._id];
return new Promise(function (resolve,reject) {
console.log('saveOrUpdate');
models.ExternalAccount.saveOrUpdate(external, function (err, newE) {
if (err) {
console.error(err)
reject(err);
}
resolve(newE)
});
});
})
.catch(function (e) {
console.error(e);
throw new Meteor.Error(e);
});
};
Meteor.methods({'createExternalAccount': function (data) {
var query = {};
var newExternalAccount = new models.ExternalAccount();
newExternalAccount.username = data.username;
newExternalAccount.password = data.password;
newExternalAccount.externalId = data.username;
newExternalAccount.name = data.name;
newExternalAccount.clientId = data.clientId;
newExternalAccount.clientUserId = data.clientUserId;
newExternalAccount._metadata = { leadId: data.leadId };
if (data.code === 'f') {
query.searchSourceId = '5744f0925db77e3e42136924';
} else {
query.searchSourceId = data.searchSourceId;
}
newExternalAccount.searchSourceId = query.searchSourceId;
console.log('creating external account')
createExternalAccountSync(query, newExternalAccount)
.then(function (external) {
console.log('should return to meteor call');
return external;
})
.catch(function (e) {
console.error(e);
throw new Meteor.Error(e);
});
}
});
The problem that I'm having is that the code on the server side, while it's being called properly, is not triggering the client side meteor.call, there's no console.log output or anything. I believe that the Meteor.wrapAsync method is properly used, but still not showing anything on the client side, and not in fact redirecting where I want the user to go after form submission.
UPDATE
The code has being updated to the newest form, but now I'm getting a weird error on the client, and its actually because the meteor.call method on the template returns neither error or result
Exception in delivering result of invoking 'createExternalAccount': http://localhost:3000/app/app.js?hash=c61e16cef6474ef12f0289b3f8662d8a83a184ab:540:40
http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:1105:27
_maybeInvokeCallback#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3557:21
receiveResult#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3577:30
_livedata_result#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:4742:22
onMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3385:28
http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:2736:19
forEach#[native code]
forEach#http://localhost:3000/packages/underscore.js?hash=27b3d669b418de8577518760446467e6ff429b1e:149:18
onmessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:2735:15
dispatchEvent#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:175:27
_dispatchMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1160:23
_didMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1218:34
onmessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1365:28
By the code you provided,it could be because you are calling different method.
You defined 'createAccount' but on client side you are calling 'createExternalAccount'
This Meteor app has the insecure and autopublish removed and accounts-password added.
meteor:PRIMARY> db.users.find({}); also shows the presence of the only user credentials I used.
Invoking Meteor.call('addTasks1',params); throws the error, further checks show Meteor.userId() being null
Why is that and how to fix it? Thanks
update
As per the suggested fix by Stephen Woods;
When I change the method addTasks1 on the server from Meteor.userId() to this.userId, It still throws the error.
///////////////////////////
// both/both.js //
///////////////////////////
Tasks1 = new Mongo.Collection('tasks1');
///////////////////////////
// client/client.js //
///////////////////////////
Template.login.events({
'click #logMe': function() {
var credentials = [$('#id').val(), $('#pin').val()];
Meteor.call('logMeIn', credentials);
}
});
Template.footer.events({
'click button': function () {
if ( this.text === "SUBMIT" ) {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var params = {};
params[inputs[i].name] = inputs[i].value;
Meteor.call('addTasks1', params);
}
}
}
});
///////////////////////////
// server/server.js //
///////////////////////////
Meteor.methods({
logMeIn: function (credentials) {
Accounts.createUser({username: credentials[0], password: credentials[1]});
}
});
Meteor.publish('tasks1', function(){
return Tasks1.find({userId: this.userId});
});
Meteor.methods({
addTasks1: function (doc) {
if (Meteor.userId()) {
Tasks1.insert(doc);
} else {
throw new Meteor.Error("Not Authorized");
}
}
});
You need to log the user in, use Meteor.loginWithPassword(<USERNAME>, <PASSWORD>) on the client side to log a created user in.
Also, addTasks1, your Meteor method, is executing on the server. You want to use this.userId instead of Meteor.userId() on the server.
For example, I have a Posts collection, which has userId indicates this post belongs to whom.
And I have a route like this:
Router.route('/:username/posts', {
waitOn: function(){
return Meteor.subscribe('posts', username); // A
// var user = Meteor.users.find({username: username}); //B
// if(user) {
// return Meteor.subscribe('posts', user._id);
// } else {
// return null; // ???
// }
}
});
And publish
Meteor.publish("posts", function(userId){ // C
check(userId, String);
return Posts.find({userId: userId});
});
Meteor.publish("posts", function(username){ // D
check(username, String);
if(user) {
return Posts.find({userId: user._id});
} else {
return null; // ???
}
});
I'm confused how to handle like GET /notexistusername/posts ??
You can configure a notFoundTemplate for iron-router either globally or on a per-route basis.
Globally:
Router.configure({
layoutTemplate: 'layout',
notFoundTemplate: 'notFound',
loadingTemplate: 'loading'
});
In a specific route (also I've cleaned up your route code):
Router.route('/:username/posts', {
notFoundTemplate: 'notFound',
data: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Posts.find({ userId: userId });
},
waitOn: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Meteor.subscribe('posts', userId);
}
});
Your notFound template would typically be your 404 page.
Also you can simplify your publication to:
Meteor.publish("posts", function(username){
check(username, String);
return Posts.find({username: username});
});
Since if there are no matches the find will return a null cursor and that will tell the route there's no data.
I having trouble to validate a user with a Meteor.call on Router. Only return "undefined" pr
"Exception in delivering result of invoking 'verifyUserRole':
TypeError: undefined is not a function"
Router.route("/admin", function(){
Meteor.call("verifyUserRole", function(error, result){
if(result){
this.render('adminDashboard');
this.layout("adminLayout");
} else {
this.render('adminLogin');
}
})
});
Meteor.methods({
"verifyUserRole" : function(){
if(this.userId){
var user = Meteor.user();
var role = user.profile.role;
if(role == "admin"){
return true;
} else {
Session.set("adminLoginError", "Restrict Area");
return false;
}
}
}});
The value of this is referring to your inner function instead of your outer function. Try the following:
Router.route("/admin", function(){
var self = this;
Meteor.call("verifyUserRole", function(error, result){
if(result){
self.render('adminDashboard');
self.layout("adminLayout");
} else {
self.render('adminLogin');
}
});
});
I have to make a aggregate query to DB when the user click on a button, however I don't know how to return that result back to the client since I'm doing an asynchronous request, this is part of my code:
//Server side
Meteor.startup(function() {
Meteor.methods({
getAllTotals: function (query){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var error = result = match = pipeline = '';
var group = {
$group: {
_id: null,
wall_clock: {
"$sum": "$wall_clock"
},
mem:{
"$sum": "$mem"
},
cpu:{
"$sum": "$cpu"
},
io:{
"$sum": "$io"
},
vmem:{
"$sum": "$vmem"
},
maxvmem:{
"$sum": "maxvmem"
}
}
};
if(typeof query.submission_time !== "undefined"){
match = {"$match": {submission_time: query.submission_time}};
pipeline = [match, group];
}else{
pipeline = [group];
}
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
console.log(result); // <<--- this is OK!
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
return result; // <<--- this is empty
}
});
}
any suggestion? :-)
Short answer:
Solution you can find here:
How to get an async data in a function with Meteor
Detailed answer
using Meteor._wrapAsync
var aggregateTotal = function(callback){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
function (error, result){
if(error){
callback(error);
}else{
callback(null, result);
}
}
);
}
var aggregateTotalsSync = Meteor._wrapAsync(aggregateTotal);
Meteor.methods({
'getAllTotals': function(){
var result;
try{
result = aggregateTotalsSync();
}catch(e){
console.log("getAllTotals method returned error : " + e);
}finally{
return result;
}
}
});
using Futures (meteorPad example)
//Server side
Meteor.startup(function() {
var Future = Npm.require('fibers/future');
Meteor.methods({
getAllTotals: function (query){
var fut = new Future();
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
if(error){
fut.throw(error);
}else{
fut.return(result)
}
},
function (exception){
// caught exception is passed to this callback
fut.throw(exception);
}
)
);
return fut.wait();
}
});
}
Easy but a bit dirty way (but not so much if you think well about your architecture) -> send back the result trough Mongo.
You can even do it without Meteor.methods, with the request creation inserted in the database on the client, an observer on the server that check it and does the async task, and then write back the result in the database.