How can I use URL parameters with meteor.
The URL could look like this: http://my-meteor.example.com:3000?task_name=abcd1234
I want to use the 'task_name' (abcd1234) in the mongodb query in the meteor app.
eg.
Template.task_app.tasks = function () {
return Tasks.find({task_name: task_name});
};
Thanks.
You are probably going to want to use a router to take care of paths and rendering certain templates for different paths. The iron-router package is the best one available for that. If you aren't using it already I would highly recommend it.
Once you are using iron-router, getting the query strings and url parameters is made very simple. You can see the section of the documentation here: https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#route-parameters
For the example you gave the route would look something like this:
Router.map(function () {
this.route('home', {
path: '/',
template: 'task_app'
data: function () {
// the data function is an example where this.params is available
// we can access params using this.params
// see the below paths that would match this route
var params = this.params;
// we can access query string params using this.params.query
var queryStringParams = this.params.query;
// query params are added to the 'query' object on this.params.
// given a browser path of: '/?task_name=abcd1234
// this.params.query.task_name => 'abcd1234'
return Tasks.findOne({task_name: this.params.query.task_name});
}
});
});
This would create a route which would render the 'task_app' template with a data context of the first task which matches the task name.
You can also access the url parameters and other route information from template helpers or other functions using Router.current() to get the current route. So for example in a helper you might use Router.current().params.query.task_name to get the current task name. Router.current() is a reactive elements so if it is used within the reactive computation the computation will re-run when any changes are made to the route.
Related
I am getting some data on a template via meteor.call. Now I want to send the object to another template. I am using iron:router for routing. Below is my code :
Meteor.call(functionName, function(err, res){
if(!err){
//do something
Router.go('templateName', {
data : res
});
}
});
Router.route('/url/:data?', function(){
console.log(this.params.data);
})
In the console.log, I am getting the object as string. Data returned is
"object Object" => (this is a string, not an object)
I don't want to use Session variables as they are global. I am confused as to how to send data from one template to another.
The templates are not related to each other (parent-child relation) and hence I can't use {{>templateName data=this}}
I also tried using query parameters as suggested by #Jankapunkt
Router.go('templateName', {},{
query : res
});
Router.route('/url/:data?', function(){
console.log(JSON.stringify(this.params.query));
});
Printed statement :
{"0":"[object Object]","1":"[object Object]","2":"[object Object]","3":"[object Object]","4":"[object Object]","5":"[object Object]","6":"[object Object]","7":"[object Object]","8":"[object Object]","9":"[object Object]","10":"[object Object]","11":"[object Object]","12":"[object Object]","13":"[object Object]","14":"[object Object]"}
Any idea on how to proceed?
So I have an Angular controller with a meteor helper method, as below.
function localeCtrl($scope, $reactive, $stateParams{
$reactive(this).attach($scope);
var self = this;
self.helpers({
locale: function(){ return Locales.findOne($stateParams.id)},
staff: function(){
// Load data from second collection based on current Locale.
// But how?
},
address: function(){
// Take self.location.address and massage it to provide
// google maps link. How?
}
tags: function(){
// Collect all unique instances of a given tag by
// iterating over the available locales.
// E. G. If 10 locales have the 'restaurant' tag, and 5
// more have the 'library' tag, I want an array of
// ['restaurant', 'library'] -- easy enough to do
// by iterating over the locales, but how do I do that
// reactively?
}
});
}
Unfortunately, I need to set additional properties based on the data fetched by locale(). I can't set them up when I initialize the controller because the value in locale() changes as data is fetched from the server. But I need access to the data in locale to, for example, create the google maps address, or fetch associated records. (They aren't imbedded in the locale document for reasons that I'm sure made sense at the time).
Edit:
Additionally, I'm using ground DB to store a local copy of the data for offline access, which makes life even more complicated.
Probably you best bet is to publish your collection using publishComposite which is implemented using the reywood:publish-composite package.
Add the package:
meteor add reywood:publish-composite
Now where you publish the Locales collection you would do something like this:
Meteor.publishComposite('locales', function() {
return {
find() {
//Put whatever you need in the query for locales
const query = {
_userId: this.userId
};
return Locales.find(query);
},
children: [{
find(locale) {
return Staff.find({ localeId: locale._id });
}
}]
};
});
Then in your controller before the helper you add this:
this.subscribe('locales');
Now you should be able to simply call the code like this:
this.helpers({
locale(){
return Locales.findOne(this.$stateParams.id);
}
});
And access it in the template like this:
locale.staff
Give that a try and let me know!
Is it possible to do something like "filtered subscription" in Meteor: for example if you have a filter on month june and switching to july fetches the new data and subscribes to it?
i tried something like:
Meteor.publish("report", function (query, opt) {
return Report.find({ 'timestamp' : { $gte : query.from, $lt: query.to }}, options);
}
on client with iron router:
HomeController=RouteController.extend({
template:"home",
waitOn:function(){
var dates = getDates();
return Meteor.subscribe("report", dates);
},
fastRender: true
});
but it does not work.
Is there a better method to dynamically subscribe? Or does it just help to navigate with url pattern?
thanks
Is there a better method to dynamically subscribe?
There is an alternative method using template subscriptions, example below. I don't think it's better, just different.
Or does it just help to navigate with url pattern?
If you want to handle the subscriptions in the Router, then storing the subscription query params in the URL does help and has some added benefits in my opinion. But it depends on your desired app behavior.
Using Template Subscriptions approach :
This Meteor Pad example will subscribe to a range of data based on a select :
http://meteorpad.com/pad/26dd8YQevBbA5uNGA/Dynamic%20Subscription
Using Iron Router approach :
This route example will subscribe based on the URL . "items/0/10" will subscribe to the itemData with a range of zero to 10.
Router.route('Items', {
name:'Items',
path:'items/:low/:high',
subscriptions : function(){
var low = parseInt(this.params.low);
var high = parseInt(this.params.high);
return [
Meteor.subscribe("itemData",low,high),
];
},
action: function () {
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
}
});
I think either approach is fine and depends on your interface. Using the URL is nice because you can provide links directly to the range of data, use forward and back buttons in browser, good for paging lists of data.
The template subscriptions approach might be appropriate to change the data on a graph.
The specific issue you are having might be due to the fact that your getDates() is not reactive, so the subscription is only run once when the route waitOn is first run.
I'm just learning Meteor now from the great Discover Meteor book and I'm struggling to understand something about how Router.go() functions which I thought might be something that other beginners could use an answer to.
Context: The code below does what it's supposed to - it picks up the url and title values from the postSubmit form (code not included for the form) and uses that to create a new post. Then it uses Router.go() to take the user to the postPage template at a posts/:_id url, displaying the information for the newly created post. This code all works.
My question is: I would expect that when you call Router.go(), as well as passing in the 'postPage' template, what you would need to pass in as the second parameter is the post id element in the form {_id: post._id} (which also works, I've tried it) as that is what the route requires. So why am I passing in the post var (which includes the url and title) rather than the ID?
Here's my code:
//post_submit.js
Template.postSubmit.events({ 'submit form': function(e) {
e.preventDefault();
var post = {
url: $(e.target).find('[name=url]').val(),
title: $(e.target).find('[name=title]').val()
};
post._id = Posts.insert(post);
//THE 'post' PARAMETER HERE INSTEAD OF '{_id: post._id}' IS WHAT I'M QUESTIONING
Router.go('postPage', post);
}
});
And the code for the router:
//Route for the postPage template
Router.route('/posts/:_id',
{name: 'postPage',
data: function(){ return Posts.findOne(this.params._id); }
});
Good question - I also found this confusing when I first saw it. Here's a sketch of what's going on:
The router parses /posts/:_id and figures out that it should be passed a context object which contains an _id field.
You call Router.go with a context object that contains an _id field.
The router takes your context object and copies the value of _id into this.params.
Because the router understands which fields are required (and ignores the rest), it doesn't actually matter if you pass in {_id: 'abc123'} or {_id: 'abc123', title: 'hello', author: 'bob'}. The fact that the latter works is simply a convenience so you don't have to extract the _id into a separate object.
I'm using Meteor with another CMS, and am creating a url with the variables I need to run Meteor (ex. http://site.com?a=flash&b=hash). How to I make those variables usable, and get Meteor to ignore it as a location? When I load the url like that, my app doesn't load correctly, presumably because it thinks I'm requesting a different location.
Using iron router, if there is a query string or hash fragment in the url, you can access those using the query and hash properties of the this.params object.
// given the url: "/post/5?q=s#hashFrag"
Router.route('/post/:_id', function () {
var id = this.params._id;
var query = this.params.query;
// query.q -> "s"
var hash = this.params.hash; // "hashFrag"
});
Use of the querystring in Meteor should have no effect unless you're using eg. Meteor Router to invoke different methods depending on the current URL.
If you want to parse the querystring, just parse it by hand with eg. (in coffeescript)
querystring: ->
qs = {}
for pair in window.location.search.replace("?", "").split "&"
[k, v] = pair.split("=")
qs[k] = v
qs
Which will return an object like:
{ "a": "flash", "b": "hash" }