Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I repeat a resource in Ember.js

I have a page resource that uses the page title in the url.

App.Router.map(function () {
    this.resource('page', {
        path: '/:page_id'
    });
});

App.PageRoute = Ember.Route.extend({
  serialize: function(model) {
    return { page_id: model.title};
  }
});

That is working fine in this jsbin. However, I would like to have subpages nested in the url like this:

localhost/#/main_page/sub_page

I tried to make a sub resource (jsbin), but I'm not sure if it is the right approach.

App.Router.map(function () {
    this.resource('page', {path: '/:page_id'},
                  this.resource('subpage', {path: '/:page_id/:subpage_id'}));
});

There are two main problems in my attempt: I have to repeat my page view and it doesn't retain the parent page in the url. I'm getting:

localhost/#/undefined/sub_page

Am I heading in the right direction? Can this be accomplished with just one resource?

Thanks in advance!

like image 376
Michael Avatar asked Dec 06 '13 22:12

Michael


People also ask

Is Ember JS frontend or backend?

AngularJS and Ember. js are designed to be backend agnostic. It's a good rule to keep the back-end independent since the front-end is seeing a lot more growth. This decision will save you some trouble in the future when you want to modify your front-end a year or two down the line.

Is Ember a backend?

The most important thing to know is that Ember. js is completely backend-agnostic.

What is Ember run?

Module: ember-metal. Runs the passed target and method inside of a RunLoop, ensuring any deferred actions including bindings and views updates are flushed at the end. Normally you should not need to invoke this method yourself.

How does Ember JS work?

It prints the model data and automatically updates itself when the model changes. Ember. js uses Handlebars, a lightweight templating engine also maintained by the Ember team. It has the usual templating logic, like if and else , loops and formatting helpers , that kind of stuff.


2 Answers

Have you considered nesting resources?

App.Router.map(function () {
    this.resource('page', {path: '/:page_id'}, function(){
        this.resource('subpage', {path: '/:subpage_id'});
    });
});

This would enable at least the URL structure you asked for, but i am not really sure about your requirements.

like image 78
mavilein Avatar answered Sep 17 '22 12:09

mavilein


Most of the modifications I've made are in your html and template. Please, don't mash up the Handlebars' link-to helper with classic anchors () and don't change the link-to tagname attribute, or atleast think twice before doing so. First - move the testData to a globally accessible object, so that you can use it in the menu:

Javascript:

App.CustomRoutes = [{
    id: 1,
    title: 'single'
}, {
    id: 2,
    title: 'subpages',
    pages: [{
        id: 3,
        title: 'subpage1'
    }, {
        id: 4,
        title: 'subpage2'
    }, {
        id: 5,
        title: 'subpage3'
    }]
}];

Html:

<ul class="navbar-nav nav">
  {{#each page in App.CustomRoutes}}
    <li class='menu-item'>
      {{#link-to 'page' page.title}}
        {{page.title}}
        {{#if page.pages}}
          <b class="caret"></b>
        {{/if}}
      {{/link-to}}
      <span class='subpages'>
        <ul>
          {{#each subpage in page.pages}}
            <li>
              {{#link-to 'page.subpage' page.title subpage.title}}
                {{subpage.title}}
              {{/link-to}}
            </li>
          {{/each}}
        </ul>
      </span>
    </li>
  {{/each}}
</ul>

Then I fixed your router declaration. When you define nested routes, the third parameter to this.resource() is a function, much alike the function you pass to App.Router.map().

App.Router.map(function () {
    this.resource('page', {path: '/:page_id'},
                  function() { this.route('subpage', {path: '/:subpage_id'});});
});

Finally, here are the definitions of your routes. Because Subpage is nested in Page, the route must be called PageSubpageRoute. If it was nested in Foo, it would have been FooSubpageRoute. NOTE: The this.render() call inside a router, has the following parameters: (, ).

App.PageSubpageRoute = Ember.Route.extend({
  model: function(params) {
    var parentModel = this.modelFor('page');
    var res = $.grep(parentModel.pages, function (e) {
          if (e.title == params.subpage_id) {
            return e;
          }
        });
    return res[0];
  },
  serialize: function(model) {
    return { subpage_id: model.title};
  },
  renderTemplate: function() {
    this.render('subpage');
  }
});

App.PageRoute = Ember.Route.extend({
  serialize: function(model) {
    return { page_id: model.title};
  },
    model: function (params) {
        return $.grep(App.CustomRoutes, function (e) {
          if (e.title == params.page_id) {
            return e;
          }
        })[0];
    }
});

Here is the code: jsbin

like image 30
Georgi Atsev Avatar answered Sep 17 '22 12:09

Georgi Atsev