LoginSignup
26
27

More than 5 years have passed since last update.

Mithril+golang Gin を試す

Last updated at Posted at 2015-09-02

mithril.jsで簡単なアプリを作ってみる。

利用するFW

アプリ説明

  • mithrilのチュートリアルにあったTodoがベース
  • SPAじゃなくて、動的な画面をmithrilで作るだけ
  • サーバ側はGin(golang)+genmai(orm)

コード

  • jsonとDBアクセスで使う構造体 $GOPATH/src/app/model/todo.go
todo.go
package model

type Todo struct {
    Id int64 `db:"pk" json:"id"`
    Description string `json:"description"`
    Done bool `json:"done"`
}

  • dbアクセス $GOPATH/src/app/db/db.go
db.go
package db
import (
    _ "github.com/mattn/go-sqlite3"
    "github.com/naoina/genmai"
    "app/model"
    "github.com/gin-gonic/gin"
    "fmt"
)


var DB *genmai.DB

func InitDB() {

    var err error
    DB, err = genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
    if err != nil {
        panic(err)
    }

    if err := DB.CreateTable(&model.Todo{}); err != nil {
        panic(err)
    }

    initData := []model.Todo{
        {1, "なんかやる", false},
        {2, "なんかやる2", true},
    }
    if _,err=DB.Insert(&initData);err != nil{
        panic(err)
    }


}

/**
トランザクション制御のミドルウェア
 */
func TransactionHandler() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                fmt.Println("END TRANSACTION ROLLBACK")
                DB.Rollback()
                panic(err)
            } else {

                DB.Commit()
                fmt.Println("END TRANSACTION COMMIT")
            }
        }()

        fmt.Println("START TRANSACTION")
        if err := DB.Begin(); err != nil {
            panic(err)
        }

        c.Next()



    }
}

  • main+ルーティング $GOPATH/src/app/main/app.go
app.go
package main
import (
    "github.com/gin-gonic/gin"
    "app/db"
    "net/http"
    "app/model"
)

func main(){

    db.InitDB()
    r := gin.Default()
    r.Static("/static","static")
    r.LoadHTMLGlob("templates/*")

    r.Use(db.TransactionHandler())


    r.GET("/",Index)
    r.GET("/todo",GetTodo)
    r.POST("/todo",AddTodo)

    r.Run(":9000")
}

func Index(c *gin.Context){

    c.HTML(http.StatusOK,"index.html",nil)
}

func GetTodo(c *gin.Context){
    db := db.DB

    var todos []model.Todo
    if err := db.Select(&todos,); err != nil {
        panic(err)
    }
    c.JSON(http.StatusOK,todos)
}

func AddTodo(c *gin.Context){

        var todo model.Todo
        if c.BindJSON(&todo) == nil {

        db := db.DB

        if num, err := db.Update(&todo); err != nil {
            panic(err)

        }else if num == 0 {

            if _, err := db.Insert(&todo); err != nil {
                panic(err)
            }
        }

        c.JSON(http.StatusOK, todo)

    }else {
        c.JSON(http.StatusBadRequest, nil)
    }

}

  • インデックスページ(htmlテンプレート) $GOPATH/templates/index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="/static/js/mithril.min.js" type="text/javascript" charset="utf-8"></script>
    <title>Mithril TODO</title>
</head>
<body>
<div id="$contents"></div>

<script type="text/javascript">
    //todo component
    var todo = {};
    //model
    todo.Todo = function (data) {
        this.description = m.prop(data.description);
        this.done = m.prop(data.done);
    };

    todo.TodoList = Array;

    //define the view-model
    todo.vm = (function () {
        var vm = {}
        vm.init = function () {
            //a running list of todos
            vm.list = new todo.TodoList();

            //a slot to store the name of a new todo before it is created
            vm.description = m.prop("");

            //init
            m.request({method: "GET", url: "/todo"}).then(function (todoList) {

                todoList.forEach(function (v) {
                    vm.list.push(new todo.Todo({description: v.description, done: v.done}));
                });

            });

            vm.add = function () {
                if (vm.description()) {

                    m.request({
                        method: "POST",
                        url: "/todo",
                        data: {id:t.id,description: vm.description()}
                    }).then(function (t) {

                        vm.list.push(new todo.Todo({id:t.id,description: t.description}));

                        vm.description("");

                    },function(error){
                        console.log("error ");
                    });
                }
            };
            vm.update = function (task) {

                m.request({
                    method: "POST",
                    url: "/todo",
                    data: {id: task.id(),
                           description:task.description(),
                           done:task.done()}
                }).then(function () {
                    console.log("updated");
                }, function (error) {
                    console.log("error ");
                });
            };

        }
        return vm
    }())

    todo.controller = function () {
        todo.vm.init()
    }

    todo.view = function () {
        return m("div", [
            m("input", {onchange: m.withAttr("value", todo.vm.description), value: todo.vm.description(),}),
            m("button", {onclick: todo.vm.add}, "Add"),
            m("table", [
                todo.vm.list.map(function (task, index) {
                    return m("tr", [
                        m("td", [
                            m("input[type=checkbox]",
                               {
                               onclick:function (e) {
                                    task.done(e.target.checked)
                                    todo.vm.update(task)
                                }
                               ,checked: task.done()
                               })
                        ]),
                        m("td", {style: {textDecoration: task.done() ? "line-through" : "none"}}, task.description()),
                    ])
                })
            ])
        ]);
    };
    m.mount($contents, {controller: todo.controller, view: todo.view});
</script>
</body>
</html>

(ちと修正。下記を参考にdocument.getElementByIdをidのみで指定してみた。知らんかった。。。
http://qiita.com/LightSpeedC/items/a2c967928f9cc13e0ebc)

  • mithrilの置き場 $GOPATH/static/mithril.js

実行

rerun app/main
26
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
27