Ember.js: objects.pop is not a function from transitionTo

Created on 17 Dec 2015  路  11Comments  路  Source: emberjs/ember.js

This may be a weird bug (and not proper way of doing things) but I think it is important it is known.

I have a route structure like so

Router.map(function() {
  this.route('index', function() {
    this.route('item', { path: '/:item_id' }, function() {
      this.route('content');
      this.route('nested', { path: '/nested/:nested_id' }, function() {
        this.route('content', function() {
          this.route('one');
          this.route('two');
        });
      });
    });
  });

and a service which I use to keep track of where I currently am as well as do transitions from a navigation component related to the nested route. For example

export default Service.extend({
  routing: Ember.inject.service('-routing'),
  // Used by nested-nav
  transition(path, neteditem){
    let self = this;
    let routing = self.get('routing');
    console.log('PATH SERVICE TRANSITION: ', path, nested);
    if (nested){
      routing.transitionTo(path, nested);
    }
    else {
      routing.transitionTo(path);
    }
  }
});

Looking at the debugger (I couldn't find the corresponding code in this repo) listed here (it was in enifed('router/transition-intent/named-transition-intent', ['exports', '../transition-intent', '../transition-state', '../handler-info/factory', '../utils'], function (exports, _transitionIntent, _transitionState, _handlerInfoFactory, _utils)...)

createParamHandlerInfo: function (name, handler, names, objects, oldHandlerInfo) {
      var params = {};

      // Soak up all the provided string/numbers
      var numNames = names.length;
      while (numNames--) {

        // Only use old params if the names match with the new handler
        var oldParams = oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params || {};

        var peek = objects[objects.length - 1];
        var paramName = names[numNames];
        if (_utils.isParam(peek)) {
          params[paramName] = "" + objects.pop();
        } else {
          // If we're here, this means only some of the params
          // were string/number params, so try and use a param
          // value from a previous handler.
          if (oldParams.hasOwnProperty(paramName)) {
            params[paramName] = oldParams[paramName];
          } else {
            throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name);
          }
        }
      }

it appears objects.pop is expecting an array, however it only recieves the string passed as nested above. The corresponding fix was to change a line in the service above to be

if (nested){
  routing.transitionTo(path, [nested]);
}
wontfix

Most helpful comment

I've figured out how to solve the issue, though now I'm not sure it should be.
The routing service handles transitionTo arguments differently:

this.get('routing').transitionTo('route.subRoute', [ model, 'orString' ], { queryParamA: 'A' });

compared to the regular route.transitionTo:

this.transitionTo('route.subRoute', model, 'orString', {
  queryParams: { queryParamA: 'A' }
});

Obviously the routing service is still private, but once it becomes public I think people would expect it to function the same as the route.transitionTo. However personally I think the way the service currently does it is superior, and requires less munching before sending it to the private _doTransition. As well I expect changes to the link component would be needed if we "fix" the way the service does things.

My suggestion would be that perhaps the routing service should have a doTransition method that could be easily used by components like link-to, and should also have a transitionTo that functions the same as route.transitionTo. Happy to take this on if it feels like the way to go.

For reference:
transitionTo in the service
transitionTo in router internals

All 11 comments

Can you create a simple https://ember-twiddle.com/ to demonstrate? It would greatly speed our ability to check this out. Thanks!

Can do this weekend!

Hey, I have exactly the same issue.
I am injecting a '-routing'service into a component like so:

routing: Ember.inject.service('-routing'),

and after using it, like this (a silly example):

this.get('routing').transitionTo('something.something-profile', '3');

I get the following error:
Uncaught TypeError: objects.pop is not a function

Only this transition syntax works:

this.get('routing').transitionTo('clipping.clipping-profile', ['3']);

It does not seem to be right.

My route is defined like so:

Router.map(function() {
  this.route('something', {path: '/clipping'}, function() {
    this.route('something-profile', {path: '/:profile_id'});
  });
});

I also experienced this problem as @gpluta did, trying to inject the -routing service into a component. His ['id'] syntax worked for me as well, but it likely isn't working exactly as intended.

I've figured out how to solve the issue, though now I'm not sure it should be.
The routing service handles transitionTo arguments differently:

this.get('routing').transitionTo('route.subRoute', [ model, 'orString' ], { queryParamA: 'A' });

compared to the regular route.transitionTo:

this.transitionTo('route.subRoute', model, 'orString', {
  queryParams: { queryParamA: 'A' }
});

Obviously the routing service is still private, but once it becomes public I think people would expect it to function the same as the route.transitionTo. However personally I think the way the service currently does it is superior, and requires less munching before sending it to the private _doTransition. As well I expect changes to the link component would be needed if we "fix" the way the service does things.

My suggestion would be that perhaps the routing service should have a doTransition method that could be easily used by components like link-to, and should also have a transitionTo that functions the same as route.transitionTo. Happy to take this on if it feels like the way to go.

For reference:
transitionTo in the service
transitionTo in router internals

That's why -routing is private API ;) Thank you very much for digging into this @robbiespeed!

I am closing this issue as a wontfix due to the reliance on the private -routing API. An improved, and public, API is being worked on at the moment and should be released very soon.
Feel free to re-open the issue if you think it's still justified, thank you!

@locks do you know when the routing api changes will be made?

@benkiefer we are actively working on implementing the public router service, so there is no scheduled release with it at the moment. I suggest to keep an eye on the canary channel, that's where it'll first appear, possibly under a feature flag.

Has anyone seen reference to this new API since May?

@toobulkeh the RFC had some changes meanwhile and was only recently merged (accepted), implementation work has started.

Just FYI, using this cheaty/hacky method discovered by @robbiespeed is the ONLY way to successfully use transitionTo from a component's context, rather than a route's, where you need to pass a parameter also. So until new API actually does come out (or someone teaches me a better method), this does need to be used.

Was this page helpful?
0 / 5 - 0 ratings