※はじめからはこちら
前回でカードの並び替えはできるようになりました。今回はカードの追加を実装していきます。
カードの追加
カードを追加できるようにしていきます。すでにボタン自体は追加済です。
これを押した時のロジックを実装します。ポイントはこのロジックはWebsocket経由ではなく、RESTのようにAjaxで実装したほうが望ましいというのがポイントです。
Card追加のサービス実装
まずはサーバサイド側でCardの追加ロジックを実装します。カードはそのPipeLineの末尾に追加します。CardはPipeLine内での位置をorder
という属性で管理していますので、追加時はその最大のorder
よりも大きい値をセットします。order
は連番であることを期待しているので、単にCardの数+1で良いはずです。
まずは、そのPipeLine内のCard数を戻すクエリを追加します。
@@ -23,3 +23,7 @@ class Card(models.Model):
return cls.objects.get(id=card_id)
except cls.DoesNotExist:
return None
+
+ @classmethod
+ def get_current_card_count_by_pipe_line(cls, pipe_line):
+ return cls.objects.filter(pipe_line=pipe_line).count()
そして、これを利用したadd_card
メソッドを追加します。
@@ -63,3 +63,14 @@ def update_card_order(pipe_line_id, card_id_list):
card.order = i
card.pipe_line = pipe_line
card.save()
+
+
+def add_card(pipe_line_id, card_title):
+ pipe_line = PipeLine.get_by_id(pipe_line_id)
+ current_count = Card.get_current_card_count_by_pipe_line(pipe_line)
+ card = Card(
+ title=card_title,
+ content=None,
+ pipe_line=pipe_line,
+ order=current_count + 1, # 現在のカード数 + 1で末尾になるはず
+ )
+ card.save()
+ return card
add_card用のAPIを実装
add_card
を呼び出すAPIとしてCardApi
を追加します。
@@ -40,4 +40,27 @@ class BoardListApi(View):
'id': board.id,
'name': board.name,
}
+
+
+@method_decorator(csrf_exempt, name='dispatch')
+class CardApi(View):
+
+ def post(self, request):
+ """
+ 新しいcardを追加する
+ """
+ data = json.loads(request.body)
+ card_title = data.get('cardTitle')
+ pipe_line_id = data.get('pipeLineId')
+
+ card = kanban_sv.add_card(
+ pipe_line_id=pipe_line_id,
+ card_title=card_title
+ )
+ return JsonResponse({
+ 'card_data': {
+ 'id': card.id,
+ 'name': card.title,
+ }
+ })
cardTitle
とpipeLineId
をパラメータとしてとるようにします。続いて、これをURLに割り当てます。
@@ -7,7 +7,7 @@ from django.views.generic import TemplateView
from .accounts import signup as signup_view
from .api.accounts import AccountsApi
-from .api.boards import BoardListApi
+from .api.boards import BoardListApi, CardApi
urlpatterns = [
@@ -17,6 +17,7 @@ urlpatterns = [
path('api/accounts/', AccountsApi.as_view()),
path('api/boards/', login_required(BoardListApi.as_view())),
+ path('api/cards/', login_required(CardApi.as_view())),
]
これでapi/cards/
にPOSTすればCardが作成されるはずです。
KanbanClientへの追加
フロント側からサーバサイドへアクセスする際に利用するAPIClient(KanbanClient
)にapi/cards
用のメソッドを追加します。
@@ -59,6 +59,13 @@ class KanbanClient extends Client {
boardName,
});
}
+
+ async addCard({ cardTitle, pipeLineId }) {
+ await this._post(`${this.baseUrl}/boards/`, {
+ cardTitle,
+ pipeLineId,
+ });
+ }
}
Store/Componentへの組み込み
KanbanClientを利用してAPIへアクセスするように組み込んでいきます。まずはStoreのActionを追加します。
@@ -1,4 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
+import kanbanClient from "../../../utils/kanbanClient";
const state = {
@@ -31,6 +32,12 @@ const actions = {
});
commit('updateCardOrder', { pipeLineId, cardList });
},
+ async addCard({ commit }, { pipeLineId, cardTitle }) {
+ await kanbanClient.addCard({
+ pipeLineId,
+ cardTitle,
+ });
+ },
};
続いて、このaddBoard
をPipeLine.vue
に組み込みます。
@@ -75,12 +75,19 @@ export default {
methods: {
addCardAction() {
const cardTitle = window.prompt('CardTitle?');
+ if (cardTitle) {
+ this.addCard({
+ pipeLineId: this.pipeLine.pipeLineId,
+ cardTitle,
+ });
+ }
},
delPipeLineAction() {
window.confirm(`DELETE [${this.pipeLineName}] ? Are you sure?`);
},
...mapActions([
'updateCardOrder',
+ 'addCard',
]),
...mapGetters([
'getBoardId',
これでカード追加ボタンを押すと、カードが追加されるようになりますが、追加されたカードはページをリロードするまで見えません。
これは、カードが追加されたあとにボード全体のデータの再取得が行われていないためです。また、これは追加を行ったブラウザ以外に対してもデータの再取得をリクエストする必要もあります。
Card追加完了後のデータ再取得
カード追加完了後は、自身を含む全てのクライアントが新しいデータを取得する必要があります。これはちょうどカードの並び替えで行っている以下の部分と同じことです。
def update_card_order(self, content):
:
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'send_board_data',
}
)
このChannelLayerを利用している処理単体をWebsocketを通じてクライアントが呼び出せるようにします。
@@ -15,7 +15,8 @@ class KanbanConsumer(JsonWebsocketConsumer):
self.board_id = None
self.namespace = 'board'
self.action_map = {
- 'update_card_order': self.update_card_order
+ 'update_card_order': self.update_card_order,
+ 'broadcast_board_data': self.broadcast_board_data
}
self.room_group_name = None
@@ -80,3 +81,16 @@ class KanbanConsumer(JsonWebsocketConsumer):
if not action:
raise Exception('{} is not a valid action_type'.format(content['type']))
action(content)
+
+ def broadcast_board_data(self, content=None):
+ """
+ 全クライアントに、ボードデータの再取得を依頼する
+ :param content:
+ :return:
+ """
+ async_to_sync(self.channel_layer.group_send)(
+ self.room_group_name,
+ {
+ 'type': 'send_board_data',
+ }
+ )
これで、broadcast_board_data
というメッセージをサーバ側に送信することで同じボードを開いている全クライアントのデータが更新できるようになります。
これでカードの追加処理は実装完了です。
次回
カードの中身の変更とかを作っていきます。