Meteor collection sorting not working as expected - javascript

I'm trying to sort one collection when the user clicks on a button. It works as expected the first time I click, but then when I click it again nothing happens.
On meteor.startup i'm sorting my collection by 'date'. When the user clicks the category button, it changes the sort by to 'category', and then I am trying to handle each click that same button, to change the sort from ascending to descending.
Heres the snippet that handles the user click:
(I'm almost sure the problem is somewhere here)
layout.js
Template.layout.events({
'click #cat': function(event) {
event.preventDefault();
//sets the session to a variable
var sortBy = Session.get('sort_by');
if (sortBy.category == 'desc') {
return Session.set('sort_by', {
category: 'asc'
});
} else {
return Session.set('sort_by', {
category: 'desc'
});
}
}
})
This is my router.js:
Router.configure({
layoutTemplate: 'layout',
waitOn: function() {
return Estagios.find({},{ sort: Session.get("sort_by")});
},
})
Publications.js
Meteor.publish('nestagios', function() {
return Estagios.find({});
})
This is my main.js
Meteor.startup(function() {
Session.set("sort_by", {
date: -1,
});
});
Can anyone help me find out, what is wrong here? Thank you.

Since you're just toggling the direction of the sort you can simplify your event handler down to:
Template.layout.events({
'click #cat': function(event) {
event.preventDefault();
Session.set('sort_by',{category: -Session.get('sort_by').category});
});
The session variable will evaluate to either {category: 1} or {category: -1}

In your router you should use $orderBy and not sort
Router.configure({
layoutTemplate: 'layout',
waitOn: function() {
return Estagios.find({},{ $orderBy: Session.get("sort_by")});
},
})

Related

Associate Lists and Tasks in Meteor todo

I'm building the todo application from the Meteor tutorial and continue it. I'm building some lists based on the task model, but I don't know how to join them and say when I click on one list, I want all the tasks from this one.
For the moment, I have the Tasks.js with:
'tasks.insert'(text, privacy, priority, listId) {
...
Tasks.insert({
text,
listId: listId,
owner: this.userId,
username: Meteor.users.findOne(this.userId).username,
});
},
Body.js
Template.body.events({
'submit .new-task' (event) {
event.preventDefault();
const listId = ???
const target = event.target;
const text = target.text.value;
...
Meteor.call('tasks.insert', text, privacy, priority, listId);
...
},
And then where I display it:
Template.body.helpers({
tasks() {
const instance = Template.instance();
if (instance.state.get('hideCompleted')) {
return Tasks.find({ checked: { $ne: true } }, { sort: Session.get("sort_order") });
}
return Tasks.find({}, { sort: Session.get("sort_order")});
},
lists() {
return Lists.find({}, { sort: { createdAt: -1 } });
},
I my body.html, I just display each items (lists and tasks) separately. But the problem is I don't know how to make the relation between both ...
Can you help me please ?
Thanks a lot
I see you are already using Session. Basically, you will use a Session variable that tracks what the list the user has selected, and then filter your tasks with that variable.
In your body, where you're displaying your list names, add the list's id as an HTML attribute:
{{#each lists}}
<a href='#' class='list-name' data-id='{{this._id}}'>
{{this.name}}
</a>
{{/each}}
Add an event for clicking on a list name that saves its id to a Session variable:
Template.body.events({
'click .list-name' (event) {
event.preventDefault();
Session.set('listId', event.currentTarget.attr('data-id'))
}
})
In your tasks helper, filter your query using the Session variable:
return Tasks.find(
{ listId: Session.get('listId') },
{ sort: Session.get("sort_order") }
);
Let me know if anything could be more clear.

Meteor: publish dynamically requested range of items

I have huge collection of over 5000+ records. I want to be able to view records 10 at a time. How can I dynamically publish the data that way?
I've tried this so far:
My server.js file :
Meteor.methods({
publishSongs : function (first, last) {
Meteor.publish('adminSongs', function() {
return Songs.find({}, {
skip : first,
limit : last,
sort : {
date : -1
}
});
});
}
});
My client.jsfile :
Template.admin.events({
'click #previous' : function() {
updateSession(-10);
publishSong();
},
'click #next' : function() {
updateSession(10);
publishSong();
}
});
Template.admin.onCreated(function() {
Session.setDefault('limit', {
first : 0,
last : 10
});
publishSong()
})
function publishSong() {
Meteor.call(
'publishSong',
Session.get('limit').first,
Session.get('limit').last
);
}
function updateSession(value) {
Session.set('limit', {
first: Session.get('limit').first + value,
last: Session.get('limit').last + value,
});
}
The server is printing this error message:
Ignoring duplicate publish named 'adminSongs'
It seems like I'm using publications wrong and could use some guidance.
It doesn't look like you're never updating your Session.get('limit'). You'll need to update then you press next/previous otherwise you're always going to get the same records. You'll also need to change the way you're doing publications:
Template.admin.events({
'click #previous' : function() {
updateSession(-10);
},
'click #next' : function() {
updateSession(10);
}
});
Template.admin.onCreated(function() {
Session.setDefault('limit', {
first : 0,
last : 10
});
Template.instance().autorun( function() {
Template.instance().subscribe('adminSongs', Session.get('limit').first, Session.get('limit').last);
});
});
function updateSession(value) {
Session.set('limit', {
first: Session.get('limit').first + value,
last: Session.get('limit').last + value,
});
}
I'm assuming based on your code that you already have a helper defined to return the available songs. The code above makes it so that you have one subscription, and that subscription will update any time your session variable changes.
Your server code will also need to be updated:
Meteor.publish('adminSongs', function(first, last) {
return Songs.find({}, {
skip : first,
limit : last,
sort : {
date : -1
}
});
});
Can be outside of a Meteor.method.

Subscribing the collection (Meteor)

I have some specific problem.
I use MeteorJS and installed yogiben:admin. I tried to build some schema, but I have an error after updating something.
I want to add that I have subpages in page, maybe that's the problem?
That's what I get after adding items to my invoice:
http://s7.postimg.org/l0q52l27v/error.png
As I can see in the picture, the problem is with some modifier and with "After.Update.sum". I use function that use "sum".
In my "server/collections/invoices_item.js"
I have:
InvoicesItem.after.update(function(userId, doc, fieldNames, modifier, options) {
var sum = 0; InvoicesItem.find({ invoiceId: doc.invoiceId }).map(function(item) { sum += item.amount; }); Invoices.update({ _id: doc.invoiceId }, { $set: { totalAmount: sum }});
});
Than I saw that problem could be with "totalAmount:sum". I use Chrome, so I tried "console.log()" to see if the page takes my collection.
And it doesn't.
I use Chrome, so I tried to see what the console will give me. I have something like this: http://s4.postimg.org/rusm4wx9p/fakturka.png
I did sth like that in my code on server side:
Meteor.publish("fakturka", function(invoiceId) {
return Invoices.find({_id:invoiceId,ownerId:this.userId}, {});
});
And did that on client side:
this.InvoicesNewInsertController = RouteController.extend({
template: "InvoicesNew",
yieldTemplates: {
'InvoicesNewInsert': { to: 'InvoicesNewSubcontent'}
},
onBeforeAction: function() {
/*BEFORE_FUNCTION*/
this.next();
},
action: function() {
if(this.isReady()) { this.render(); } else { this.render("InvoicesNew"); this.render("loading", { to: "InvoicesNewSubcontent" });}
/*ACTION_FUNCTION*/
},
isReady: function() {
var subs = [
Meteor.subscribe("invoices_item"),
Meteor.subscribe("invoiceeeee"),
Meteor.subscribe("customers"),
Meteor.subscribe("fakturka", this.params.invoiceId),
Meteor.subscribe("invoices_item_empty_faktura"),
Meteor.subscribe("invoices_itemss_faktura", this.params.invoiceId)
];
var ready = true;
_.each(subs, function(sub) {
if(!sub.ready())
ready = false;
});
return ready;
},
data: function() {
return {
params: this.params || {},
invoices_item: InvoicesItem.find({}, {}),
invoiceeeee: Invoices.find({}, {}),
customers: Customers.find({}, {}),
fakturka: Invoices.findOne({_id:this.params.invoiceId}, {}),
invoices_item_empty_faktura: InvoicesItem.findOne({_id:null}, {}),
invoices_itemss_faktura: InvoicesItem.find({invoiceId:this.params.invoiceId}, {})
};
/*DATA_FUNCTION*/
},
onAfterAction: function() {
}
});
I'm sorry for so much code, but I really want to solve that problem and I want to give so much info as I could. Please, help me to solve my problem.
After removing that code from: both/collections/invoices.js
Schemas={};
Schemas.Invoicess = new SimpleSchema({
invoiceNumber:{
type:Number
},
date_issued:{
type:Date
},
date_due:{
type:Date
},
customerId:{
type:String
},
totalAmount:{
type:String
}
});
Invoices.attachSchema(Schemas.Invoicess);
"fakturka" is visible. After adding that code - "fakturka" in undefined.

Retrieving a display results from a search

I'm relatively new to meteor.js and I'm trying to get a search form to work. So far I'm not even trying to get the params to work, but it will come later.
I'm basically trying to get a bunch of lifts to display.
lib/router.js
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() {
return Meteor.subscribe('lifts');
}
});
Router.route('/', { name: 'liftsList' });
Router.route('/lifts/search/:from-:to-:when', {
name: 'liftsSearch',
waitOn: function() {
return Meteor.subscribe('liftsSearch');
}
});
server/publications.js
Meteor.publish('liftsSearch', function() {
var query = { fromLoc: { $near : {
$geometry: {
type : "Point" ,
coordinates: [ 6.11667, 45.9 ]
} },
$maxDistance : 50
}};
return Lifts.find(query);
});
If I try to display the results with Lifts.find(query).fetch(), it returns actual results.
client/lifts_search.html
<template name="liftsSearch">
<div class="container">
<h3>Lifts search results {{hi}}</h3>
<div class="lifts">
{{#each lifts}}
hi
{{> liftItem}}
{{/each}}
</div>
</div>
</template>
Here I simply got no lifts displaying, not even the little "hi" string.
Thanks
Unless there's code that you haven't included, {{#each lifts}} isn't rendering because you're not defining lifts anywhere. Just because you're populating the Lifts collection, the template doesn't automatically known that lifts refers to it (largely because that would be totally arbitrary - what exact query would it refer to?).
So, you need to define lifts in either a router data function:
Router.route('/lifts/search/:from-:to-:when', {
name: 'liftsSearch',
waitOn: function() {
return Meteor.subscribe('liftsSearch');
},
data: function() {
return {
lifts: Lifts.find() // add a query if you want
}
}
});
Or in a template helper:
Template.liftsSearch.helpers({
lifts: function() {
return Lifts.find(); // add a query if you want
}
});

Trigger event from an approuter

I created an application and it worked fine, most of the functionality is just the application reacting to different events. I would like to implement a router so that users would be able to show their search results with other users etc. The problem is the router appears to be set up correctly, as when i use it to append things directly to the body everything works as expected. When I try to use the router to trigger events though nothing happens, any help would be greatly appreciated. It is worth mentioning I suppose that this is not the complete code but just the parts that seemed relevant to the issue I am experiencing.
IEG = new Backbone.Marionette.Application();
IEG.addRegions({
searchBox: '#searchBox',
resultBox: '#resultBox',
modalBox: '#modalBox',
recipientBox: '#recipientBox',
confirmBox: '#confirmToggleActive'
});
IEG.vent = _.extend({}, Backbone.Events);
IEG.Router = Backbone.Marionette.AppRouter.extend({
routes: {
'': 'index'
},
index: function () {
IEG.vent.trigger("default"); ////TRIGGER EVENT DOES NOT WORK
//$(document.body).append("Index route has been called..");
}
});
SearchBoxView = Backbone.Marionette.ItemView.extend({
template: Handlebars.templates['search'],
events: {
'click #addGroup': 'addGroup',
'keyup #searchStr': 'evaluateSearch'
},
addGroup: function () {
IEG.vent.trigger("addGroup");
},
clearValidationMsg: function () {
$('#searchErrors').html("");
},
evaluateSearch: function (e) {
console.log("keyup DO SOMETHING> ", e.keyCode);
if (e.keyCode === 13) {///press enter execute search
var searchStr = $('#searchStr').val().trim();
if (searchStr) {
IEG.vent.trigger("searchGroups", searchStr);
}
}
else if (e.keyCode === 8 || e.keyCode === 46) {//backspace and delete keys
var searchStr = $('#searchStr').val().trim();
if (!searchStr) {//when searchbar is cleared show all groups
IEG.vent.trigger("searchGroups", null)
}
}
},
validateEmail: function (searchStr) {
return /^.+#.+\..+$/.test(address);
}
});
$(document).ready(function () {
IEG.start();
new IEG.Router;
Backbone.history.start();
IEG.vent.on("default", function () {
var SBV = new SearchBoxView();
IEG.searchBox.show(SBV);
IEG.searchColl = new GroupEntries();
IEG.searchColl.fetch({
data: {
cmd: 0, //search groups
searchStr: null //if null show all groups
},
success: function (data) {
searchResults = new SearchResultsView({ collection: IEG.searchColl });
IEG.resultBox.show(searchResults);
}
});
});
});
Make sure your event listeners are defined before the event is triggered. Most likely, the event trigger is working fine, but your event listener is registered after the router has triggered the event and nothing happens...

Categories

Resources