I am using iron router with Meteor (latest versions). I have a template:
<template name="home">
{{#each products}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
and in lib/router.js:
Router.configure({
layoutTemplate:'layout'
});
Router.map(function () {
this.route('home', {
path:'/',
template:'home',
data : function () {
return Products.find();
}
});
});
When I run the page, I see empty page with this JJJJJJJJJJJJ, added for test to see is it template loads.
In the Products collection are 2 items with name. I can read (select), add, remove items for this collection via WEB browser console, but the collection is not rendered in the template.
What can be the error ?
The data function of Iron Router sets the data context for the template. In your case, you are setting the data context to be a cursor but attempting to access the cursor with products, which does not exist as a helper, either registered globally or on the template itself.
There's a few ways you can fix this, but I would suggest letting the router simply determine which template to render and let the template fetch it's own data.
Adjusted router:
Router.map(function () {
this.route('home', {
path: '/',
template: 'home'
}
);
Template helper:
Template.home.helpers({
products() {
return Products.find();
}
});
Alternatively, you can use the this keyword within the template to access the current data context:
<template name="home">
{{#each this}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
However, it is not easy to discern what is being put into this unless you can follow the flow of the data through the route to the template. This also couples this template very tightly with this route, as the route itself is determining the context of your template.
The solution is in lib/router.js, need to set attribute data like this :
data : function () {
templateData = {
products: Products.find()
};
return templateData;
}
, NOT like before - return Products.find(); .
Related
In a dynamic segment template, how do you display data from a model using the route ?
so for example I have those three routes with phone_id as dynamic segment
Router.map(function() {
this.route('phones');
this.route('phone', {path: 'phones/:phone_id'});
this.route('numbers');
});
in phones/:phone_id template, I am trying to show all the numbers model. so in phone.js route, I tried to return the number model and output it but it showed nothing.
import Ember from 'ember';
export default Ember.Route.extend({
numbers(){
return this.get("store").findAll('number')
}
});
I tried it also with the params.phone_id as argument but it did not work. (no error was shown also).
the template phone.hbs looks like
<h5> Device Id: {{model.device_id}}</h5>
{{#each numbers as |number|}}
{{number.digits}}
{{/each}}
funny thing is model.device_id returns the correct one even though I did not even set it to return that in phone.js route. But the each loop for numbers which I did implement something for does not return anything.
Is there a workaround to return number model data in phone.hbs dynamic segment template ?
EDIT:
the way I am reaching my dynamic segment is through a link to:
{{#each phones as |phone|}}
<li>{{#link-to 'phone' phone}} {{phone.id}}{{/link-to}}</li>
{{/each}}
Only object from returned from model hook of route is set as model of controller.
if you want to use numbers as it is in template then write it as a computed property in controller.
numbers:Ember.computed(function(){
return this.store.findAll('number');
});
or you can set these properties in model itself
so model hook of your route will look like this
model:function(params){
return Ember.RSVP.hash({
phone: this.store.findRecord('phone',params.phone_id),
numbers: this.store.findAll('number')
});
}
after this you will get two properties in your model
Now your template will look like this
<h5> Device Id: {{model.phone.device_id}}</h5>
{{#each model.numbers as |number|}}
{{number.digits}}
{{/each}}
I started my first app with Meteor and everything was going fine, until I noticed that a collection is no longer showing in a template.
This is my code:
App.js
Tasks = new Mongo.Collection("tasks");
if (Meteor.isServer) {
Meteor.publish("tasks", function () {
return Tasks.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe("tasks");
Template.body.helpers({
tasks: function () {
return Tasks.find({}, {sort: {createdAt: -1}});
}
});
}
App.html
<template name="home">
<h3>Open Tasks</h3>
<ul>
{{#each tasks}}
{{> displayTasks}}
{{/each}}
</ul>
</template>
<template name="displayTasks">
<li>{{text}}</li>
</template>
Routes.js
Router.route("/", function () {
this.render("Home");
});
I've double-checked with http://meteortips.com/second-meteor-tutorial/publish-subscribe/ and MeteorJS template not showing data, not appearing and it seems that I've done everything correctly. I also tried changing the names and trying to display the tasks on different templates, but to no avail. MongoDB does have data and I can manually insert entries (using the Mongo console) that have their text fields filled out.
What else can I do to troubleshoot? Backtracing my steps hasn't helped and I'd rather avoid starting a new app from scratch.
NOTE: I'm using Iron Router.
By default, child templates don't have access to their parent's helpers. In the code above, the tasks helper has been defined for the body template, but it's needed in the home template. Try this instead:
Template.home.helpers({
tasks: function () {
return Tasks.find({}, {sort: {createdAt: -1}});
}
});
Note that you can explicitly pass a helper from a parent to a child, as seen in my answer to this question, but that's uncommon.
I have an ember route webtest contained within the file routes/webtest.js:
export default Ember.Route.extend({
model: function() {
return {
title: "Does not appear"
};
}
});
I have the matching template contained within templates/webtest.hbs
<div class="container">
<h2>Title: {{title}}</h2>
</div>
when I navigate to the page /webtest in my web browser with ember serve
the resulting page has the title: text, but not the text does not appear
I have been to multiple ember pages, and I have the same code working here:
http://jsbin.com/neheru/6/edit?html,js,output
The goal is to be able to have a variable accessible from within the template webtest that can be accessed by a route.
FYI I'm trying to get it to the template so I can pass variables to a component
The variable should be {{model.title}}
You can log out variables from your template with
{{log title}}
{{log controller.title}}
{{log model.title}}
This might help you to debug faster.
You should then be able to pass data in to our component with something like:
{{my-component title=model.title}}
URL to current version of my project
Here is the code for my project
Background:
I am making a blog using meteor and iron-router. I want to use a single controller for several different "category pages," which filter a list a blog articles in the yield region.
The Problem:
The article list does not get rerendered when the URL changes. I.e. the article list is not reactive. Interestingly, if I navigate back to the home page, the correct article list shows up.
The Question:
How do I make that article list change when I change between different routes on the category route controller?
Some example code:
Please note that the code for this whole project is available here.
Here is my Route Controller:
CategoryController = RouteController.extend({
action: function(){
this.render();
},
template: 'category',
data: function(){
return {category: this.params.category};
}
});
CategoryController.helpers({
articles: function(){
return Articles.find({category: this.params.category});
}
});
And here is the template it is rendering:
<template name='category'>
<div class="container">
<h2>{{category}}:</h2>
<ul>
{{#each articles}}
<li>
{{#linkTo route="article.show"}}
{{title}}
{{/linkTo}}
</li>
{{/each}}
</ul>
</div>
</template>
Resources/Updates:
Read this article on Meteor Reactivity and the Deps Package. Very interesting, but after trying some Deps.autoruns in different places, I don't think that this is the answer.
Currently trying to make different "category" routes inherit from the controller.
The article list does not change because the Template helper is not using a reactive data source. You may use the RouteController.getParams method to establish a reactive dependency on route parameters as shown below.
CategoryController.helpers({
articles: function(){
var controller = this;
var params = controller.getParams();
return Articles.find({category: params.category});
}
});
From Iron Router documentation:
Note: If you want to rerun a function when the hash changes you can do
this:
// get a handle for the controller.
// in a template helper this would be
// var controller = Iron.controller();
var controller = this;
// reactive getParams method which will invalidate the comp if any part of the params change
// including the hash.
var params = controller.getParams();
By default the router will follow normal browser behavior. If you
click a link with a hash frag it will scroll to an element with that
id. If you want to use controller.getParams() you can put that in
either your own autorun if you want to do something procedural, or in
a helper.
This question is related to this one: Ember.js {{render}} helper model not correctly set
But I think that I ask the wrong question.
Router
App.Router.map(function () {
this.resource('article', {path: '/article/:id'});
this.resource('article.new', {path: "/article/new"});
});
I have not defined a route or resource for categorynew because it is rendered as a popup within both Article and Article.new.
Template
<script type="text/x-handlebars" data-template-name="article">
{{render "category/new"}}
</script>
<!-- popups -->
<script type="text/x-handlebars" data-template-name="category/new">
Name: {{input type="text" value=name}}
Image: {{view App.UploadFile name="image" file=image }}
Category-parent: {{input value=categoryRelation}}
<button {{action 'saveCategory'}}>Save</button>
</script>
Controller
App.CategoryNewController = Ember.ObjectController.extend({
actions: {
saveCategory: function () {
var newCategory = this.store.createRecord('category', {
name: this.get('name'),
image: this.get('image'),
category_parent:this.get('category_parent')
});
newCategory.save();
console.log(this.get('naam')); // undefinded
}
}
});
When I fill the form that gets rendered with {{render category/new}} I get these errors:
Assertion failed: Cannot delegate set('name', a) to the 'content' property of object proxy <App.CategoryNewController:ember387>: its 'content' is undefined. ember-1.1.2.js:417
Uncaught Error: Object in path nam could not be found or was destroyed.
I think there must be a model in the controller. But if I do a this.get('model') it is always the wrong model. Even if I define it in App.CategoryNewRoute.
When you call render you can supply it a model, but you aren't supplying it a model. Your controller on the other hand extends ObjectController, which tells ember it's backed by a model. So either you can supply it a model, or you can change it to extend Controller (and everything will live on the controller instead of on a non-existent model).
App.CategoryNewController = Ember.Controller.extend({
name is spelled wrong in the console.log, but I'm pretty sure that's just a typo while putting it on SO.
http://emberjs.jsbin.com/EtafEFUr/1/edit