【Go言語】webフレームワークBeegoでTodoタスクを一覧化する方法

# サンプル
#### 想定イメージは、下記の前回記事でタスクを登録してユーザーに紐づくタスクを一覧化する機能について紹介します。

https://qiita.com/SKY-HaYaTo/items/5966ca5cf035576bd888

![BeegoのCard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/86407c5f-0b77-47f4-939a-d3676a80705a.png)

# ディレクトリ構造

```
MY-FIRST-BEEGO-PROJECT
├─ conf
│  └─ app.conf
├─ controllers
│  └─ default.go
├─ crypt
│  └─ crypt.go
├─ models
│  └─ todo.go
├─ routers
│  └─ router.go
└─ static
   ├─ css
   ├─ img
   ├─ js
   │  ├─ form.js
   │  ├─ login.js
   │  ├─ reload.min.js
   │  ├─ todoCreate.js
   │  ├─ todoCard.js
   │  └─ todoList.js
   ├─ lib
   │  └─ bootstrap
   │     ├─ css
   │     │  ├─ bootstrap-grid.min.css
   │     │  └─ bootstrap.min.css
   │     ├─ js
   │     │  ├─ bootstrap-bundle.min.js
   │     │  └─ bootstrap.min.js
   │     ├─ jquery
   │     │  └─ jquery.js
   │     └─ upload
   ├─ views
   │  ├─ mytodo
   │  │  ├─ addTodo.tpl
   │  │  └─ myList.tpl
   │  ├─ index.tpl
   │  ├─ subIndex.tpl
   │  └─ thirdIndex.tpl
   └─ main.go


```

# フロント側のコード

```views/subIndex.tpl
<!DOCTYPE>
<html>
    <head>
        <title>Todoリスト</title>
        <!--共通-->
        <link rel="stylesheet" type="text/css" href="/static/lib/bootstrap/css/bootstrap.min.css"/>
        <script type="text/javascript" src="/static/lib/jquery/jquery.js"></script>
        <!--個別-->
        <script type="text/javascript" src="/static/js/todoList.js"></script>        
    </head>
    <body>
        <nav class="navbar navbar-expand-lg bg-body-tertiary">
          <div class="container-fluid">
            <button id="backToTopPage" class="btn btn-primary">
                トップページへ
            </button>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        
                        <button id="myTaskCreate" class="btn btn-primary">
                            タスク登録
                        </button>                        
                    </li>
                    <li class="nav-item">
                        <button id="logout" class="btn btn-secondary">
                            ログアウト
                        </button>                        
                    </li>
                </ul>
            </div>
          </div>  
        </nav>

        
        <div>
            <input type="hidden" id="userId" name="userId" value=""/>
        </div>
        <div id="cardTodo" class="grid gap-3" style="display:flex"></div>
    </body>
</html>
```
#### 今回は、Cardコンポーネントにしてみます。
```static/js/todoList.js
$(document).ready(function(){
    //Session StorageからユーザIDを取得する
    const userId = sessionStorage.getItem("userId");
    let inputValueInUserId = document.getElementById("userId");
    inputValueInUserId.value = userId;

    //トップページに戻るボタンをクリックしたときの処理
    $('#backToTopPage').on('click',function(){

    });

    //タスク登録ボタンをクリックし時の処理
    $('#myTaskCreate').on('click',function(){
        location.replace('/mytodo/addTodo'); //location.replace('myTodo/addTodo');
    });

    //ログアウトボタンをクリックしたときの処理
    $('#logout').on('click',function(){
        sessionStorage.removeItem('user');
        location.replace('/');
    });

    
    $.ajax({
        url:`/controllers/sub/getTasks?userid=${userId}`,// /controllers/sub
        method:'GET',
        success:function(response){
            console.log(response);
            const cardComponent = document.getElementById("cardTodo");
            //タスクデータがある場合、ループして表示する
            if(response.length > 0){
                for(let i=0;i<response.length;i++){
                    const task = response[i];
                    cardComponent.innerHTML += `
                        <div class="card" style="width: 10rem">
                            <img src="${task.TaskImage}" class="card-img-top" alt=" style="height:50px"${task.TaskName}"/>
                            <div class="card-body">
                                <h5 class="card-title">${task.TaskName}</h5>
                                <p class="card-text">${task.TaskDescription}</p>
                                <a href="#" class="btn btn-primary">Go somewhere</a>
                            </div>    
                        </div>
                    `;
                }
            }else{
                cardComponent.innerHTML = `
                    <p>登録済みのデータはありません。</p>
                    <div>
                        <button id="backToTopPage" class="btn btn-secondary">
                            トップに戻る<br/>
                            <small>Back To TopPage</small>
                        </button>
                    </div>
                `;
            }
    
        },
        error:function(response){
            alert('データを取得できませんでした。');
            const cardComponent = document.getElementById("cardTodo");
            cardComponent.innerHTML = `
            <div>
                <button id="backToTopPage" class="btn btn-secondary">
                    トップに戻る
                    <br/>
                    <small>
                        Back To TopPage
                    </small>
                </button>
            </div>`;
        }
    });
    
});
```

# サーバ側のコード

```routers/router.go
package routers

import (
	"my-first-beego-project/controllers"

	"github.com/astaxie/beego"
)

func init() {
	beego.Router("/", &controllers.MainController{})
	//追加
	beego.Router("/sub", &controllers.SubController{}) //beego.Router("/sub", &controllers.SubController{})
	beego.Router("/:id", &controllers.ThirdController{})
	beego.Router("/controllers/user", &controllers.UserController{})
	beego.Router("/login", &controllers.LoginController{})
	beego.Router("/controllers/login", &controllers.LoginController{})
	beego.Router("/mytodo/addTodo", &controllers.TodoCreateController{})
	beego.Router("/controllers/todoAdd", &controllers.TodoAddController{})
	// GetTasksアクションのためのルーティング追加
	beego.Router("/controllers/sub/getTasks", &controllers.SubController{}, "get:GetTasks")
}

```
### レンダリングするためのコントローラ
まずは、`subIndex.tpl`をレンダリング表示するコントローラの修正です。

```controllers/default.go
// 20250205追加
type SubController struct {
	beego.Controller
}

// 20250205
func (c *SubController) Get() {
	//クエリパラメータでユーザIDを取得する

	userId, err := c.GetInt("userid")
	//仮のコード
	//userId = 1

	fmt.Println("取得したリクエストパラメータuseridは、", userId)

	if err != nil {
		beego.Error("リクエストパラメータ 'userid' がありません。リクエストURL:", c.Ctx.Request.URL.String())
		c.Ctx.ResponseWriter.WriteHeader(400)
		c.Ctx.WriteString("ユーザIDが指定されていません。")
		return
	}

	//ORMを使ってユーザIDに紐づくタスクを取得する
	o := orm.NewOrm()
	var tasks []models.Task
	_, err = o.QueryTable("task").Filter("register", userId).All(&tasks)

	if err != nil {
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("タスクデータの取得に失敗しました。")
		return
	}
	fmt.Println("データベースから取得したtasksは", tasks)
	//タスクをJSONで返す
	//c.Data["json"] = tasks

	c.Data["Page"] = "SubPage"
	c.TplName = "subIndex.tpl"
	//c.ServeJSON()
}
```

### JSONデータを返却するコントローラの作成
つぎに、JSONデータを返却するコントローラを作成します。

#### JavaScript でタスクデータを取得して動的にTodoリストを表示する方法
テンプレート内でタスク情報を表示する場合、`tasks `データをレンダリングして表示できます。
しかし、もし`AJAX`を使って動的にタスク情報を取得したい場合は、コントローラを分けて、GET メソッドではページをレンダリングし、AJAXリクエストでJSONを返すようにします。

なので、`GetTasks `メソッドを追加して、`AJAX`リクエストを使ってタスクデータを取得できるようにします。

```controllers/default.go

func (c *SubController) GetTasks() {
	// ユーザIDを取得
	userId, err := c.GetInt("userid")
	fmt.Println("GetTasksのユーザIDは、", userId)
	if err != nil {
		beego.Error("リクエストパラメータ 'userid' がありません。")
		c.Ctx.ResponseWriter.WriteHeader(400)
		c.Ctx.WriteString("ユーザIDが指定されていません。")
		return
	}

	// ORMを使ってタスクを取得
	o := orm.NewOrm()
	var tasks []models.Task
	_, err = o.QueryTable("task").Filter("register", userId).All(&tasks)

	if err != nil {
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("タスクデータの取得に失敗しました。")
		return
	}

	// タスクデータをJSON形式で返す
	c.Data["json"] = tasks
	c.ServeJSON()

}
```

以上です。