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
}
});
Related
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")});
},
})
I just updated to Meteor 1.0 and the latest version of Iron-Router.
For whatever reason, when I pass data to a template that includes only a single document, it works. But when I try to pass multiple documents to the template, I get a blank screen.
//galleryRoute.js
Router.route('/:section', function() {
this.layout('Gallery', {
data: function() {
var data = { photos: photos.find({ path: { $regex: '/'+this.params.section +'/' } }) };
return data;
}
});
});
<template name="Gallery">
<div class="container">
{{#each photos}}
<div class="section-photo" style="background:url({{path}}) no-repeat center center; width:175px; height:175px; background-size:cover;"></div>
{{/each}}
</div>
</template>
Wondering if anyone has any ideas about why this would be?
In your data function, you're accessing this.params.section. However, this is refers to your current scope, which is not the route, therefore this.params will be undefined. Try doing something like this:
//galleryRoute.js
Router.route('/:section', function() {
var route = this;
this.layout('Gallery', {
data: function() {
var data = { photos: photos.find({ path: { $regex: '/'+route.params.section +'/' } }) };
return data;
}
});
});
I have this Layout View:
var appLayoutView = Backbone.Marionette.LayoutView.extend({
template: function() {
return "some template string";
},
regions: {
notify: "[data-region='Notify']"
},
onShow: function() {
this.regions.notify.show(new notifyView());
}
});
Which I call like so:
mainLayout.app.show(appLayout);
So ideally, I'd like, when I run the above line (essentially when the layout view is put into the DOM) for the notifyView to be rendered into the "notify" region. However this.regions.notify is just a string. How can I achieve what I'm trying to do here? Basically having the render logic for "notify" inside the Layout View class, and not controlled from the invocation line.
I can't find any docs that show where this got added, but LayoutView should have a getRegion method :
https://github.com/marionettejs/backbone.marionette/blob/master/src/marionette.layoutview.js#L74
so your code would look like :
var appLayoutView = Backbone.Marionette.LayoutView.extend({
template: function() {
return "some template string";
},
regions: {
notify: "[data-region='Notify']"
},
onShow: function() {
this.getRegion('notify').show(new notifyView());
}
});
In my pursuit to get a binding for an associative array to work, I've made significant progress, but am still blocked by one particular problem.
I do not understand how to create a binding from strictly javascript
Here is a jsFiddle that shows more details than I have posted here:
jsFiddle
Basically, I want to do a new binding within the shown $.each function that would be equivalent to this...
<div data-template="display-associative-many" data-bind="repeat: Root.Items"></div>
Gets turned into this ...
<div data-template="display-associative-single" data-bind="source: Root['Items']['One']"></div>
<div data-template="display-associative-single" data-bind="source: Root['Items']['Two']"></div>
<div data-template="display-associative-single" data-bind="source: Root['Items']['Three']"></div>
And I am using the repeat binding to create that.
Since I cannot bind to an associative array, I just want to use a binding to write all of the bindings to the objects in it.
We start again with an associative array.
var input = {
"One" : { Name: "One", Id: "id/one" },
"Two" : { Name: "Two", Id: "id/two" },
"Three" : { Name: "Three", Id: "id/three" }
};
Now, we create a viewModel that will contain that associative array.
var viewModel = kendo.observable({
Name: "View Model",
Root: {
Items: input
}
});
kendo.bind('#example', viewModel);
Alarmingly, finding the items to bind was pretty easy, here is my binding so far;
$(function(){
kendo.data.binders.repeat = kendo.data.Binder.extend({
init: function(element, bindings, options) {
// detailed more in the jsFiddle
$.each(source, function (idx, elem) {
if (elem instanceof kendo.data.ObservableObject) {
// !---- THIS IS WHERE I AM HAVING TROUBLE -----! //
// we want to get a kendo template
var template = {};// ...... this would be $('#individual-item')
var result = {}; // perhaps the result of a template?
// now I need to basically "bind" "elem", which is
// basically source[key], as if it were a normal HTML binding
$(element).append(result); // "result" should be a binding, basically
}
});
// detailed more in the jsFiddle
},
refresh: function() {
// detailed more in the jsFiddle
},
change: function() {
// detailed more in the jsFiddle
}
});
});
I realize that I could just write out the HTML, but that would not perform the actual "binding" for kendo to track it.
I'm not really sure what you are attempting to do, but it seemed to me that the custom "repeat" binding was unnecessary. Here's what I came up with. Is this on track with what you are trying to do?
Here is a working jsFiddle example.
HTML
<div id="example">
<div data-template="display-associative-many" data-bind="source: Root.Items"></div>
</div>
<script type="text/x-kendo-template" id="display-associative-many">
#for (var prop in data) {#
# if (data.hasOwnProperty(prop)) {#
# if (data[prop].Id) {#
<div><span>${data[prop].Id}</span> : <span>${data[prop].Name}</span></div>
# }#
# }#
#}#
</script>
JavaScript
$(function () {
var input = {
"One" : { Name: "One", Id: "id/one" },
"Two" : { Name: "Two", Id: "id/two" },
"Three" : { Name: "Three", Id: "id/three" }
};
var viewModel = new kendo.data.ObservableObject({
Id: "test/id",
Root: {
Items: input
}
});
kendo.bind('#example', viewModel);
});
I have a page resource that uses the page title in the url.
App.Router.map(function () {
this.resource('page', {
path: '/:page_id'
});
});
App.PageRoute = Ember.Route.extend({
serialize: function(model) {
return { page_id: model.title};
}
});
That is working fine in this jsbin. However, I would like to have subpages nested in the url like this:
localhost/#/main_page/sub_page
I tried to make a sub resource (jsbin), but I'm not sure if it is the right approach.
App.Router.map(function () {
this.resource('page', {path: '/:page_id'},
this.resource('subpage', {path: '/:page_id/:subpage_id'}));
});
There are two main problems in my attempt: I have to repeat my page view and it doesn't retain the parent page in the url. I'm getting:
localhost/#/undefined/sub_page
Am I heading in the right direction? Can this be accomplished with just one resource?
Thanks in advance!
Have you considered nesting resources?
App.Router.map(function () {
this.resource('page', {path: '/:page_id'}, function(){
this.resource('subpage', {path: '/:subpage_id'});
});
});
This would enable at least the URL structure you asked for, but i am not really sure about your requirements.
Most of the modifications I've made are in your html and template. Please, don't mash up the Handlebars' link-to helper with classic anchors () and don't change the link-to tagname attribute, or atleast think twice before doing so.
First - move the testData to a globally accessible object, so that you can use it in the menu:
Javascript:
App.CustomRoutes = [{
id: 1,
title: 'single'
}, {
id: 2,
title: 'subpages',
pages: [{
id: 3,
title: 'subpage1'
}, {
id: 4,
title: 'subpage2'
}, {
id: 5,
title: 'subpage3'
}]
}];
Html:
<ul class="navbar-nav nav">
{{#each page in App.CustomRoutes}}
<li class='menu-item'>
{{#link-to 'page' page.title}}
{{page.title}}
{{#if page.pages}}
<b class="caret"></b>
{{/if}}
{{/link-to}}
<span class='subpages'>
<ul>
{{#each subpage in page.pages}}
<li>
{{#link-to 'page.subpage' page.title subpage.title}}
{{subpage.title}}
{{/link-to}}
</li>
{{/each}}
</ul>
</span>
</li>
{{/each}}
</ul>
Then I fixed your router declaration. When you define nested routes, the third parameter to this.resource() is a function, much alike the function you pass to App.Router.map().
App.Router.map(function () {
this.resource('page', {path: '/:page_id'},
function() { this.route('subpage', {path: '/:subpage_id'});});
});
Finally, here are the definitions of your routes. Because Subpage is nested in Page, the route must be called PageSubpageRoute. If it was nested in Foo, it would have been FooSubpageRoute.
NOTE: The this.render() call inside a router, has the following parameters: (, ).
App.PageSubpageRoute = Ember.Route.extend({
model: function(params) {
var parentModel = this.modelFor('page');
var res = $.grep(parentModel.pages, function (e) {
if (e.title == params.subpage_id) {
return e;
}
});
return res[0];
},
serialize: function(model) {
return { subpage_id: model.title};
},
renderTemplate: function() {
this.render('subpage');
}
});
App.PageRoute = Ember.Route.extend({
serialize: function(model) {
return { page_id: model.title};
},
model: function (params) {
return $.grep(App.CustomRoutes, function (e) {
if (e.title == params.page_id) {
return e;
}
})[0];
}
});
Here is the code: jsbin