UniqueId for autoform hook - meteor

This is probably are a really simple answer, however, I'm stumped. I have a lot of forms on my site. I would like to notify the user that an update form has been saved.
In this instance I'm creating a uniqueId, it's a Q&A form so there can be many question forms on one page. I'm not sure how to use the uniqueId with AutoForm.addHooks(); everything I've tried to date creates global autoform hooks which is not ideal because it affects all the other forms on the site.
Template.answers.helpers({
makeUniqueID: function () {
return "update-each-" + this._id;
},
});
var hooksObject = {
onSuccess: function(formType, result) {
var collectionId = this.docId;
Meteor.call('sendEmail',
collectionId
);
},
};
var answerForm = "update-each-" + this._id;
AutoForm.addHooks('answerForm', hooksObject);
UPDATE
Path: answer.js
var hooksObject = {
onSuccess: function(formType, result) {
var collectionId = this.docId;
Meteor.call('sendEmail',
collectionId
);
},
};
Template.answers.onCreated(function() {
var self = this;
self.autorun(function() {
var id = FlowRouter.getParam('id');
self.subscribe('answers', id);
});
this.formId = "update-each-" + this._id;
console.log("oncreated: ", this.formId);
AutoForm.addHooks(this.formId, hooksObject, true);
});
Template.answers.helpers({
answer: function() {
return Answers.find({"userId": Meteor.userId()});
},
formId() {
/**
* expose the form id we set above to the template
**/
var test = Template.instance().formId;
console.log("test: ", test);
return Template.instance().formId;
},
});
Path: answer.html
{{#each answer}}
{{#autoForm id=formId type="update" collection="Answers" doc=this}}
{{> afQuickField name='answer'}}
<button type="submit">Save changes</button>
{{/autoForm}}
{{/each}}

Updated based on new information from updated post and comment feedback.
The key to this solution is calling AutoForm.addHooks inside your Template's onCreated event. Otherwise, you won't have access to the unique id:
answers.html
<template name="answers">
{{#each answer}}
{{> answerForm this }}
{{/each}}
</template>
answers.js
Template.answers.onCreated(function() {
this.autorun(() => {
var id = FlowRouter.getParam('id');
this.subscribe('answers', id);
});
});
Template.answers.helpers({
answer: function() {
return Answers.find({"userId": Meteor.userId()});
}
});
answer.html
<template name="answerForm">
{{#autoForm id=formId type="update" collection="Answers" doc=this}}
{{> afQuickField name='answer'}}
<button type="submit">Save changes</button>
{{/autoForm}}
</template>
answer.js
Template.answerForm.onCreated(function onCreated() {
/**
* The data._id field is passed in to your template as data
**/
this.formId = "update-each-" + this.data._id;
/**
* Call addHooks with the third option, true, to replace any existing hooks for this form.
* This is because addHooks will run every time an instance of this template is created.
**/
AutoForm.addHooks(this.formId, hooksObject, true);
});
Template.answerForm.helpers({
formId() {
/**
* expose the form id we set above to the template
**/
return Template.instance().formId;
}
});

Related

Meteor Subscribe & Publish with external api

I'm trying to connect my Meteor Subscribe and Publish to my api, the Publish is calling the API and returning the data no problem but I cant seem to load my data on the template.
Below is my code.
boards.js
import './boards.html';
Tracker.autorun(function() {
Meteor.subscribe('getUserBoards');
});
boards.html
<template name="userBoards">
{{#each boards}}
{{this.id}}
{{/each}}
</template>
index.js
if (Meteor.isServer) {
Meteor.publish('getUserBoards', function getBoards() {
var self = this;
try {
var response = HTTP.get(Meteor.settings.private.api.url+'users/'+this.userId+'/boards/');
_.each(response.data.boards, function(item) {
var doc = {
id: item._id,
name: item.name,
urlFriendlyName: item.urlFriendlyName,
access: item.access,
backgroundImage: item.backgroundImage,
products: item.products,
sharedCount: item.meta.shared,
totalProducts: item.meta.totalProducts,
dateAdded: item.meta.dateAdded
};
self.added('boards', item._id, doc);
});
self.ready();
} catch(error) {
console.log(error);
}
});
}
your html template:
<template name="userBoards">
{{#each boards}}
{{this.id}}
{{/each}}
</template>
You need a helper to return a cursor called boards:
js:
Template.userBoards.helpers({
boards(){
return Boards.find();
}
});

this.userId not displaying user

I'm publishing users and a second collection called joboffers. The joboffers collection stores the userIds for employer and candidate. I would like to get the candidate name to display next to the joboffer, for an admin page, however nothing I do seems to work. All of the joboffers display but not the candidate name. In my console I just get object .
Path: publish.js
// publish all jobs for admin to view
Meteor.publish('allJobs', function () {
return JobOffers.find({});
});
Meteor.publish('allUsersWithJobs', function () {
var offers = JobOffers.find({}, {fields: {candidateUserId: 1}}).fetch();
var ids = _.pluck(offers, 'candidateUserId');
options = { fields: {username: 1, emails: 1, "profile.firstName": 1, "profile.familyName": 1 } };
return Meteor.users.find({ _id: { $in: ids } }, options);
});
Path: alljoboffers.js
Template.alljoboffers.onCreated(function() {
Meteor.subscribe("allJobs");
Meteor.subscribe("allUsersWithJobs");
});
Template.alljoboffers.helpers({
alljoboffers: function() {
return JobOffers.find({});
},
candidateName: function() {
console.log(this);
var user = this.userId;
var candidate = (user && user.profile && user.profile.firstName);
return candidate;
},
});
Path: alljoboffers.html
{{#each alljoboffers}}
{{positionTitle}}
{{#with candidateName}}
{{profile.firstName}}
{{/with}}
{{/each}}
You're mixing user id and user object. It's a good idea to create a global helper to help keep a convention on how you manage them. This will help reduce the confusion. For example:
Template.registerHelper('usernameById', function(userId) {
var user = Meteor.users.findOne({_id: userId});
return user && user.profile.firstName;
});
Then in your template:
{{#each alljoboffers}}
{{positionTitle}}
{{usernameById candidateUserId}}
{{/each}}

Meteor publish - subscribe user profile

I'm trying to publish a user profile. I have the following publish function in publish.js:
Meteor.publish("singleProfile", function ( profileId ) {
check(profileId, String);
return Meteor.users.find(profileId, { fields: { _id: 1, services: 1, profile: 1 }});
});
This is my route in router.js:
Router.route('/profile/:_id', {
name: 'profilePage',
template: 'appProfile',
onBeforeAction: function() {
var currentUser = Meteor.userId();
if(currentUser) {
this.next();
} else {
this.render("signin");
}
},
waitOn: function() {
this.response = Meteor.subscribe('singleProfile', this.params._id);
return this.response;
},
action: function() {
this.render('appProfile');
}
});
Question is, how do I access the profile details in the appProfile template? Do I need a template helper defined? Or do I need to modify this code?
You can use a template helper for this:
Template.appProfile.helpers({
users() {
return Meteor.users.find();
}
});
Then in your template:
...
{{#each users}}
{{profile.myProperty}} <!-- Renders the myProperty field of the profile. -->
{{/each}}

Meteor: How can I restrict user on a chat?

Im working on a project and my last task is to implement publish and subscribe to prevent users seeing conversations they were not involved in. We were given an example code and I notice a filter on the router.
Router.route('/chat/:_id', function () {
// the user they want to chat to has id equal to
// the id sent in after /chat/...
var otherUserId = this.params._id;
// find a chat that has two users that match current user id
// and the requested user id
var filter = {$or:[
{user1Id:Meteor.userId(), user2Id:otherUserId},
{user2Id:Meteor.userId(), user1Id:otherUserId}
]};
var chat = Chats.findOne(filter);
if (!chat){// no chat matching the filter - need to insert a new one
chatId = Chats.insert({user1Id:Meteor.userId(), user2Id:otherUserId});
}
else {// there is a chat going already - use that.
chatId = chat._id;
}
if (chatId){// looking good, save the id to the session
Session.set("chatId",chatId);
}
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
I thought the filter should be on publish and then subscribe. Here is what I have now.
My HTML
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each recentMessages}}
{{> message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
{{#if currentUser}}
<form class="new-message">
<input class="input" type="text" name="text" placeholder="type a message here...">
<button class="btn btn-default">Send</button>
</form>
{{/if}}
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="message">
<div class = "container">
<div class = "row">
<div class = "username">
<img src="/{{avatar}}" class="avatar_img" >
{{username}}
said: {{messageText}}
</div>
</div>
</div>
</template>
Server Side
Meteor.startup(function () {
if (!Meteor.users.findOne()){
for (var i=1;i<9;i++){
var email = "user"+i+"#test.com";
var username = "user"+i;
var avatar = "ava"+i+".png"
console.log("creating a user with password 'test123' and username/ email: "
+ email);
Meteor.users.insert({
profile:{username:username, avatar:avatar},
emails: [{address:email}],
services:{
password:{"bcrypt" : "PASSWORD REMOVED"}}});
}
}
});
Meteor.publish("messages", function (userId) {
return Messages.find();
});
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
Meteor.publish("userData", function(){
if(this.userId) {
return Meteor.users.find({_id: this.userId},{
fields: {'other':1, 'things': 1}});
} else {
this.ready();
}
return Meteor.users.find({ "status.online": true })
});
Client Side
Meteor.subscribe("messages");
Meteor.subscribe("userStatus");
Meteor.subscribe("userData");
// set up the main template the the router will use to build pages
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// specify the top level route, the page users see when they arrive at the site
Router.route('/', function () {
console.log("rendering root /");
this.render("navbar", {to:"header"});
this.render("lobby_page", {to:"main"});
});
Router.route('/chat/:_id', function () {
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
///
// helper functions
///
Template.message.helpers({
userName: function() {
var userId = this.userId;
var user = Meteor.users.findOne(userId);
var username = user && user.profile && user.profile.username;
var avatar = user && user.profile && user.profile.avatar;
return {
username: username,
avatar: avatar
}
}
})
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.profile.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
recentMessages: function () {
if (Session.get("hideCompleted")) {
return Messages.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
} else {
return Messages.find({}, {sort: {createdAt: 1}});
}
},
hideCompleted: function () {
return Session.get("hideCompleted");
},
incompleteCount: function () {
return Tasks.find({checked: {$ne: true}}).count();
}
});
Template.chat_page.events({
// this event fires when the user sends a message on the chat page
'submit .new-message':function(event){
console.log(event);
event.preventDefault();
var text = event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
// see if we can find a chat object in the database
// to which we'll add the message
Meteor.call("sendMessage", text);
},
});
Collections
Messages = new Mongo.Collection("messages");
Shared-Methods
Meteor.methods({
sendMessage: function (messageText) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Messages.insert({
messageText: messageText,
createdAt: new Date(),
username: Meteor.user().profile.username,
avatar: Meteor.user().profile.avatar,
});
}
});

How can I route to a users profile page?

I show a list of items and for each item its belongs to a user. I list the item's name, description and the user who created it (by there name). I want to also have a link that goes to the user who created the item. Note: That I also link to an item's page.
Here is what I've done so far:
packages
aldeed:collection2
aldeed:simple-schema
iron:router
aldeed:autoform
useraccounts:iron-routing
accounts-password
accounts-base
useraccounts:core
zimme:active-route
todda00:friendly-slugs
reywood:publish-composite
client/items/listed_item.html
<template name="listedItem">
<a href="{{pathFor 'itemPage'}}">
{{name}}
</a>
<a href="{{pathFor 'profile'}}">
{{usernameFromId user}}
</a>
</template>
client/items/items.html
<template name="items">
<div class="items">
{{#each items}}
{{> listedItem}}
{{/each}}
</div>
</template>
client/subscriptions.js
Meteor.subscribe('items');
Meteor.subscribe('allUsernames');
Meteor.subscribe('users');
client/helpers.js
Template.items.helpers({
items: function() {
return Items.find();
},
});
Template.registerHelper("usernameFromId", function (userId) {
var user = Meteor.users.findOne({_id: this.userId});
return user.profile.name;
});
server/publications.js
Meteor.publish("items", function () {
return Items.find();
});
Meteor.publish("users", function () {
return Meteor.users.find({}, {
fields: { profile: 1 }
});
});
Meteor.publish("allUsernames", function () {
return Meteor.users.find({}, {
fields: { 'profile.name': 1, 'services.github.username': 1 }
});
});
lib/routes.js
Router.route('/items', function () {
this.render('items');
});
Router.route('/users/:_id', {
template: 'profile',
name: 'profile',
data: function() {
return Meteor.users.findOne({_id: this.params._id});
}
});
What this does though is show the items URL for the users URL, so it links to a user who doesn't exist. i.e. items/1234 = users/1234 when theres only users/1 in the system. How can I get it to link to the correct user ID?
use a link with the constructed URL
<template name="listedItem">
<a href="{{pathFor 'itemPage'}}">
{{name}}
</a>
<a href="http://yourdomain.com/users/{{user}}">
{{usernameFromId user}}
</a>
</template>
In this part:
Router.route('/users/:_id', {
template: 'profile',
name: 'profile',
data: function() {
return Meteor.users.findOne({_id: this.params._id});
}
});
you have referenced the route and created a route to a template with the name "profile" but I can't see any template with that name. Is it possible you just forgot to include it here? or that you really don't have that template?
Just making sure.
Try this:
Router.route('/users/:_id', {
template: 'profile',
name: 'profile'
}
In helper you can retrive that record id by this:
Router.current().params._id
I usually use this way:
In the template:
<div class="css-light-border">
{{title}}
</div><!-- / class light-border -->
In the router.js file:
Router.route('/document/:_id', function(){
Session.set('docid', this.params._id);
this.render('navbar', {to: "header"});
this.render('docItem', {to: "main"});
});
Basically here docid is the _id of the document which I want to display. Here is an example of how you pull from your database:
somehelper:function(){
var currentId = Session.get('docid');
var product = Products.findOne({_id:currentId});
return product;
I think it is an easy way because it uses Sessions.

Resources