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.
Related
I am having issues refreshing events when I add a new one. The event gets inserted into the database fine, but the call to
this.$refs.calendar.$emit('refetch-events')
Throws the following error:
[Vue warn]: Error in event handler for "refetch-events": "TypeError: $(...).fullCalendar is not a function"
Here is some more of the code to further demonstrate what I am trying to do:
<template>
<div>
<full-calendar ref="calendar" :event-sources="eventSources" #day-click="daySelected" #event-selected="eventSelected" :config="config"></full-calendar>
<!-- Modal Component -->
<b-modal ref="my_modal" title="New Appointment" #ok="submit" #shown="clearModalValues">
<form #submit.stop.prevent="submit">
<label>Client:</label>
<b-form-select v-model="selectedClient" :options="clientOptions" class='mb-3'></b-form-select>
<label>Service:</label>
<b-form-select multiple v-model="selectedService" :options="serviceOptions" class='mb-3'></b-form-select>
<label>Start time:</label>
<time-picker v-model="myTime"></time-picker>
<label>Notes:</label>
<b-form-input textarea v-model="notes" placeholder="Notes"></b-form-input>
</form>
</b-modal>
<!-- /Modal Component -->
</div>
</template>
<script>
export default {
props: {
staff:{
type: Number,
required: true
},
},
data() {
return {
myTime: new Date(),
selectedService: [null],
selectedClient: null,
selectedStartTime: new Date(),
notes: null,
serviceOptions: [],
clientOptions: [],
events: [],
config: {
timeFormat: 'h(:mm)',
eventClick: (event) => {
console.log('Event Clicked: '+event.title);
},
},
selected: {},
};
},
computed: {
eventSources() {
return [
{
events(start, end, timezone, callback) {
axios.get('/getEvents').then(response => {
callback(response.data)
})
}
}
]
}
},
mounted() {
this.myTime = new Date()
axios.get('/getClients').then(response => this.clientOptions = response.data);
axios.get('/getServices').then(response => this.serviceOptions = response.data);
},
methods: {
clearModalValues() {
this.selectedService = [null];
this.selectedClient = null;
this.selectedStartTime = new Date();
this.myTime = new Date();
this.notes = null;
},
submit(e) {
axios.post('/addEvent/',{'selectedService':this.selectedService,'selectedClient':this.selectedClient,'selectedStartTime':this.selectedStartTime,'notes':this.notes}).then(function(response){
//console.log(response.data);
new PNotify({
title: 'Success',
text: 'New event has been created',
icon: 'icon-checkmark3',
type: 'success'
});
this.selectedService = [null];
this.selectedClient = null;
this.selectedStartTime = new Date();
this.notes = null;
this.myTime = new Date();
// ******** I HAVE TRIED THESE CALLS AS PER DOCUMENTATION **********
//this.$refs.calendar.fireMethod('refetch-events')
//this.$refs.calendar.fullCalendar.$emit('refetch-events');
//this.$refs.calendar.$emit('refetch-events');
console.log(this.$refs.calendar);
}.bind(this));
},
eventSelected(event) {
console.log('Event Selected: '+event.title);
},
daySelected(date,event,view){
this.$refs.my_modal.show();
this.selectedStartTime = date.format("YYYY-MM-DD HH:mm:ss");
this.myTime = date.toDate();
},
},
};
</script>
According to the documentation it should be correct. I know its late and I have been at this for a couple hours so I might be overlooking something simple. Again this is vue-full-calendar and not regular full-calendar. I just need to call refetchEvents when I add the new events in the submit method. Thanks!
I have found the issue, thanks to Brock for the help. I had multiple versions of jquery running(the html template I was using was also calling it).
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});
});
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);
})
}
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 :)
I am trying to make collection aggregate in my Meteor.js app as shown below, yet each time I call my server logSummary method I get the following error. Can someone please tell me what I am doing wrong / how to resolve this error? Thanks.
Note: I am using Meteor-aggregate package
TypeError: undefined is not a function
at Object.Template.detailedreport.helpers.myCollection (http://localhost:3000/client/views/report.js?
Code:
Template.detailedreport.rendered = function() {
Session.set("dreport_customer", "");
Session.set("dreport_project", "");
Session.set("dreport_startDate", new Date());
Session.set("dreport_endDate", new Date());
$('.set-start-date').datetimepicker({
pickTime: false,
defaultDate: new Date()
});
$('.set-end-date').datetimepicker({
pickTime: false,
defaultDate: new Date()
});
$('.set-start-date').on("dp.change",function (e) {
Session.set("dreport_startDate", $('.set-start-date').data('DateTimePicker').getDate().toLocaleString());
});
$('.set-end-date').on("dp.change",function (e) {
Session.set("dreport_endDate", $('.set-end-date').data('DateTimePicker').getDate().toLocaleString());
});
};
Template.detailedreport.helpers({
customerslist: function() {
return Customers.find({}, {sort:{name: -1}});
},
projectslist: function() {
return Projects.find({customerid: Session.get("dreport_customer")}, {sort:{title: -1}});
},
myCollection: function () {
var now = Session.get("dreport_startDate");
var then = Session.get("dreport_endDate");
var custID = Session.get("dreport_customer");
var projID = Session.get("dreport_project");
Meteor.call('logSummary', now, then, projID, custID, function(error, data){
if(error)
return alert(error.reason);
return data;
});
},
settings: function () {
return {
rowsPerPage: 10,
showFilter: true,
showColumnToggles: false,
fields: [
{ key: '0._id.day', label: 'Day' },
{ key: '0.totalhours', label: 'Hours Spent'}
]
};
}
});
Template.detailedreport.events({
'submit form': function(e) {
e.preventDefault();
Session.set('dreport_endDate', $('.set-end-date').data('DateTimePicker').getDate().toLocaleString());
Session.set('dreport_startDate', $('.set-start-date').data('DateTimePicker').getDate().toLocaleString());
Session.set('dreport_project', $(e.target).find('[name=project]').val());
Session.set('dreport_customer', $(e.target).find('[name=customer]').val());
},
'change #customer': function(e){
Session.set("dreport_project", "");
Session.set("dreport_customer", e.currentTarget.value);
},
'change #project': function(e){
Session.set("dreport_project", e.currentTarget.value);
}
});
Template:
<div>
{{> reactiveTable class="table table-bordered table-hover" collection=myCollection settings=settings}}
</div>
Server:
Meteor.methods({
logSummary: function(startDate, endDate, projid, custid){
var pipeline = [
{ $match: { date: { $gte: new Date(startDate), $lte: new Date(endDate) },
projectid: projid,
customerid: custid
}
},
{ $group: {
_id: {
"projectid": "$projectid",
"day": { "$dayOfMonth": "$date" },
"month": { "$month": "$date" },
"year": { "$year": "$date" }
},
totalhours: {"$sum": "$hours"}
}}
];
return ProjectLog.aggregate(pipeline);;
}
});
Looking at the ReactiveTable documentation, it looks like you need to do something like:
Template.myTemplate.helpers({
myCollection: function () {
return myCollection;
}
});
Where myCollection is the name of a Mongo/Meteor collection (e.g. BlogPosts) which you defined with e.g. BlogPosts = new Mongo.Collection('blogPosts');
The reason you're getting undefined is not a function is that you are calling a Meteor method inside a template helper. The call is asynchronous so the return value is undefined. Now you are passing undefined to ReactiveTable. ReactiveTable will be trying to call something like myCollection.find() which is essentially undefined.find() and will therefore throw the error you're seeing.
Later on the Meteor call will finish and the data value will be lost because the function has already returned.
You can call Meteor.call inside the onCreated function like so:
Template.myTemplate.onCreated(function () {
Meteor.call('myFunction', 'my', 'params', function (err, result) {
if (err) {
// do something about the error
} else {
Session.set('myData',result);
}
});
});
Template.myTemplate.helpers({
myData: function () {
Session.get('myData')
}
});
This won't fix the issue with ReactiveTable, however.
If the collection you're trying to display is only used for this single page, you could put the aggregation inside the publish function so that minimongo contains only the documents that match the aggregation and therefore the correct documents will appear in your ReactiveTable.