I've written code for a website which allows you to login and chat with other users. The root page has a list of the users you can chat to. Here's the code:
<!-- Top level template for the lobby page -->
<template name="lobby_page">
{{> available_user_list}}
</template>
<!-- display a list of users -->
<template name="available_user_list">
<h2 class="cha_heading">Choose someone to chat with:</h2>
<div class="row">
{{#each users}}
{{> available_user}}
{{/each}}
</div>
</template>
<!-- display an individual user -->
<template name="available_user">
<div class="col-md-2">
<div class="user_avatar">
{{#if isMyUser _id}}
<div class="bg-success">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}} (YOU)</div>
</div>
{{else}}
<a href="/chat/{{_id}}">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}}</div>
</a>
{{/if}}
</div>
</div>
</template>
and the helper functions:
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.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
I've written publish/subscribe code for Chats collection but that's for when you click on one of the users and sends them a message. Now that I've removed autopublish, in the root page, the user can't see any other users to click on. Can someone please help with this issue?
Meteor.users will only publish the current users profile if autopublish is removed.
Add the below publish to your server code:
Meteor.publish(null, function () {
if (!this.userId) return this.ready();
return Meteor.users.find({});
});
A null publish will be auto-published and auto-subscribed by the client if autopublish is removed.
Also, remember to include only those fields that are not sensitive. For, Eg. you might want to omit the password field or the services field.
Something like this:
Meteor.users.find({}, {
fields: {
profile : 1,
emails : 1
}
});
Related
The user can only delete a post if he was the one who posted it.However a user can see all the posts.The javascript code is:
var postedBy = Meteor.user();
var currentPost = this._id;
Posts.insert({
name:postName,
createdAt:new Date(),
postId:currentPost,
postedBy:postedBy
});
The HTML code is:
<template name="posts">
{{#if currentUser}}
{{> addPost}}
<ul>
{{#each post}}
<li>{{> postItem}}</li>
{{/each}}
</ul>
{{/if}}
</template>
<template name="postItem">
<li>
<h4>{{name}}</h4>
<i>Posted by {{postedBy.username}} on {{createdAt}}</i>
[Delete]
</li>
</template>
<template name='addPost'>
<input type='text' placeholder='Add post here' name='postName' id ='myinput'>
<button class="btn btn" type="button" id='btn'>Post</button>
</template>
Both currentUser.username and postedBy.username are displaying the names of the logged in user and the user who posted a particular post respectively.
I am trying to work with the Delete anchor tag.
{{#if currentUser.username==postedBy.username}}
[Delete]
{{/if}}
But it shows error in command prompt.I know it is wrong but I can't think of any other way.How do i write this 'if' statement to check if the current user was the one who posted this post?
Please help as I am new to Meteor.Sorry for bad English.
You can't use arbitrary JavaScript expressions in spacebars. Add a helper like this:
Template.postItem.helpers({
canDelete: function (){
return Meteor.user().username === this.postedBy.username;
}
});
Which you can then use in your template like this:
{{#if canDelete}}
Delete
{{/if}}
Also note, instead of copying the user object into each post, the recommended way is to store the user's id in postedBy.
Here's the relevant code template code:
<!-- display a list of users -->
<template name="available_user_list">
<h2 class="cha_heading">Choose someone to chat with:</h2>
<div class="row">
{{#each users}}
{{> available_user}}
{{/each}}
</div>
</template>
<!-- display an individual user -->
<template name="available_user">
<div class="col-md-2">
<div class="user_avatar">
{{#if isMyUser _id}}
<div class="bg-success">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}} (YOU)</div>
</div>
{{else}}
<a href="/chat/{{_id}}">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}}</div>
</a>
{{/if}}
</div>
</div>
</template>
<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 messages}}
{{> chat_message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form class="js-send-chat">
<input class="input" type="text" name="chat" placeholder="type a message here...">
<button class="btn btn-default">send</button>
</form>
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="chat_message">
<div class="chat-message">
{{> avatar user=user size="small" shape="circle"}} <div class="chat-center">{{user}}: {{text}}</div>
</div>
</template>
and the template helpers:
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.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
messages:function(){
var chat = Chats.findOne({_id:Session.get("chatId")});
return chat.messages;
},
other_user:function(){
return ""
},
})
Template.chat_message.helpers({
user: Meteor.user()
})
I'm making an website where users can log in and chat with each other. I've downloaded the utilities:avatar package to show the avatars of the users. The avatar image is based on the first initial of the username of the user. When I render the avatar template in the template available_user with the code {{> avatar user=this shape="circle"}}, it shows the initials in the avatars fine because it's with the context of the users collection.
I also want to show the avatar when a user sends a message but the template chat_message is within the data context of an array inside the chats collection. So it only shows the default avatar without the initial.
the documentation for the package doesn't quite specify how I can set the template parameter for user or userId. Can someone please help with this issue?
I figured it out. I included the user id into each object in the messages array under the field userId and in the template I set it as {{> avatar userId=userId size="small" shape="circle"}}
I have a list of users generated with ng-repeat and data from db, which works fine. Now when you click on a user, you get a popup box. I would like to display the name of the selected user in this popup box, but I don't know how to access the username because the ng-repeat does not take place in the popup box.
Note that I work with angular material
Part of my html code:
<!-- START SIDEBAR -->
<div id="logo-wrap">
<img id="logo" src="assets/images/logo2.png" alt="Zazzle Logo" >
</div>
<div id="sidebar" class="md-whiteframe-z4" ng-data-color="">
<div style="height: 80px;"></div>
<div class="userList" id="usrL">
<li id="customLI" ng-repeat="user in users" id="userPos" class="active circular md-whiteframe-z2" style="background-color: {{ user.color }} " ng-click="showPopUpDeletionConfirmation($event, user._id); " ng-data-id="{{ user._id }}">
<div ng-if="user._id==activeUser" class="wrapperImageCurrentUser" id="marker_active_user"> </div>
<p class="initials" id="userValue" style="top: {{ user.top }};" >
<custom id="user._id"></custom>
{{user.initials}}
<!-- {{user.email}} -->
</p>
<md-tooltip>{{user.name}}</md-tooltip>
</li>
</div>
</div>
<!-- END SIDEBAR -->
The code for the popup box (html) resides in the file dialog1.tmpl. This file is just the layout of the popup box nothing relevant to share the code in this question
Here is a visual of my user list and popup box -> https://gyazo.com/694f65c5269cbca910ec6989ee5a77c2
You don't access the user in the popup, you pass the user to the popup.
You are already sending the users id, just send the entire user. Use user.name and user._id after you've send it.
Change this:
ng-click="showPopUpDeletionConfirmation($event, user._id);"
to this:
ng-click="showPopUpDeletionConfirmation($event, user);"
and access user object in the popup
EDIT:
You need also to change the showPopUpDeletionConfirmation with this:
$scope.showPopUpDeletionConfirmation = function (ev, user) {
$mdDialog.show({
controller: 'DialogDeleteUserController',
templateUrl: 'confirmDeletion.tmpl.html',
//parent: angular.element(document.body),
locals: {
userId: user._id,
selectedUser: user.name,
},
targetEvent: ev,
hasBackdrop: false,
})
.then(function (result) {
if (result) {
$scope.users = _.filter($scope.users, function (user) {
return user._id !== userId;
})
}
});
}
And then you can access the entire user object in the popup template with $scope.selectedUser or something like {{selectedUser.name}}
I'm building an app with two views: home & view list
When the user clicks on a list's name on the home view, it should change to the "view list" template. I've added a session variable called 'view', setting it to 'home' on startup. When a click event is detected on one of the items (list name) on the home screen, it changes the value of view to 'viewList'. Then in the HTML, I have an if statement to show the home template if 'view' is 'home', otherwise show the 'viewList' template.
I can tell the first part works because I'm outputting the value of 'view' and it does output the value "viewList" when you click on a list name, it just doesn't change the template.
What am I missing?
My code:
mylists.js:
Lists = new Mongo.Collection("lists");
if (Meteor.isClient) {
Meteor.startup( function() {
Session.set("view", "home");
});
Template.main.helpers({
view: function () {
return Session.get("view");
}
});
Template.home.helpers({
lists: function () {
return Lists.find({}, {sort: {lastUsed: -1}});
}
});
Template.home.events({
"submit #new-list": function (event) {
var name = event.target.listName.value;
Lists.insert ({
name: name,
createdAt: new Date(),
lastUsed: new Date()
});
},
"click .list-row": function (event) {
Session.set("view", "viewList");
}
});
}
mylists.html:
<head>
<title>My Lists</title>
</head>
<body>
{{> main}}
</body>
<template name="main">
{{view}}
{{#if view "home"}}
{{> home}}
{{else}}
{{> viewList}}
{{/if}}
</template>
<template name="home">
<header>
<h2>My Lists</h2>
</header>
<ul id="lists">
<li>
<form id="new-list">
<input type="text" name="listName" value="My List 1">
<input type="submit" value="Save">
</form>
</li>
{{#each lists}}
{{> list}}
{{/each}}
</ul>
</template>
<template name="viewList">
<header>
<h2>View List</h2>
</header>
<!-- list details will show here -->
</template>
<template name="list">
<li class="list-row" id="{{_id}}">{{name}}</li>
</template>
If you want to change from templates view i suggest you tu install the iron:router package.
run
meteor add iron:router
lester create the routes.js on the /lib folder
now lets do this step by step.
First create 1 template on myAppName/client/views/layout.html
<template name="layout">
{{> yield}}
</template>
and update the routes.js with this code.
Router.configure({
layoutTemplate: 'layout' // here we say that layout template will be our main layout
});
Now on the same routes.js create this 2 routes.
Router.route('/home', function () {
this.render('home');
});
Router.route('/viewList', function () {
this.render('viewList');
});
With this if you navigate to localhost:3000/home or /viewList you will see the html content on there.
NOTES: <header> inside the templates you don't need it.
Now this is just an example because i don't really know whats your main idea here.
you are calling {{#each lists}} inside the home template, so whats the point of having the viewList template?
Now if you want to create individual and dynamic routes for each list you can try this.
Router.map(function () {
this.route('listViews', {
path: '/listViews/:_id',
waitOn: function(){
return Meteor.subscribe('lists')
},
data: function(){
return Lists.findOne({_id: this.params._id});
}
});
});
Now with this, you have dynamic templates for each object on the List collection, if you go to localhost:300/listView/35dwq358ew for example you will get render the listView with some data.
you can do stuff like this inside the template list
<template name="list">
<li class="list-row" id="{{_id}}">{{name}}</li>
<li>Check this List in detail</li>
</template>
and the viewList template will look like this.
<template name="viewList">
<h2>{{title}}</h2>
<!-- list details will show here -->
{{informationAboutList}}
</template>
I'm using meteor.js and playing around with a simple application. I have a form on my page and once submitted the data is inserted into a database. I have a 'feed' of data on the left side of my page which updates when a new entry in the database is submitted, displaying the data. This is basic data at present about countries and populations etc. My question is how to mix a js variable to vary the source of an image file thats loaded in this 'feed' - hopefully explained below.
So, in code, I have this:
<template name="mainLeftCol">
<div class="col-sm-5">
{{> form}}
</div>
</template>
<template name="mainBody">
{{> mainLeftCol}}
<div class="col-sm-7">
{{#each dbEntry}}
{{> formItem}}
{{/each}}
</div>
</template>
and in a js file I have the event code for when the form is submitted:
Template.mainLeftCol.events({
'submit form': function(e) {
e.preventDefault()
var country = $(e.target).find('[id=country]').val()
prefix = country.slice(0,3);
if (prefix === 'Eng') {
console.log("Eng is for England");
}
var spot = {
country: country,
continent: $(e.target).find('[id=continent]').val(),
};
spot._id = Spots.insert(spot);
}
});
The formItems are being displayed using the following template which outputs the 'variables' that were input in the form:
<template name="formItem">
{{#Animate}}
<div class="panel panel-default spot animate">
<div class="panel-heading">
<h5 class="pull-right">{{country}}</h5>
<h4><mark><b>{{continent}}</b></mark></h4>
</div>
<div class="panel-body">
<img src="Eng.png" class="img-circle pull-right">
</div>
</div>
{{/Animate}}
</template>
As you can see in this template I have hardcoded "Eng.png" as the source for the image. What I would like to do is based on the prefix variable which slices the country field is to have the template display a different image (they're flags) based on the country on the template.
How can I mix a JS variable from my events code into the source of the image file in my template code?
Hope this makes sense!
I don't know if i got i right, but if you want to change the image (flag) according to the country try something like this:
Build a Template helper "prefix" which outputs the current country prefix.
Prefix helper:
Template.formItem.helpers({
countryPrefix: function () {
var country = $(e.target).find('[id=country]').val()
return country.slice(0,3);
}
});
In your Template you can now:
<div class="panel-body">
<img src="{{countryPrefix}}.png" class="img-circle pull-right">
</div>