Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with asyn routing #1268

Closed
cmaldonadowilson opened this issue Aug 13, 2012 · 14 comments
Closed

Problem with asyn routing #1268

cmaldonadowilson opened this issue Aug 13, 2012 · 14 comments

Comments

@cmaldonadowilson
Copy link

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
Copy link
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 as completed Aug 14, 2012
@cmaldonadowilson
Copy link
Author

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
Copy link

leroj7 commented Aug 17, 2012

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

@leroj7
Copy link

leroj7 commented Aug 21, 2012

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.

@cmaldonadowilson
Copy link
Author

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

Thanks

@mutewinter
Copy link
Contributor

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

@trek
Copy link
Member

trek commented Aug 22, 2012

@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
Copy link
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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

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

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

@heartsentwined
Copy link

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
Copy link

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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants