template duplicate list items when server re starts - meteor

This code displays items from the MenuItems collection in my app, but during development when the server re-runs, the list gets a new list added to the old "duplicate entries".
I need one list only and not duplicates.
Why is that happening and how to fix it? Thanks
/////////////////////////////////////
// client code
/////////////////////////////////////
<template name="mainMenu">
<div class="container">
<div class="row">
<section class="col-xs-12">
<div class="list-group menuItems">
{{#each menuItems}}
<li data-template="{{menuItem}}" role="presentation">
<a href="#" class="list-group-item menuItem">
<img src="/abc.png">
{{menuItem}} <span class="badge">></span>
</a>
</li>
{{/each}}
</div>
</section>
</div>
</div>
</template>
Template.mainMenu.onCreated(function () {
var template = this;
template.handler = template.subscribe('menuItems');
});
Template.mainMenu.helpers({
menuItems: function () {
return MenuItems.find();
}
});
Template.mainMenu.onDestroyed(function () {
var template = this;
if (template.handler && template.handler.stop) template.handler.stop();
});
/////////////////////////////////////
// server code
/////////////////////////////////////
var items =
[
{menuItem: "task1", group: "ab"},
{menuItem: "task2", group: "ab"},
{menuItem: "task3", group: "b"},
{menuItem: "task4", group: "a"},
{menuItem: "task5", group: "a"},
{menuItem: "task6", group: "a"},
{menuItem: "task7", group: "b"},
{menuItem: "task8", group: "b"},
{menuItem: "task9", group: "b"},
{menuItem: "login", group: "ab"},
{menuItem: "logout", group: "ab"}
]
_.each(items, function (doc) {
MenuItems.insert(doc);
})

_.each(items, function (doc) {
MenuItems.insert(doc);
})
This fragment of code inserts the new bunch of data each server start, so as result your collection grows with each run. You can easily check it if you look at your collection (meteor shell or meteor mongo can help). Wrap it in this construction
if (!MenuItems.find().count()) {
_.each(items, function (doc) {
MenuItems.insert(doc);
})
}

Related

Meteor populate a collection on server start up

This code needs to insert some documents in MenuItems collection at server start up. But the browser console shows it is an empty [].
I have no idea what this _.each mean, just got it off another post.
Why and how to fix it please? Thanks
///////////////////////////
// both/both.js //
///////////////////////////
MenuItems = new Mongo.Collection('menuItems');
///////////////////////////
// server/server.js //
///////////////////////////
Meteor.publish('menuItems', function(){
return MenuItems.find();
});
Meteor.startup(function () {
var items =
[
{menuItem: "task1", login: false},
{menuItem: "task2", login: true},
{menuItem: "task3", login: true},
{menuItem: "task4", login: true},
{menuItem: "task5", login: true},
{menuItem: "task6", login: true},
{menuItem: "task7", login: false},
{menuItem: "task8", login: false},
{menuItem: "task9", login: false},
{menuItem: "login", login: false},
{menuItem: "logout", login: false}
]
_.each(items, function (doc) {
MenuItems.insert(doc);
})
});
///////////////////////////
// client/client.js //
///////////////////////////
Template.mainMenu.helpers({
menuItems: function () {
return MenuItems.find();
}
});
If you removed autopublish package, in your client/client.js file, you need to subscribe to menuItems publication.
///////////////////////////
// client/client.js //
///////////////////////////
Template.mainMenu.onCreated(function () {
var template = this;
template.handler = template.subscribe('menuItems');
});
Template.mainMenu.helpers({
menuItems: function () {
return MenuItems.find();
}
});
Template.mainMenu.onDestroyed(function () {
var template = this;
if (template.handler && template.handler.stop) template.handler.stop();
});
P.S: _.each iterates over the array and call the function the function per each item in the element with the item passed as parameter to the function.

User profile value as a value in collection find query

This code has a collection MenuItems which needs to be filtered according to a value in the logged in user profile,
db.users.find({}); out put is
"profile" : { "menuGroup" : "a" }
but I am getting error:
Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
from the meteor server terminal. The problem line is marked at the end of the code below. Why is the error and how can it be fixed? Thanks
/////////////////////////////////////
// client
/////////////////////////////////////
<template name="mainMenu">
<div class="container">
<div class="row">
<section class="col-xs-12">
<div class="list-group menuItems">
{{#each menuItems}}
<li data-template="{{menuItem}}" role="presentation">
<a href="#" class="list-group-item menuItem">
<img src="/abc.png">
{{menuItem}} <span class="badge">></span>
</a>
</li>
{{/each}}
</div>
</section>
</div>
</div>
</template>
Template.mainMenu.onCreated(function () {
var template = this;
template.handler = template.subscribe('menuItems');
});
Template.mainMenu.helpers({
menuItems: function () {
return MenuItems.find();
}
});
Template.mainMenu.onDestroyed(function () {
var template = this;
if (template.handler && template.handler.stop) template.handler.stop();
});
/////////////////////////////////////
// server code
/////////////////////////////////////
var items =
[
{menuItem: "task1", group: "ab"},
{menuItem: "task2", group: "ab"},
{menuItem: "task3", group: "b"},
{menuItem: "task4", group: "a"},
{menuItem: "task5", group: "a"},
{menuItem: "task6", group: "a"},
{menuItem: "task7", group: "b"},
{menuItem: "task8", group: "b"},
{menuItem: "task9", group: "b"},
{menuItem: "login", group: "ab"},
{menuItem: "logout", group: "ab"}
]
if (!MenuItems.find().count()) {
_.each(items, function (doc) {
MenuItems.insert(doc);
})
}
Meteor.publish('menuItems', function(){
var menuGroup = Meteor.user().profile.menuGroup; //<<<<< problem line
return MenuItems.find({group: menuGroup});
});
I think you need to replace
Meteor.user()
with something like
Meteor.users.findOne({_id: this.userId})
inside publish
...try...
Meteor.publish('menuItems', function(){
if (!this.userId) return null;
var menuGroup = Meteor.users.findOne({_id:this.userId}).profile.menuGroup;
return MenuItems.find({group: menuGroup});
});

Collection insert if empty else update

This code displays a mainMenu with menuItems to click. "Template.mainMenu"
When menuItem is clicked, I need to store the value of the menuItem in a document but if the user clicks a different item, then I need to change the value and not create another document.
The code below is not updating the document with the new menuItem value. Thanks
Tasks = new Mongo.Collection('tasks');
Template.mainMenu.helpers({
menuItems: [
{menuItem: "task1"},
{menuItem: "task2"},
{menuItem: "task3"},
{menuItem: "task4"},
{menuItem: "task5"},
{menuItem: "task6"},
{menuItem: "task7"}
]
});
Template.mainMenu.events({
'click .menuItem': function (event) {
var item = $(event.currentTarget).data('value');
if (Tasks.find().count() === 0) {
Tasks.insert({menuItem: item});
} else {
Tasks.update({_id: item._id} ,{$set: {menuItem: item}});
}
}
});
Upsert will update the id with the new value without inserting a new line. If the id you pass doesn't exist in the db, it will create a new one.
Template.mainMenu.events({
'click .menuItem': function (event) {
var item = $(event.currentTarget).data('value');
Tasks.upsert({_id: item._id} ,{$set: {menuItem: item}});
}
});
More info: http://docs.meteor.com/#/full/upsert
Template.mainMenu.events({
'click .menuItem': function (event) {
var item = $(event.currentTarget).data('value');
Tasks.update({_id: item._id} ,{$set: {menuItem: item}},{upsert : true});
}
});
This is the syntax, hope it will help :)

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.

emberjs router class active

I know i can find examples of this but i cant put it into my code without errors... just dont know why.
I want start with set class="menu-active" to first in menu.
<li><a {{action gotoAbout}} >About</a></li>
And later when somebody click other position of menu move class="menu-active" to this position.
http://jsfiddle.net/kwladyka/LGArM/3/
And the bonus question: Do you have any remarks to make my code better?
HTML
<script type="text/x-handlebars" data-template-name="application">
{{view App.NavbarView}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="navbar">
<div id="menu" class="grid_12">
<ul>
<li><a {{bindAttr class="isAbout:active"}} {{action gotoAbout}} >About</a></li>
<li><a {{bindAttr class="isProjects:active"}} {{action gotoProjects}} >Projekty</a></li>
<li><a {{action gotoTechnology}} >Technologie</a></li>
<li><a {{action gotoContact}} >Kontakt</a></li>
</ul>
</div>
</script>
EMBERJS
$(function() {
console.log("### emberjs start ###");
App = Em.Application.create({
rootElement: '#emberjs-container'
});
App.ApplicationController = Em.Controller.extend();
App.ApplicationView = Em.View.extend({
templateName: 'application'
});
App.NavbarController = Em.Controller.extend({
});
App.NavbarView = Em.View.extend({
templateName: 'navbar',
});
App.AboutView = Em.View.extend({
templateName: 'about'
});
App.ProjectsView = Em.View.extend({
templateName: 'projects'
});
App.TechnologyView = Em.View.extend({
templateName: 'technology'
});
App.ContactView = Em.View.extend({
templateName: 'contact'
});
App.Router = Em.Router.extend({
enableLogging: true,
location: 'hash',
root: Em.Route.extend({
// EVENTS
gotoAbout: Ember.Route.transitionTo('about'),
gotoProjects: Ember.Route.transitionTo('projects'),
gotoTechnology: Ember.Route.transitionTo('technology'),
gotoContact: Ember.Route.transitionTo('contact'),
// STATES
about: Em.Route.extend({
route: '/',
connectOutlets: function (router, context) {
router.get('applicationController').connectOutlet('about');
}
}),
projects: Em.Route.extend({
route: '/projects',
connectOutlets: function (router, context) {
router.get('applicationController').connectOutlet('projects');
}
}),
technology: Em.Route.extend({
route: '/technology',
connectOutlets: function (router, context) {
router.get('applicationController').connectOutlet('technology');
}
}),
contact: Em.Route.extend({
route: '/contact',
connectOutlets: function (router, context) {
router.get('applicationController').connectOutlet('contact');
}
})
})
});
App.initialize();
});

Resources