Why is Express rendering a page other than specified in res.render - javascript

I am trying to render an ejs page called compare.ejs but when I navigate to the page where i am expecting compare to be rendered, another page has been rendered. What am I missing here?
in app.js :
var compare = require('./routes/compare')(nav);
app.use('/compare', compare);
in routes/compare.js
var compare = express.Router();
var router = function (nav) {
compare.route('/')
.get(function(req,res){
res.render('compare',
{
nav: nav
})
});
return compare
};
module.exports = router;
However when I navigate to /compare another page with another name is rendered.

Probably you have another route before compare that is matching the same location. Remember that the routes are middleware so, you must be careful with the order.

Might need to be router.route() rather than compare.route()
// after edit
This sort of thing usually happens if an earlier route matches the same route. Do you have other, similar routes?

Related

Making route unique to one ejs file

i want a URL like this localhost3000/hh234due, with a unique id, to route to specific page, but with what am doing it is conflicting with other routes.
how to make /:id unique to one view
module.exports = function (app) {
app.get('/:id', function (req, res) {
res.render('page/index');
});
}
Since routes are tested in order, place it last in the sequence and anything it would conflict with will take precedence over it.
In general, this is just a questionable practice because
app.get('/:id', ...)
matches every single possible top level route and invites conflicts with other top level routes that you want/need in the workings of your site.
You can make it work by always placing it as the last possible route definition, but I would recommend changing the URL to something like
http://localhost:3000/id/hh234due
and then you can use:
app.get('/id/:id', ...)
and not have any conflicts with any of your other top level routes.
When doing it this way, the URL structure is more declarative too since the /id part clearly states what this URL is rather than before where you were more relying on the fact that it doesn't look like any of the other top level routes on your site so "I guess" it must be an id which is not as declarative or clear to the other developers that might work on this site some time in the future.
It should be enough to put the spcific page routing before the general one, like this:
module.exports = function (app) {
app.get('/hh234due', function (req, res) {
res.render('<your special page>');
});
app.get('/:id', function (req, res) {
res.render('page/index');
});
}

Ember not calling setupController of router

So, I have two paths in my route. I created the two routes as the doc recommends.
My router is the following:
// router.js
Router.map(function() {
this.route('photos');
this.route('photo', { path: '/photo/:photo_id' });
});
If I visit firstly the route /photo/ID and then go to /photos, it will only show one object on the latter. (wrong)
If I visit /photos first it shows all the objects and I can go to /photo/ID later on and it will be fine. (right)
I want to make it work both ways. How to do this? You can see my code for each route down below:
// photo.js
export default Ember.Route.extend({
model(params) {
return this.get('store').findRecord('photo', params.photo_id);
}
});
// photos.js
export default Ember.Route.extend({
setupController(controller, model) {
let photos = this.get('store').findAll('photo');
console.log('add all...');
// convert to an array so I can modify it later
photos.then(()=> {
controller.set('photos', photos.toArray());
});
},
});
I can always call the findAll() function regardless where the user goes, but I don't think this is smart.
The way I am dealing with the page transitions:
To go to photos I use:
{{#link-to 'photos'}}All{{/link-to}}
To go to /photo/ID I inject the service '-routing' and I use in one event click like this:
routing: Ember.inject.service('-routing'),
actions() {
selectRow(row) {
this.get("routing").transitionTo('photo', [row.get('id')]);
}
}
findAll will get it from a store and return immediately and later on it will request the server and update the store. but in your case, as you are not using route model hook, so this live array will not be updated so it will not reflect it in the template.
If I visit firstly the route /photo/ID and then go to /photos, it will
only show one object on the latter.
In the above case, store will contain only one reocrd, so when you ask for store data using findAll it will return the existing single record.
Another option is,
avoiding this photos.toArray() - It will break live-array update, I am not sure why do you need it here. since photos is DS.RecordArray.
Note: It's important to note that DS.RecordArray is not a JavaScript
array, it's an object that implements Ember.Enumerable. This is
important because, for example, if you want to retrieve records by
index, the [] notation will not work--you'll have to use
objectAt(index) instead.

In marionette mvc pattern, where to put different get API calls

For example I have the following server routes set up for my user entity:
GET /users/ // gets collection of users
GET /users/:id // gets user :id
GET /users/me // gets the current user
At the beginning of my app I want to get the current user from the server and store it... Something along the lines of:
App.addInitializer(function () {
$.get('/users/me')
.done(function processCurrentUser (userJson) {
App.user = new User(userJson);
});
});
My question is where this API call should actually reside. Would it be better to have something along the lines of:
App.addInitializer(function () {
App.user = new User();
App.user.fetchMe(); // performs the api call above
});
Or should I be doing something inside of a controller?
Thanks for the help!
When doing a fetch, I always worry about how its asyn behavior is going to affect the components that depend on that data. If there are no downriver components that will need the data before it can be reasonably expected to return, then there's technically nothing wrong with your approach.
There is, however, another possible way of loading your globals. What I often do (and for a user's list, too, it so happens) is bootstrap the data to the initial load page. I generally load it on the window variable. So for your example, in your backend template,
<script>
window.globals = {};
window.globals.currentUser = #Html.Raw(Json.Encode(ViewBag.User))
</script>
Of course, you can replace #Html.Raw(Json.Encode(ViewBag.User)) (we use C#) with your favorite backend model.
Then in your app start you're guaranteed to have the models:
App.addInitializer(function () {
App.user = new User(window.globals.currentUser);
});

Is destroying all Backbone.History.handler routes enough to have a router garbage collected?

I am using Backbone.SubRoute to provide a means to create sub-routers on the fly from a master router.
As this provided me with a great way to modularise code I also want to tear down the router when the module is deactivated as there are many modules that create sub routers of their own and want to keep the application as light as possible.
As the routers routes are stored in Backbone.history.handlers I remove these on module deactivation.
/**
To give you an idea what allHandles may look like
RouterCallback instances are module initialisation objects, the router
always calls an activate method on these. The second method: deactivate,
tears it down
*/
allHandles = {
"subModule1" : RouterCallback,
"subModule2" : RouterCallback
};
// An example of what baseRoute may equal
baseRoute = "module1";
for (var path in allHandles) {
var combinedPath = baseRoute + '/' + path;
Backbone.history.handlers = _.reject(
Backbone.history.handlers, function(value) {
return String.prototype.search.call(value.route, combinedPath) !== -1;
}
);
}
I then retrieve an array of primary routes that contain only the baseRoute from Backbone.history.handlers and check that there are multiple routes registered, if there are, remove the first as it overrides the second.
var primaryHandlers = _.filter(Backbone.history.handlers, function(value) {
return String.prototype.search.call(value.route, baseRoute) !== -1;
});
// Deactivate every loaded module in this routers context
_.invoke(allHandles, "deactivate");
// If primary handlers has the parent routers callback as well as this
// then lets remove the first one that overrides the second.
if (primaryHandlers.length > 1) {
Backbone.history.handlers.splice(
Backbone.history.handlers.indexOf(primaryHandlers[0]), 1);
}
This works well for removing all trace of the router from the history.
Is this enough to have the router garbage collected? I am running profiles that would suggest it isn't, though running through the source for Backbone.Router and Backbone.SubRoute has not yielded anything that would suggest the router is referenced anywhere other than in the history. Any thoughts?

Backbone Collection get(id) method

I have one main home page in my application and another page for each post that can be accessed through a list displayed in the home page..
this is how my router looks like :
var AppRouter = Backbone.Router.extend({
initialize: function(){
this.model = new model();
this.collection = new collection();
},
routes: {
"" : "showForm",
"post/:id" : "showPost"
},
showPost: function(id){
var curmodel = this.collection.get(id);
var post = new postView({model:curmodel});
post.render();
$(".maincontainer").html(post.el);
},
showForm : function(){
var qcView = new qcV({model:this.model, collection:this.collection});
qcView.render()
$(".maincontainer").html(qcView.el);
}
});
this is what one of the links to the posts in this list looks like
<h2><a id= "<%=_id%>" href="#post/<%=_id%>"><%=name%></h2></a>
my first question is: Is it dangerous to link pages with a hash-based URL in this manner?
my second question is: I am having no problem navigating to a posts view if I click one of the links in my home page. I my url successfully changes to something like http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034 and that specific post's view is rendered. However at that point if I refresh the page, or if I directly type http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034to my URL bar the this.collection.get(id) method in my showPost method in the router returns undefined. Can anyone help me figure out why this is the case?
I checked couple times that my initialize method gets called both times, and my collection and model is created successfully
For #2, you are most likely not fetching the collection on the "post" route. Try fetching the collection (if it does not exist) and then call render. That should do the trick!
I think #Trunal's on the right path for the 2nd question. For the first, no, it's not "dangerous". You're not really doing anything different than you would with a classic server-side app, passing information to the server via GET to retrieve info. In my opinion, this should be the preferred approach to implementing routes (rather than attempting to trigger backbone.history.navigate manually, as it avoids all kinds of setup and eventing issues that might otherwise occur).

Categories