My router.js file is like this:
this.route('cards', function() {
this.route('all');
this.route('card', {path: '/:card_id'}, function() {
this.route('edit');
});
this.route('new');
});
In all.js, I've:
model() {
return this.store.findAll('card');
}
In cards.js, I've:
beforeModel() {
this.transitionTo('cards.all');
},
model() {
return this.store.findAll('card');
}
As you can see that I'm making 2 requests which, IMO, is not necessary. So, if I remove the call from cards.js, the new.js doesn't work properly.
When I create a new card from new.js, after creation, it should go to /cards/1 and show the proper data. But, when I remove that line from cards.js, after creation of a card, it goes to /cards/1 but the data is not saved.
Link to repo: https://github.com/ghoshnirmalya/hub-client
Related
I am trying to make sing post page a route where it does a several things using iron:router
Uses the template postPage
Subscribes to publication of singlePost, userStatus (shows status and info of Author of single post page'), comments .
Grabs Comments documents that has field of postId : this.params._id
Increments Comments List by Session.get('commentLimit')
Here is the code I currently have.
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function() {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', {
limit: Number(Session.get('commentLimit'))
})
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});
Publications.js
Meteor.publish('singlePost', function(id) {
check(id, String);
return Posts.find(id);
});
Meteor.publish('comments', function(options) {
check(options, {
limit: Number
});
return Comments.find({}, options);
});
Template.postPage.onCreated
Template.onCreated( function () {
Session.set('commentLimit', 4);
});
Template.postPage.helpers
Template.postPage.helpers({
comments: function () {
var commentCursor = Number(Session.get('commentLimit'));
return Comments.find({postId: this._id}, {limit: commentCursor});
},
});
Template.postPage.events
Template.postPage.events({
'click a.load-more-comments': function (event) {
event.preventDefault();
Session.set('commentLimit', Number(Session.get('commentLimit')) + 4)
}
});
Everything works fine, but I found one thing to be inconsistent.
Here is the problem I am having...
User goes into single post page and adds comment (everything works fine).
User goes into a different single post page and adds comment (everything works fine).
Here is where the problem begins
The user at any time, goes into another route that is not the single post page.
User goes back into single post page
The comments are not showing.
New comments will be added into DB but still wont show
This problem only goes away when meteor reset or manual deletion of all comments in MongoDB is performed.
Is there a better way that I can code my routing and related code to stop this weird behavior from happening?
Or even if there is a better practice.
Your publish is publishing comments without any postId filter.
Your helper, filters by postId. Maybe the 4 comments that get published are the ones that do not belong to the current post that is open?
Could you try updating, your subscription to
Meteor.subscribe('comments', {
postId: this.params._id
}, {
limit: Number(Session.get('commentLimit'))
})
and your publication to
Meteor.publish('comments', function(filter, options) {
check(filter, {
postId: String
});
check(options, {
limit: Number
});
return Comments.find(filter, options);
});
so that only the same posts' comments are published?
I have figured it out. I have updated the following codes.
So far it is not showing weird behavior...
Publications.js
Meteor.publish('comments', function(postId, limit) {
check(postId, String);
check(limit, Number);
return Comments.find({postId:postId}, {limit:limit});
});
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function () {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', this.params._id, Number(Session.get('commentLimit')))
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});
For some odd reason, iron-router randomly returns undefined.
this.route('pollyShow', {
path: '/polly/:_id',
template: 'polly_show',
notFoundTemplate: 'notFound',
before: function () {
var id = this.params._id;
var poll = Polls.findOne({_id: id});
console.log(poll);
var ip_array = poll.already_voted;
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
ip_voted = ip_array.indexOf(data.host);
if (ip_voted > -1) {
Router.go('pollyResults', {_id: id});
}
});
},
data: function() {
return Polls.findOne({_id: this.params._id});
}
});
Sometimes it is returning normally while other times it just returns undefined.
Is there any reason behind this?
The problem occurs because the Polly collection is sometimes populated and at other times unpopulated when the route executes.
This problem can be prevented by explicitly waiting on a subscription using waitOn option in the route configuration.
From the docs:
By default, a new Meteor app includes the autopublish and insecure packages, which together mimic the effect of each client having full read/write access to the server's database. These are useful prototyping tools, but typically not appropriate for production applications. When you're ready, just remove the packages.
To remove the packages, call meteor remove <package-name>.
Then you need to explicitly publish records which you want to see on the client on the server:
server/publications.js:
Meteor.publish('all_of_polly', function () { return Polls.find({}); });
And subscribe to it on the client:
this.route('pollyShow', {
path: '/polly/:_id',
template: 'polly_show',
notFoundTemplate: 'notFound',
waitOn: function () { return Meteor.subscribe('all_of_polly'); }
// ...
});
My issue is that when a user goes to my route book/:id/:version, it takes some time to pull the JSON and for a quick second it still renders the old data then replaces it with the new data.
This is my route:
App.BookRoute = Ember.Route.extend({
setupController: function (controller, model) {
// This gets the entire JSON for the single book
Ember.$.getJSON('/book?id=' + model.id + '&version=' + model.version,
function (data) {
// Set the json to the model
controller.set('model', data);
});
}
});
This is my Router:
App.Router.map(function () {
// Homepage (All the books)
this.resource('index', { path: '/' });
// Single Book view
this.resource('book', { path: '/book/:id/:version' });
});
So for example, on the first visit to #/book/2/1, it works fine. The next visit to another book #/book/3/1, it will show the data (the html template rendered) for #/book/2/1 for a quick second and then load the data for #/book/3/1.
How do I clear the view after the user leaves? Or how do I make it not show the previously loaded book in the route/view.
Thanks.
Edit (Added a possible relevant issue):
Also I have another issue that may or may not be related, but the didInsertElement event is called before the actual HTML is rendered to the DOM. I thought this method is called after the HTML is rendered to the DOM.
This is the view:
App.BookView = Ember.View.extend({
didInsertElement: function () {
console.log('inside didInsertElement');
}
});
It sounds like it's because you're doing that in your setup controller hook. Getting data like that should be done in your model hook. This guide tells you how to do it refer to the "Dynamic Routes" section: http://emberjs.com/guides/routing/specifying-a-routes-model/
Try doing this
App.Router.map(function () {
// Homepage (All the books)
this.resource('index', { path: '/' });
// Single Book view
this.resource('book', { path: '/book/:book_id/:version' });
});
App.BookRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('/book?id=' + params.book_id + '&version=' + params.version);
}
});
I actually think that :id as a param is reserved as it's recommended to do something like :book_id
I got the following simple ember.js-setup, which works all great
App.Router.map(function() {
this.resource('tourdates', function() {
this.resource('tourdate', { path: ':tourdate_id' });
});
});
App.TourdatesRoute = Ember.Route.extend({
model: function() {
return $.getJSON('http://someapi.com/?jsoncallback=?').then(function(data) {
return data;
});
}
});
App.TourdateRoute = Ember.Route.extend({
model: function(params) {
return tourdates.findBy('id', params.tourdate_id);
}
});
so, pretty simple, whenever i call index.html#/tourdates, i get the data via api. and when I click on a link in this view and call f.e. index.html#/tourdates/1 it just displays the view for its nested child.
This all breaks, when I directly call index.html#/tourdates/1 with the message
DEPRECATION: Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object (error on <Ember.Route:ember174>)
Error while loading route: ReferenceError {}
Uncaught ReferenceError: tourdates is not defined
Although he makes the ajax-call to the api and gets the data, he is not able to initialize the nested model
When your App.TourdatesRoute is loaded, all data from the json, will be rendered. And when you click to edit one of these loaded objects, using a link-to for example, ember is smart enough to get the already referenced object, instead of send a new request. So your url will change to: yourhost.com/tourdate/id.
When you direct call this url, it will call the App.TourdateRoute model method. Because doesn't have any pre loaded data. But in your case you have a:
tourdates.findBy('id', params.tourdate_id);
And I can't see in any place the declaration of tourdates.
I recommed you to change your TourdateRoute to TourdateIndexRoute so when transitioning to tourdates the ajax call is performed once:
App.TourdatesIndexRoute = Ember.Route.extend({
model: function() {
return $.getJSON('http://someapi.com/?jsoncallback=?').then(function(data) {
return data;
});
}
});
The TourdatesRoute is called both for TourdateRoute and TourdatesIndexRoute, because it's the parent route of both. So fetching all data in the TourdatesIndexRoute will ensure this is just called when transitioning to tourdates.
In your TourdateRoute you will load just the record needed. Something like this:
App.TourdateRoute = Ember.Route.extend({
model: function(params) {
// retrieve just one data by id, from your endpoint
return $.getJSON('http://someapi.com/' + params.tourdate_id + '?jsoncallback=?').then(function(data) {
return data;
});
}
});
So a direct call to yourhost.com/tourdate/id will just loaded one record.
About your warning message, it happens because in some route you have:
App.MyRoute = Ember.Route.extend({
events: {
eventA: function() { ...},
eventB: function() { ...},
}
});
The events is deprecated and you need to use actions:
App.MyRoute = Ember.Route.extend({
actions: {
eventA: function() { ...},
eventB: function() { ...},
}
});
I hope it helps
I have a messageBox in my Durandal app and whether you click no or yes you are sent throw to an other page. I want to do this with the router, but the pages aren't switched.
I can see the code is executing the line but nothing happens!
define(function(require) {
var app = require('durandal/app'),
system = require('durandal/system'),
router = require('durandal/plugins/router');
return {
router: router,
displayName: 'SometingApp Startpage',
activate: function() {
system.log("Application started!");
},
createEstimate: function() {
app.showMessage('Do you want to create a new something?', 'New something', ['Yes', 'No']).then(function(result) {
if (result == "Yes") {
return router.activate('otherpage');
}
});
}
};
});
THe user click a button that is bind to createEstimate!
Hope someone can help!
I think that what you need to do is call router.navigateTo('#/yourUrl').
If i understand right the documentation, router.activate must be call only one time, usually at the shell activation.
The route functions available for your viewModel navigation is listed in the documentation
http://durandaljs.com/documentation/Router/ under the section "Other APIs"