Issue with multiple subscriptions on one publication - javascript

I have a page that generates a series of post templates, each of which subscribes to a single publication. I'm running into an issue where passing the post ID to my publication does not return any results. Can anyone help me figure out what's wrong?
I have tried using console.log() inside onCreated (both inside and outside of the autorun) to make sure that my IDs are correctly generated and have also tried other query values (such as {$exists:true}) to ensure that my query is working.
// client
CommentSubs = new SubsManager();
Template.post.onCreated(function() {
var self = this;
self.ready = new ReactiveVar();
self.autorun(function() {
var commentParent = this._id;
var handle = CommentSubs.subscribe('comments', commentParent);
self.ready.set(handle.ready());
});
});
// server
Meteor.publish("comments", function (commentParent) {
return Posts.find({commentParent: commentParent}, {sort: {createdAt: 1}});
});
I am new to meteor so perhaps I am missing something that should be obvious.

Related

Meteor.publish on server doesn't show new documents on client

The problem is the next code on server:
Meteor.publish(null , function() {
let events = [];
Groups.find({participants: this.userId}).forEach(function(item) {
events.push(item.latestEvent);
});
return Events.find({_id: {$in: events}});
});
doesn't provide possibility to see new documents on the client > Events.find().fetch()
without reloading the page.
Both collection are in the lib folder:
Groups = new Mongo.Collection('groups');
Events = new Mongo.Collection('events');
I'm pretty sure the issue is in reactive source of data, but still cannot fix it.
Thank You for help!
Yes, you are right: only Events collection is reactive. There is simple way to solve it by using publish-composite package:
Meteor.publishComposite(null, {
find(){
return Groups.find({participants: this.userId});
},
children: [{
find(group){
return Events.find({_id: {$in: group.latestEvent}});
}
}]
});
But this solution has one disadvantage: Groups documents are published as well. So, probably you should exclude some fields from it.

Two-way data binding for a Meteor app

I've built an app that is form-based. I want to enable users to partially fill out a form, and then come back to it at a later date if they can't finish it at the present. I've used iron router to create a unique URL for each form instance, so they can come back to the link. My problem is that Meteor doesn't automatically save the values in the inputs, and the form comes up blank when it is revisited/refreshes. I tried the below solution to store the data in a temporary document in a separate Mongo collection called "NewScreen", and then reference that document every time the template is (re)rendered to auto fill the form. However, I keep getting an error that the element I'm trying to reference is "undefined". The weird thing is that sometimes it works, sometimes it doesn't. I've tried setting a recursive setTimeout function, but on the times it fails, that doesn't work either. Any insight would be greatly appreciated. Or, if I'm going about this all wrong, feel free to suggest a different approach:
Screens = new Meteor.Collection('screens') //where data will ultimately be stored
Forms = new Meteor.Collection('forms') //Meteor pulls form questions from here
NewScreen = new Meteor.Collection('newscreen') //temporary storage collection
Roles = new Meteor.Collection('roles'); //displays list of metadata about screens in a dashboard
//dynamic routing for unique instance of blank form
Router.route('/forms/:_id', {
name: 'BlankForm',
data: function(){
return NewScreen.findOne({_id: this.params._id});
}
});
//onRendered function to pull data from NewScreen collection (this is where I get the error)
Template.BlankForm.onRendered(function(){
var new_screen = NewScreen.findOne({_id: window.location.href.split('/')[window.location.href.split('/').length-1]})
function do_work(){
if(typeof new_screen === 'undefined'){
console.log('waiting...');
Meteor.setTimeout(do_work, 100);
}else{
$('input')[0].value = new_screen.first;
for(i=0;i<new_screen.answers.length;i++){
$('textarea')[i].value = new_screen.answers[i];
}
}
}
do_work();
});
//onChange event that updates the NewScreen document when user updates value of input in the form
'change [id="on-change"]': function(e, tmpl){
var screen_data = [];
var name = $('input')[0].value;
for(i=0; i<$('textarea').length;i++){
screen_data.push($('textarea')[i].value);
}
Session.set("updateNewScreen", this._id);
NewScreen.update(
Session.get("updateNewScreen"),
{$set:
{
answers: screen_data,
first: name
}
});
console.log(screen_data);
}
If you get undefined that could mean findOne() did not find the newscreen with the Id that was passed in from the url. To investigate this, add an extra line like console.log(window.location.href.split('/')[window.location.href.split('/').length-1], JSON.stringify(new_screen));
This will give you both the Id from the url and the new_screen that was found.
I would recommend using Router.current().location.get().path instead of window.location.href since you use IR.
And if you're looking for two way binding in the client, have a look at Viewmodel for Meteor.

java script - using parse.com query with angular ng-repeat

I make a query from parse.com angd get and array of 2 object. Now I want to user ng-reapet('phone in phones') , so I need to convert it to json. I didn't suucess to do it. for some reason, it doesnt see the result as a json.
var Project = Parse.Object.extend("Project");
var query = new Parse.Query(Project);
query.find({
success: function (results) {
var allProjects = [];
for (var i = 0; i < results.length; i++) {
allProjects.push(results[i].toJSON());
}
$scope.phones = allProjects;
//i also tried this : $scope.phones = JSON.stringify(allProjects);
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
Thanks
Not sure if you already figured this out, but I was having a similar issue and found your post. I'm not sure what your HTML looks like, but I ended up using the Parse.Object's get method in my repeater like so:
<ul ng-repeat="list in lists">
<li>
<a ng-href="#/lists/{{list.id}}">{{list.get('title')}}</a>
</li>
</ul>
I also looked into using promises so that the Parse query success callback actually updates the view when you set $scope.phones to the query result. My code is similar to yours but my object is List instead of Project. Here is what mine looks like:
// Define your Parse object
var List = Parse.Object.extend('List');
// Define a function that runs your Parse query. Use an angular promise so that
// the view updates when you set your $scope var equal to the query result
function getList() {
var deferred = $q.defer();
var query = new Parse.Query(List);
query.find({
success: function(results) {
deferred.resolve(results);
},
error: function(error) {
deferred.reject(error.message);
}
});
return deferred.promise;
}
// Call the getList function on load
var promise = getLists();
promise.then(function(lists) {
$scope.lists = lists;
});
So basically, it isn't that Angular doesn't see the response right. You shouldn't have to modify the result from Parse in any way. It's just that you need to use the Parse.Object get method like you would if you were accessing properties of the object, and make sure that you are using a promise so that Angular accesses your query result as it should in the view.
Do not use .get function on Parse in you angular code, its not working any more, plus its not a good idea to change your angular code because your object is three level nested and need a get method.
The proper way is to extend the object and then map the values back to whatever items you need in that class.
Then you can bind in normally to ng-repeat without changing your html code specifically for Parse.
var Game = Parse.Object.extend("Game");
var query = new Parse.Query(Game);
query.find({
success: function(results) {
$scope.$apply(function() {
$scope.games = results.map(function(obj) {
return {points: obj.get("points"), gameDate: obj.get("gameDate"), parseObject: obj};
});
});
},
error: function(error) {
console.log(error);
}
There may be better tools , frameworks to use.
line 188 is the fetch. It automatically loads json for the model into the collection defined at line 47.
Looping over entries in the result from the query on parse is all automated in the framework so that you can save yourself tons of time by learning a relevant framework ( ie backbone ). On backbone/parse you focus on business logic , not manipulating network io and query structures.
'phone in phones' from your question may just be a nested model or nested collection which IMO can be handled by more advanced manipulation of the basic backbone framework.

Underscore function in Backbone acting strangely

I have been working on a Rails app using Backbone on the frontend. It has two models, publication and article. I wrote the following function in the publications backbone router and it supposed to delete the specified publication and all it's related articles. It deletes the publication just fine but I am running into an issue when it comes to deleting the articles. Here is the code:
publications_router.js
delete_publication: function(id){
var publication = new SimpleGoogleReader.Models.Publication({id: id});
publication.fetch();
publication.destroy();
var articles = new SimpleGoogleReader.Collections.Articles();
articles.fetch({
success: function(data){
_.each(data.models, function(item){
if (item.toJSON().publication_id == id) {
console.log(item);
}
});
}
});
}
This works great for printing each item in the console. However, if I change the console.log(item) line to say:
item.destroy();
It will only destroy every other item. Obviously I would like to correct this so the function destroys all the items and not every other one.
Can anybody tell me why this is happening and what we can do to fix it?
First filter out the items you want to destroy.
var tobeDeleted = _.filter(data.models, function(item){
return (item.toJSON().publication_id == id);
});
... and then destroy
_.invoke(tobeDeleted, "destroy");

node.js/javascript/couchdb view to associative array does not seem to work

I am trying to create a webapp on a node/couchdb/windows stack but get terribly stung by what seems to be a lack of experience.
In the database, there is a view that returns all users with passwords. Based on the tutorial for a blog I have tried to access the view through my node code.
Whenever I investigate the structure of the users or users variable, I get an undefined object.
The call to getDatabase() has been tested elsewhere and works at least for creating new documents.
function GetUser(login)
{
var users = GetUsers();
return users[login];
}
function GetUsers() {
var db = getDatabase();
var usersByEmail = [];
db.view("accounts", "password_by_email")
.then(function (resp) {
resp.rows.forEach(function (x) { usersByEmail[x.key] = x.value});
});
//usersByEmail['test'] = 'test';
return usersByEmail;
}
I am aware that both the use of non-hashed passwords as well as reading all users from the database is prohibitive in the final product - just in case anyone wanted to comment on that.
In case something is wrong with the way I access the view: I am using a design document called '_design/accounts' with the view name 'password_by_email'.
Your call to db.view is asynchronous, so when you hit return usersByEmail the object hasn't yet been populated. You simply can't return values from async code; you need to have it make a callback that will execute the code that relies on the result.

Categories