Typescript + Marionette.js コードサンプル

# 概要 #

Typescript + Marionette.jsのサンプルを探し回った結果、一通り動くサンプルがなかったので、とりあえず作ったもの。　色々説明書くのも面倒なので、コード見て参考にできたらいいねぐらいの気持ち。自分が引っかかった部分にはコードの中にコメントを入れたつもり。

## サンプルコードがやっていること ##
テキストエリアに文字列を入力して投稿すると、スレッドIDとユーザーIDをひも付けてサーバーにも登録されるし表示上もちゃんと更新されるという一通りの流れ。

参考画像↓

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/35536/62094391-623c-0a16-aaee-61fa4fcadb4a.png)

## サーバーサイド ##
Railsで普通にrails generateコマンドとかで叩いて作ったまんま。
それ以上特にいじってない。

## 実際のコード ##

```ts
// common的な奴に移動したい
_.templateSettings = {
    interpolate: /\{\{(.+?)\}\}/g,
    evaluate: /\{%(.+?)%\}/g,
    escape: /\{%-(.+?)%\}/g
};

module GatheringThreadPosts {

    //とりあえずrouteをAppに混ぜたくないので分離
    //Routerクラスに直接記述する方法を考えたい
    var appRoutes = {
        "": "posts" //この機能ではrouteいらない気がするのだが知見はのこしたいので
    },
    THREADID:string,
    USERID:string;

    //ここで使われるメソッド群の総括的な役割
    export class App extends Marionette.Application {
        navbarRegion: Marionette.Region;
        constructor(threadId:string, userId:string) {
            super();

            //本当はaddInitializerとかで登録しそうだけどこれで普通に大丈夫そう
            var router = new Router({
                controller : new Controller(),
                routes     : {},//ここがないとコンパイル通らない謎
                appRoutes  : appRoutes
            });
            router.route;

            //この人は最後に書かないと直接パス指定で飛んできた時にrouterがちゃんと動かないみたい
            Backbone.history.start({pushState: false, root:""});

            USERID   = userId;
            THREADID = threadId;
        }
    }

    class Controller extends Marionette.Controller {
        posts() {
            var postsCollection = new PostsCollection();
            var layout          = new Layout();
            //ちょっと混乱したがfetchは情報の取得しかしないはずなので
            //getメソッド固定っぽい,なので指定できない
            postsCollection.fetch({
                success : (data) => {
                    layout.posts.show(new PostsView({ collection : postsCollection }));
                },
                error : (that, xhr) => {
                }
            });

        }
    };

    class Router extends Marionette.AppRouter {
    };

    //===============Model=======================================================================

    class PostModel extends Backbone.Model {
    };

    class PostsCollection extends Backbone.Collection<PostModel> {
        url:string = "/gathering_thread_posts.json";
    };

    //===============View=======================================================================

    class Layout extends Marionette.LayoutView<PostModel> {
        el:string = ".js-thread-posts-layout";

        //後でプロパティ追加するような処理の場合はあらかじめクラスで
        //宣言しとかないとコンパイルエラーになる
        posts:any;
        form:any;

        regions() {
            return {
                posts : ".js-layout-posts",
                form  : ".js-layout-post-form"
            };
        }
    };

    class PostView extends Marionette.ItemView<PostModel>{
        template:string = "#post-template";
        tagName:string  = "div";
    };

    class PostsView extends Marionette.CompositeView<PostModel, PostView>{
        childView:any             = PostView;
        template:string           = "#posts-template";
        childViewContainer:string = ".js-post-area";

        events() {
            return {
                "click .js-post-button": "sendPost",
            };
        }

        sendPost() {
            //これでサーバーに保存までできちゃったrails便利やな（小並感）。
            this.collection.create({
                posts     : this.$(".js-post-text").val(),
                thread_id : THREADID,
                user_id   : USERID //ここに入れるのはあくまで表示上で使いたいから
            });
            this.$(".js-post-text").val("");
        }

    };

}

$(document).ready(()=>{
    var app = new GatheringThreadPosts.App(
            $(".js-data-thread-id").val(),
            $(".js-data-user-id").val()
        );
    app.start
});
```
テンプレート側

```html

<input type="hidden" class="js-data-thread-id" value="<%= @gathering_thread.id %>">
<input type="hidden" class="js-data-user-id" value="<%= current_user.id %>">

<div class="js-thread-posts-layout">
  <span>スレッド</span>
  <div class="js-layout-posts"></div>
  <div class="js-layout-post-form"></div>
</div>

<script type="text/template" id="posts-template">
<div class="js-post-area">
</div>

<div>
  <textarea class="js-post-text"></textarea>
  <input type=button class="js-post-button" value="投稿">
</div>
</script>

<script type="text/template" id="post-template">
<div>
{{posts}}
{{user_id}}
</div>
</script>

```

サーバー側はまあいいよね。ってことで以上！