4

I just started reading about Mithril. Fascinating.. Just one thing that puzzles me after first read.

How can I route one component inside another (top-level component)? I mean, how do I emulate angulars ng-view or embers outlet?

I understand that I can get m.route to attach components to any dom node. But how can I render say top level component App, which generates m("#view") among other things, and then all other routable components go inside App's #view div? Is this possible? Otherwise I have to repeatedly include header and footer with every route transition to a subcomponent, right? Am I missing something?

Thank you.

r.sendecky
  • 9,933
  • 9
  • 34
  • 62

3 Answers3

3

Otherwise I have to repeatedly include header and footer with every route transition to a subcomponent, right? Am I missing something?

I don't think you're missing anything. Mithril has as little magic as possible, so it's hard to miss things. Yet it's still somehow more convenient than frameworks with magic.

I simply wrap my views in a template function. I'm a lazy guy, but even I don't mind doing this because it's flexible and not confusing.

http://codepen.io/farzher/pen/vOjjEB

function viewTemplate(content) {
  return function() {return [
    m('#header', [
      'my site',
      m('a', {config:m.route, href:'/'}, 'home'),
      m('a', {config:m.route, href:'/1'}, 'page 1'),
      m('a', {config:m.route, href:'/2'}, 'page 2'),
    ]),
    m('hr'),

    m("#view", content),

    m('#footer', 'copyright my site'),
  ]}
}

component1 = {
  view: viewTemplate([
    m('h1', 'component 1 page')
  ])
}

component2 = {
  view: viewTemplate([
    m('h1', 'component 2 page')
  ])
}

m.route(document.body, '/', {
  '/': {view: viewTemplate()},
  '/1': component1,
  '/2': component2,
})
Farzher
  • 13,934
  • 21
  • 69
  • 100
  • Thank you very much. I found Leo's suggestion I posted above which I prefer for the top outer layout. But your method is good too as an option. I think I'd use it if any further sub layering is required. I'll give you the tick as your answer helped me understand how people solve this kind of problems. Cheers. – r.sendecky Jul 13 '15 at 04:05
1

I ended up going with on of the Leo's suggestions I found googling around.

I can only have "one-layer" wrap and no named outlets with this solution but it works and does the job for now.

At the end of the day, Angular has only one ng-view and people get by somehow.

So this is the outer component.

var Layout = {
  controller(subcomp) {
    this.own = {
      slide: false
      };
    this.subctrl = new subcomp.controller();
    this.subview = subcomp.view;
  },
  view(ctrl) {
    return bubble(ctrl.own, ctrl.subview(ctrl.subctrl));
  },
  wrap(routes) {
    var map = {};
    Object.keys(routes).map((r) => {
      map[r] = {
        controller() {
          return new Layout.controller(routes[r]);
        },
        view: Layout.view
      };
    });
    return map;
  }
};

This is the outer view where you insert your component.

function bubble(vm, subview) {
  return m("main", [
    m("#outlet",[ subview ])
  ]);
}

And then you route all your subcomponents inside the layout.

m.route.mode = "pathname";
m.route(document.body, "/articles/create", Layout.wrap({
  "/articles/create": CreateArticle
}));

Hope this helps someone in the same situation.

r.sendecky
  • 9,933
  • 9
  • 34
  • 62
  • That's a very good idea too. I've actually seen that route wrapping concept turned into a plugin https://github.com/gitter-badger/moria checkout the usage section at the bottom, pretty cool – Farzher Jul 15 '15 at 22:33
  • Small syntax note: shouldn't the `Layout` component's methods be like `wrap: function(routes) {` instead of `wrap(routes) {`? – GreenRaccoon23 Mar 20 '16 at 00:52
  • @GreenRaccoon23 This is ES6 syntax. It is perfectly ok. – r.sendecky Mar 20 '16 at 01:12
0

I tried several solutions:

  1. With m.component for route handler - http://jsfiddle.net/0xwq00zm/1/
  2. With internal method of the App component, that wraps the inner component. This is somewhat better, cause I'm able to pass aplication state to other components - http://jsfiddle.net/0xwq00zm/11/
  3. With simple external function, that wraps the inner component with other elements - http://jsfiddle.net/0xwq00zm/12/

More or less complex - with all of them I have the feeling that the apps redraws itself, and not only the inner component.

Simply select all the elements - Ctrl+A in the result pane in JsFiddle - and then navigate. It's virtual DOM and it shouldn't re-render everything, but with all solutions above - it happens.

(I tried also with context.retain = true; on some parts, but still after a few navigations I get to a point where nothing gets selected.)

========

Hope these variants help someone ... but also - I'll be happy to see solution of the total re-rendering.

pesho hristov
  • 1,946
  • 1
  • 25
  • 43