Skip to content

Loading…

Problem with asyn routing #1268

Closed
cristobal151 opened this Issue · 14 comments

10 participants

@cristobal151

Hi,
I have this code (http://jsfiddle.net/cristobal151/GCSdd/1/):

(function() {
    /**
     * App
     */
    App = Ember.Application.create({});
    App.ApplicationController = Ember.Controller.extend({
        updateTitle: function updateTitle(title) {
            document.title = title;
        }
    });
    App.ApplicationView = Ember.View.extend({
        templateName: 'layout'
    });

    /**
     * Menu
     */
    App.MenuController = Ember.ArrayController.extend({});
    App.MenuView = Ember.View.extend({
        templateName: 'menu'
    });
    App.MenuItem = Ember.Object.extend({});

    /**
     * Posts list
     */
    App.PostsController = Ember.ArrayController.extend({
        content     : [],

        init: function() {
            var _self = this;

            _self._super();
            _self.updatePosts();
        },
        updatePosts: function() {
            var _self    = this;

            var url     = 'url';
            $.getJSON(url + '&callback=?', function(result) {
                var posts = [];
                $.each(result.items, function(i, post) {
                    posts.pushObject(App.PostController.create(post));
                });
                _self.set('content', posts);
            });
        }
    });
    App.PostsView = Ember.View.extend({
        templateName: 'posts'
    });

    /**
     * Post
     */
    App.PostController = Ember.ObjectController.extend({
        year: function() {
            var updated_at = this.get('updated_at');
            return moment(updated_at).format('YYYY');
        }.property('updated_at'),
        month: function() {
            var updated_at = this.get('updated_at');
            return moment(updated_at).format('MM');
        }.property('updated_at'),
        find: function(slug) {
            var _self = this;
            var url = 'url';

            $.getJSON(url + '?callback=?', function(post) {
                _self.set('content', post);
            });
        }
    });
    App.PostView = Ember.View.extend({
        templateName: 'post',
        didInsertElement: function() {
            $(window).scrollTop(0);
        }
    });

    /**
     * Router
     */
    App.Router = Ember.Router.extend({
        location: 'history',
        enableLogging: true,
        root: Ember.Route.extend({
            showHome: Ember.State.transitionTo('index.home'),
            showPostsInDimension: Ember.State.transitionTo('index.dimension'),

            index: Ember.Route.extend({
                route: '/',                
                showPost: Ember.State.transitionTo('post'),                
                connectOutlets: function(router) {
                    var applicationController = router.get('applicationController');

                    applicationController.connectOutlet('menu', 'menu');
                },
                home: Ember.Route.extend({
                    route: '/',
                    connectOutlets: function(router) {
                        var applicationController = router.get('applicationController');
                        var homeController = router.get('homeController');

                        homeController.connectOutlet('posts', 'posts');
                        applicationController.connectOutlet('home');
                    }
                }),
                post: Ember.Route.extend({
                    route: '/:year/:month/:slug',

                    connectOutlets: function(router, post) {
                        router.get('applicationController').connectOutlet('post', post);
                    },
                    serialize: function (router, post) {
                        return {
                            "year": post.get('year'),
                            "month": post.get('month'),
                            "slug": post.get('slug')
                        }
                    },
                    deserialize: function (router, params) {
                        router.get('postController').find(params['slug']);
                    }
                })
            })
        })
    });

    $(function() {
        App.initialize();
    });
})();

It work when i load the list of post and then go to one post, but when a want to enter with the url of a post, the serialize and derialize dont wait to load the post from an api y send me an error.

How can i asyn a rout when enter for the first time in the url??

Thanks

@lukemelia
Ember.js member

PR #1183, which was merged a few weeks ago, offers a solution to your problem. To take advantage of it, you will need to make the result of your deserialize method implement the promises pattern.

@wagenet wagenet closed this
@cristobal151

Sorry for that issue, i look, but don't fine any things.
Can you make and example of this??, i can't fine how to do it.

Thanks

@leroj7

I need help too, please. May be you create a fiddle?
Thanks

@leroj7

I finally get it:

deserialize: (router, params) ->
    page=App.Page.find(params.id})
    deferred = $.Deferred()
    page.addObserver("isLoaded", -> deferred.resolve(page))
    return deferred.promise()

While 'page' is loading the router goes to state 'loading'. I defined that state in the router:

loading: Em.State.extend
    connectOutlets: (router, context) ->
        router.get('applicationController').connectOutlet(context: context, name: "loading")

I created a view for loading whith an ajax loader gif. All work ok.

Good Job Wagenet.

@cristobal151

can you post a fiddle example??, i can't make works.

Thanks

@mutewinter

@leroj7 that worked perfectly for me, thanks for sharing that code

@trek
Ember.js member

@wagenet can you say whether @leroj7's solution is the intende usage? I feel like any object that implements then could be the return object and not just jQuery.Deferred objects.

@lukemelia
Ember.js member

@trek: I would say that @leroj7's solution is one possible approach. The requirement is the deserialize return something that as a then method which conforms to the Promises/A pattern and calls the success handler with the params that should be passed to connect outlet.

@krisselden
Ember.js member

Here is a fiddle http://jsfiddle.net/krisselden/uErrd/ if you want to see the urls you can go directly to http://jsfiddle.net/krisselden/uErrd/show/

When routes are nested, you need a loading state at each level.

@shwoodard

I have a loading state at each level. Sometimes, the router makes to the later states; sometimes, it hangs at root.loading--never makes it to nested routes. Any ideas?

@shwoodard

UPDATE

The loading object may already be loaded when serialize is called so do,

deserialize: (router, params) ->
  report = @_super(router, params)
  deferred = $.Deferred()
  if report.get('isLoaded')
    deferred.resolve(report)
  else
    report.one 'didLoad', ->
      deferred.resolve(report)
  deferred.promise()
@ferdy-lw

Does not adding an observer cause a leak? Will the observer be automatically torn down?

page.addObserver("isLoaded", -> deferred.resolve(page))
@heartsentwined

Is there a solution for this with the new router?

I have read #1378, #1183, ghempton's gist, lukemelia's gist, and this SO question, but they all refer to the old router.

@heartsentwined

Solved. Posting solution here just in case anybody comes across this:

App.FoosIndexController = Em.ArrayController.extend
  someAction: ->
    foo = App.Foo.find(1) # id might as well come from somewhere
    if foo.isLoaded
      @transitionToRoute 'foos.show', foo
    else
      foo.one 'didLoad', => @transitionToRoute 'foos.show', foo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.