Search code examples
javascriptjsonurl-routingsingle-page-applicationmithril.js

How to create Mithril.js SPA with JSON source?


I'm trying to make a SPA (single page app) with Mithril.js. So far I've found very good tutorial here, and of course on Mithril homepage, but still cannot achieve combination of those two.

Here is modified working example from Dave's guide...

function btn(name, route){
  var click = function(){ m.route(route); };
  return m( "button", {onclick: click}, name );
}
function Page(content){
  this.view = function(){
    return [         
      m("page", 
        m("span", Menu.menu()) 
      ) 
      , m("div", content)
    ];
  }
}
var Menu = { 
  menu: function(){
    return [
      btn("Home",   "/home")
    , btn("About",  "/about")
    ];
  }
};
var page_Home =  new Page("The home of the Hobbits. Full of forests and marshes.");
var page_About = new Page(["The blighted home of Sauron. Scenic points of interest include:"]);

  m.route(document.body, "/home", {
    "/home": page_Home,
    "/about": page_About
  });

My JSON file:

[
 {
  "id":1,
  "title": "Home",
  "url": "/home",
  "content":"This is home page"
 },{
  "id":2,
  "title": "About",
  "url": "/about",
  "content":"This is about page"
 },{
  "id":3,
  "title": "Galery",
  "url": "/galery",
  "content":"This is gallery page"
 }
]

And my effort in combining those two from above:

//model
var PageSource = {
  list: function() {
    return m.request({method: "GET", url: "pages.json"});
  }
};
var pages = PageSource.list();

var App = {
  //controller
  controller: function() {
    return {
      menu: pages
    , rotate: function() { pages().push(pages().shift()); }
    , id: m.route.param(pages.url)
    }
  },

  //view
  view: function(ctrl) {
    return  [
      m("header"
        , m("h1", "Page Title")
        , m("span",
            ctrl.menu().map(function(item) { 
              var click = function(){ 
                console.log (item.url);
                m.route(item.url); 
              };               
              return [
                  m("button", {onclick: click}, item.title)        
              ];
            })
          )
        , m("hr")
       )
    ,  m("button", {onclick: ctrl.rotate}, "Rotate links" )
    ,  m("p", ctrl.content ) //CONTENT
    ];
  }
};

//initialize
  m.route(document.body, "/home", {
    "/:id": App
  });

And finally, questions are: - "How can I retrieve data from JSON file and display it in div based on selected button (routing)?" - "When I use m.route my entire view refreshes, but I only want to reload changed div. How?" Please help, 'cause so far I really like mithril.js


Solution

  • Thanks to @dcochran I've managed to achieve this:

    //model
    var PageSource = {
      list: function() {
        return m.request({method: "GET", url: "pages.json"});
      }
    };
    var pages = PageSource.list();
    var id = m.prop()
      , url = m.prop()
      , title = m.prop()
      , content = m.prop();
    
    var App = {
    //controller
      controller: function() {
        return {
          menu: pages
        , rotate: function() { pages().push(pages().shift()); }
        }
      },
    
    //view
      view: function(ctrl) {
        return  [
          m("header"
            , m("h1", "Page title")
            , m("span",
                ctrl.menu().map(function(item) { 
                  return [ btn(item.title, item.url) ];
                  function btn(name, route){
                    var isCurrent = (url === route);
                    var click = function(){ 
                      //m.route(route); 
                      id = item.id;
                      url = item.url; 
                      content = item.content;
                      title = item.title;
                    };
                    return m(
                      "button"+(isCurrent ? ".active" : ""), 
                      {onclick: click}, 
                      name
                    );
                  }
                })
              )
            , m("hr")
           )
        ,  m("button", {onclick: ctrl.rotate}, "Rotate links" )
        ,  m(".page", content )
        ];
      }
    };
    //initialize
    m.route.mode = "hash";
    m.route(document.body, "/home", { 
      "/:url": App
    })