How do I dynamically publish collections via a Meteor method? - asynchronous

I dynamically create collections with this method:
createPlist: function(jid) {
try {
Plist[jid] = new Meteor.Collection(pid);
} catch(e) {
console.log("oops, I did it again");
}
Plist[jid].insert({
...,
...,
public:true,
uid:this.userId
});
}
Then I am wanting to publish these selectively, and I am attempting to do it via a method:
getPlist: function(jid,pid) {
// var future = new Future();
try {
Plist[jid] = new Meteor.Collection(pid);
} catch(e) {
console.log("oops, I did it again");
}
Meteor.publish(pid, function() {
console.log(Plist[jid].find({}));
// future["return"](Plist[jid].find({}));
return Plist[jid].find();
});
// return future.wait();
},
This returns 'undefined' to my Template helper, and returns nothing (i.e. waits forever) using Future.
Any user can log in and create a Plist collection, which can be either public or not. A user can also subscribe to any collection where public is true. The variable jid is passed to the method 'getPlist' from the template. It is stored in the user's Session.
Thanks! I hope I have explained it well enough!
And of course the template:
Template.plist.helpers({
getPlist: function() {
Pl = []
jid = Session.get('jid');
//alert(jid);
pid = "pl_"+jid;
// console.log(pid);
Meteor.call('getPlist', jid, pid, function(err,res) {
console.log(res); //returns undefined
try {
Pl[jid] = new Meteor.Collection(pid);
} catch(e) {
console.log(e);
}
Meteor.subscribe(pid);
// return Pl[jid].find({}).fetch();
});
}

Related

firebase reset password controller

Yesterday my app was launched, Ionic v1, and a few users entered the wrong password and can't log into the app.
The app uses firebase authentication. I have a __refs file that points to the database and have tried numerous things trying to get the reset to work.
I've tried referencing $firebaseAuth, of course my __refs, $firebase then use $firebase.auth()...
I didn't write the authentication of this app so I'm not real sure how it works. I'm hoping that someone can help me.
My reset controller
angular.module('formulaWizard').controller('ResetPasswordCtrl',
function($scope, $ionicLoading, $firebaseAuth, __Refs) {
$scope.user = {
email: ''
};
$scope.errorMessage = null;
var fbAuth = $firebaseAuth(__Refs.rootRef);
$scope.resetPassword = function() {
$scope.errorMessage = null;
$ionicLoading.show({
template: 'Please wait...'
});
fbAuth.sendPasswordResetEmail($scope.user.email)
.then(showConfirmation)
.catch(handleError);
};
function showConfirmation() {
$scope.emailSent = true;
$ionicLoading.hide();
}
function handleError(error) {
switch (error.code) {
case 'INVALID_EMAIL':
case 'INVALID_USER':
$scope.errorMessage = 'Invalid email';
break;
default:
$scope.errorMessage = 'Error: [' + error.code + ']';
}
$ionicLoading.hide();
}
});
My Refs file
angular.module('formulaWizard')
.factory('__Refs', function ($firebaseArray, $firebaseObject) {
// Might use a resource here that returns a JSON arrayf
var ref = new Firebase('https://firebasedatabase.com/');
return {
rootRef: ref,
customers: ref.child('customers'),
}
});
I can't take credit for the answer it was provide by Abimbola Idowu on HackHands.
Since I paid for the answer I thought I would share it with anyone else that might also be stumped by this.
$scope.resetPassword = function() {
$scope.errorMessage = null;
$ionicLoading.show({
template: 'Please wait...'
});
__Refs.rootRef.resetPassword({ email: $scope.user.email }, function(error) {
if (error === null) {
showConfirmation();
} else {
handleError()
}
});
};
This is the __refs service
angular.module('formulaWizard')
.factory('__Refs', function ($firebaseArray, $firebaseObject) {
// Might use a resource here that returns a JSON arrayf
var ref = new Firebase('https://firebasedatabase.com/');
return {
rootRef: ref,
}
});

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 can i save the value in database with meteor?

In meteor framework inside pre-added code, the counter increases every time when it gets clicked. How to save the value using mongodb ?
Create a collection on the server side to persist the data:
Meteor.isServer {
Counter= new Mongo.Collection('Counter');
// Server side method to be called from client
Meteor.methods({
'updateCounter': function (id) {
if(typeof id && id) {
return Counter.update({_id: id}, {$set: {counter: {$inc: 1}}});
} else {
return Counter.insert({counter: 1})
}
}
})
// Publication
Meteor.publish("counter", function () {
Counter.find();
})
}
You can subscribe the data at the client:
Meteor.isClient{
Template.yourTemplateName.created = function () {
Meteor.subscribe('counter');
}
Template.yourTemplateName.heplers( function () {
counter: function () {
return Counter.findOne();
}
})
Template.yourTemplateName.event( function () {
'click #counterButtonIdName': function () {
if(Counter.findOne()) {
Meteor.call('updateCounter', Counter.findOne()._id);
} else {
Meteor.call('updateCounter', null);
}
}
})
}
Html sample
<template name="yourTemplateName">
<span>{{counter}}</span> //area where count is written
</template>
By this way you can achieve a secure server side processing of your data and the count will be persistent until you have data in the database. Also, this way you can learn Meteor's basics.
Just insert it to a collection. Here's an upsert (i.e., update if exists, insert if not) function:
if (Saves.find({_id: Meteor.userId()})){
Saves.update( {_id: Meteor.userId()}, {save: save} )
console.log("Updated saves")
}
else {
Saves.insert(save)
}
If the autopublish package exists, you can simply create a Mongo.Collection and insert this counter into the database:
var myCounter = 5;
var collection = new Mongo.Collection('collection');
collection.insert({counter: myCounter});
Hope this helps.

Mongoose pre.save() async middleware not working on record creation

I am using keystone#0.2.32. I would like to change the post category to a tree structure. The below code is running well except when I create a category, it goes into a deadlock:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* PostCategory Model
* ==================
*/
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true },
parent: { type: Types.Relationship, ref: 'PostCategory' },
parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.scanTree = function(item, obj, done) {
if(item.parent){
PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
if(cats.length){
obj.parentTree.push(cats[0]);
PostCategory.scanTree(cats[0], obj, done);
}
});
}else{
done();
}
}
PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
if (this.isModified('parent')) {
this.parentTree = [];
if(this.parent != null){
this.parentTree.push(this.parent);
PostCategory.scanTree(this, this, done);
}else
process.nextTick(done);
}else
process.nextTick(done); //here is deadlock.
next();
});
PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();
Thanks so much.
As I explained on the issue you logged on Keystone here: https://github.com/keystonejs/keystone/issues/759
This appears to be a reproducible bug in mongoose that prevents middleware from resolving when:
Parallel middleware runs that executes a query, followed by
Serial middleware runs that executes a query
Changing Keystone's autokey middleware to run in parallel mode may cause bugs in other use cases, so cannot be done. The answer is to implement your parentTree middleware in serial mode instead of parallel mode.
Also, some other things I noticed:
There is a bug in your middleware, where the first parent is added to the array twice.
The scanTree method would be better implemented as a method on the schama
You can use the findById method for a simpler parent query
The schema method looks like this:
PostCategory.schema.methods.addParents = function(target, done) {
if (this.parent) {
PostCategory.model.findById(this.parent, function(err, parent) {
if (parent) {
target.parentTree.push(parent.id);
parent.addParents(target, done);
}
});
} else {
done();
}
}
And the fixed middleware looks like this:
PostCategory.schema.pre('save', function(done) {
if (this.isModified('parent')) {
this.parentTree = [];
if (this.parent != null) {
PostCategory.scanTree(this, this, done);
} else {
process.nextTick(done);
}
} else {
process.nextTick(done);
}
});
I think it's a bug of keystone.js. I have changed schemaPlugins.js 104 line
from
this.schema.pre('save', function(next) {
to
this.schema.pre('save', true, function(next, done) {
and change from line 124 to the following,
// if has a value and is unmodified or fixed, don't update it
if ((!modified || autokey.fixed) && this.get(autokey.path)) {
process.nextTick(done);
return next();
}
var newKey = utils.slug(values.join(' ')) || this.id;
if (autokey.unique) {
r = getUniqueKey(this, newKey, done);
next();
return r;
} else {
this.set(autokey.path, newKey);
process.nextTick(done);
return next();
}
It works.

angular service and http request

creating service
myApp.factory('serviceHttp', ['$http', function(http) {
http.get($scope.url).then(function(result){
serviceVariable = result;
}
return serviceVariable;
}
Controller
function appController($scope, serviceHttp){
$scope.varX = serviceHttp;
if(serviceHttp){
// decision X;
} else {
// decision Y;
}
}
view:
input(ng-if='varX') serviceHttp Exist
input(ng-if='!varX') serviceHttp noExist
The above code always shows varX not exist because app installs during http call of service. I want to use angular service to inject variables from server to make decision at time of booting the application.
Try to rewrite factory by this way that returns promise:
myApp.factory('serviceHttp', ['$http', function(http) {
var factory = {
query: function () {
var data = http.get($scope.url).then(function(result){
return result;
},
function (result) {
alert("Error: No data returned");
});
return data;
}
}
return factory;
}]);
From controller:
serviceHttp.query().then(function (result) {
$scope.varX = = result;
}
Here is Demo Fiddle
in demo we used other URL source
If i correct understand you, you should doing it like this:
var app = angular.module('YourModule', []);
app.factory("serviceHttp", function($http) {
var serviceHttp={};
serviceHttp.yourGetRequest = function(yourUrl) {
return $http.get(yourUrl);
};
return serviceHttp;
});
And for example, controller:
var Controller = function($scope,serviceHttp) {
$scope.varX='';
$scope.loading = true;
var returnArr = serviceHttp.yourGetRequest($scope.url).success(function(dataFromServer) {
$scope.loading = false;
$scope.varX = dataFromServer;
})
};
in view you can use ng-show, like this:
<div ng-show="loading" class="loading"><img src="../styles/ajax-loader-large.gif"></div>
When your application start loading, $scope.loading = true and this div shown, and when you get response from server $scope.loading became false and div doesn't show.

Resources