ember routing not working how I want - ember.js

I have 3 views in my router.
The index view picks viewtwo as the default.
The problem is when I go to viewone or viewthree it goes through the index route! and loads the viewto before then rerouting to whichever I clicked viewone or viewthree and in my setup that causes some glitch as each view does something to the HTML that it then has to undo before leaving but something is not syncing too well (I tested it has something to do with how fast things load and javascript is applied onto it because my glitch only occurs if I click back and forth really fast).
What is the opposite of didInsertElement right before it gets destroyed?
Also why is the viewto getting loaded from the index route?
index: Ember.Route.extend({
route: '/',
redirectsTo: 'viewtwo'
}),
viewone: Ember.Route.extend({
route: '/viewone',
connectOutlets: function( router ) {
....
viewtwo: Ember.Route.extend({
route: '/viewtwo',
connectOutlets: function( router ) {
....
viewthree: Ember.Route.extend({
route: '/viewthree/:item_id',
connectOutlets: function( router, item ) {
....

What is the opposite of didInsertElement right before it gets destroyed?
willDestroyElement. See this page: http://emberjs.com/api/classes/Ember.View.html#event_willDestroyElement
Also why is the viewto getting loaded from the index route?
The reason index loads viewto is because of the redirect, but I think you already knew that. Not sure what you are asking here.
As far as all your routes going through index, you might want to post a fiddle that emulates this problem. /viewthree should not enter index from what you've posted. If you post a fiddle that can reproduce the problem it will help people provide better answers.

Related

Ember - Hitting refresh on browser redirects to previous controller?

I have an ember application.
The routes are setup like.
customer
customer/view/:customerId
customer/dashboard
customer/device-sharing
Customer/dashboard page displays a component, a table, which has a #linkto helper with route customer.device-sharing
This is working as expected.
The issue is, once on device-sharing route, if I am hitting refresh button on browser, the app is being redirected to dashboard route.
EDITED:
router.js:
this.route('customers', function() {
this.route('index', {path: '/'});
this.route('view', {path: '/view/:device_id'});
this.route('dashboard', {path: '/dashboard/:customer_id'});
this.route('device-sharing', {path: '/device-sharing'});
});
The thing going wrong is, in the customer.js route file's afterModel function, we are using transitionTo to go to dashboard.
afterModel(model) {
model = model || [];
if (model.length === 1) {
console.log('Route parent');
this.transitionTo('customers.dashboard', this.get('paramValue'));
}
}
Is there any way to check if the device-sharing subroute is active so that we can prevent the transitionTo call.
Regards,
Ishan
You probably want to move your model and afterModel to your customers/index route to get the behavior that you're really after. Without seeing more of the code, it's a bit of a guessing game though.
You could use the currentRouteName method on the RouterService to check decide whether to transition or not, but I suspect that would be working around an incorrect design and storing up trouble for yourself down the line.

Getting different url requests to API depending on how I've gotten to the page

I'm getting some curious behaviour that I can't figure out the reason for.
This is my router:
App.Router.map(function() {
this.resource('mapPieceSets', { path: '/map-pieces' }, function () {
this.resource('mapPieceSet', { path: '/:mapPieceSet_id' }, function () {
this.resource('mapPiece', { path: '/:mapPiece_id' });
});
});
});
I reload the app from the home page #/ then navigate down to the mapPiece route, I get these URLs requested:
[Domain]/api/mapPieceSets/
[Domain]/api/mapPieces/1/
[Domain]/api/mapPieces/2/
And it all works fine (mapPieceSets returns a list of mapPieceSet which have a list of mapPiece against them)
However, if I reload the whilst on a mapPiece routed page, then I get this URL:
[Domain]/api/mapPieceSets/
[Domain]/api/mapPieceSets/?mapPieceSet_id=1
[Domain]/api/mapPieces/?mapPiece_id=1
So switching from /:id= to ?id=, which isn't working on my end points (that's a side issue which I need to resolve), but just wondering why the URLs changed what they're requesting, and why we get a request to mapPieceSets/?mapPieceSet_id=1 when the whole of that object is returned within the response from mapPieceSets/
(If you need any other snippets of code from my app, let me know and I can put them in)
This is a fairly common confusion. When you're in your app navigating around you're often using a link-to which is then telling ember to use the specified model when visiting the route. When you're refreshing the page, Ember has to divine the models using the url /apimapPieceSets/3/2. At that point it will go to each route MapPieceSetsRoute, MapPieceSetRoute, and MapPieceRoute and hit each model hook passing in any associated params. So what you need to tell Ember how to do, is how to load a mapPieceSet, and mapPiece properly. You'll need to setup a model hook for both of those.
App.MapPieceSetsRoute = Em.Route.extend({
// I don't know if you're using Ember Data, but I'm going to assume you are
model: function(params){
return this.store.find('mapPieceSet', params.mapPieceSet_id);
}
});
From what you said, it sounds like the model is already available client side from the mapPieceSets. In that case, you can use the modelFor method to get a parent's route's model and get your model.
App.MapPieceSetsRoute = Em.Route.extend({
// I don't know if you're using Ember Data, but I'm going to assume you are
model: function(params){
return this.modelFor('mapPieceSets').get('properyWithMapPieces').findBy('id', params.mapPieceSet_id);
}
});

Ember router with transient states

Inspired by Emberjs: Conditional redirect in router I thought I could use transient states in Ember router, as that is what the 'index' route in that question is - it is entered and immediately transitions to another state without a new event triggering it.
I can get the desired effect using the following code (action triggering transitionTwice), however the URL is updated in reverse order leaving it at the first state even though the App traverses through the states in the correct order ending in the expected last state.
App.Router = Ember.Router.extend({
enableLogging: true,
root: Ember.Route.extend({
transitionTwice: Ember.Route.transitionTo('twiceStep1'),
index: Ember.Route.extend({
route: '/',
}),
twiceStep1: Ember.Route.extend({
route: '/twiceStep1',
connectOutlets: function (router) {
router.transitionTo('twiceStep2');
}
}),
twiceStep2: Ember.Route.extend({
route: '/twiceStep2',
})
})
}),
App.initialize();
The console output shows the correct state changes:
STATEMANAGER: Sending event 'transitionTwice' to state root.
STATEMANAGER: Entering root.twiceStep1
STATEMANAGER: Entering root.twiceStep2
However the URL ends up in:
...test2.html#/twiceStep1
Can anyone spot anything I am doing wrong?
Thanks,
Jon.
I have been able to get this to work successfully by wrapping the second transitionTo() call in Ember.run.next().
Ember.run.next(function () {
router.transitionTo('twiceStep2');
});
The problem is that for any transition the URL is updated after the connectOutlets() call completes. This means that chained calls to transitionTo from connectOutlets nest and the URL is updated in reverse order as the calls complete.
While this fixes my immediate problem I'm not sure this really constitutes a final answer to the question as this implies that the final state needs to have the knowledge that it will be entered from a previous, transient state - which isn't good separation. But I thought I should record it in case anyone else struggles with this anomaly.

Ember.Router loses context for dynamic segments on page reload

I've been trying to debug this for a while now, and I may have figured out what the problem is, let me explain what is happening by use of a fiddle
Navigate to http://fiddle.jshell.net/ivanvanderbyl/mfqEB/show/#/projects/1, you'll notice the dynamic segment in the url is replaced with null — it should stay as 1
From what I can gather, after routing once, Ember Router then makes a call to update the URL, replacing the dynamic segments with the values it gets from the respective instantiated objects, in this case App.Project.
The problem is that App.Project is not loaded at this point so id is null
Now whether this is a bug or an implementation failure on my part, has anyone else seen this?
Moving connectOutlets from projects.index directly into projects seems to do the trick. Don't ask me why though.
jsFiddle
Router: Ember.Router.extend(
location: 'hash'
enableLogging: true
root: Ember.Route.extend(
listProjects: Ember.Route.transitionTo("projects.index")
showProject: Ember.Route.transitionTo("projects.show")
index: Ember.Route.extend(
route: "/"
redirectsTo: 'projects.index'
)
projects: Ember.Route.extend(
route: '/projects'
connectOutlets: ((router) ->
router.get('applicationController').connectOutlet('projects', App.Project.find())
)
index: Ember.Route.extend(
route: '/'
)
add: Ember.Route.extend(
route: '/new'
)
show: Ember.Route.extend(
route: '/:project_id'
connectOutlets: (router, project) ->
console.log project.get('name')
# router.get('applicationController').connectOutlet('project', project)
)
)
)
)
So after much investigation the correct solution to this is to simply not specify the primary key attribute on the model, in this case I should not have been specifying the ID attribute on the Project model. Ember Data handles this internally.
Thanks to Peter Wagenet for pointing this out on Github.

Emberjs: Conditional redirect in router

Is there a way to have a conditional redirect in the Ember.js Router, without breaking internal consistency of the router?
What you could do (as of today), is something like that:
root: Ember.Route.extend({
index: Ember.Route.extend({
enter: function(router) {
var logged = /* get from appropriated source... */;
Ember.run.next(function() {
if (logged) {
router.transitionTo('loggedIn');
} else {
router.transitionTo('loggedOut');
}
});
}
}),
loggedIn: Ember.Route.extend({
// ...
}),
loggedOut: Ember.Route.extend({
// ...
})
})
Do not miss the Ember.run.next as while you are in enter, the state transition is always pending, so you have to transition after that.
We use it as shown for authent, but you could imagine using it for whatever condition you have to...
The new router now includes a
beforeModel
hook which you could over-ride to include conditional logic while transitioning to a route.
The beforeModel hook will be called before the
model
hook is called and it gets passed a
transition
object. You can decide if you want to redirect to another route using
transitionToRoute()
or you could abort the transition if you don't want to redirect by calling
transition.abort()
Depending on what you're trying to do, you may be looking for conditional transitions. This is covered in another stackoverflow question, the TLDR of which is to check this fiddle.