Search code examples
vue.jsgraphqlapollographene-djangovuedraggable

Problem with vuedraggable and apollo mutation


In my project I'm using Django - graphene-django (graphQL) - Apollo - VueJS - Vuetify and for the drag and drop concerns I'm trying to use Vuedraggable. I'm actually trying to build a kanban board with columns and cards to move from column to column (Trello like). The thing is it works well when I don't run any Apollo mutation.

So you can see my initial state :

enter image description here

If I don't do anything apart providing the :list and group='...', it works :

enter image description here

But when I provide a @change="..." method with an apollo mutation, it doesn't work anymore and it does this :

enter image description here

My Datas are structured like this :

There are multiple stages (New, In Progress, Done) and each of them can have multiple tickets (Stage 1-n Tickets)

stage {
  id
  name
  ticketIds {
    id
    name
  }
}

Here are my sources :

My template (I omitted pure visual things such as styling classes and column header to make it cleaner) :

<template>
  <v-row>
    <v-col
      v-for="stage in helpdeskTicketStages"
      :key="stage.id">
      <draggable
        :list="stage.ticketIds"
        @change="changeTicketStage($event, stage)"
        group="tickets">
        <v-card
          v-for="ticket in stage.ticketIds"
          :key="ticket.id">
          <v-card-title>{{ ticket.name }}</v-card-title>
        </v-card>
      </draggable>
    </v-col>
  </v-row>
</template>

My change method :

changeTicketStage (event, stage) {
  if (event.added) {
    this.$apollo.mutate({
      mutation: CHANGE_HELPDESK_TICKET_STAGE_MUTATION,
      variables: {
        ticketId: event.added.element.id,
        stageId: stage.id
      },
      update: (cache, { data: { changeHelpdeskTicketStage } }) => {
        console.log('cache : ', cache)
      }
    })
  }
}

The CHANGE_HELPDESK_TICKET_STAGE_MUTATION mutation :

const CHANGE_HELPDESK_TICKET_STAGE_MUTATION = gql`
  mutation changeHelpdeskTicketStageMutation (
    $ticketId: ID!,
    $stageId: ID!
  ) {
    changeHelpdeskTicketStage (
      ticketId: $ticketId,
      stageId: $stageId
    ) {
      id,
      isClosed,
      stageId {
        id
        name
      }
    }
  }
`

The graphene-django that is called :

class ChangeHelpdeskTicketStage(graphene.Mutation):

    class Arguments:
        ticket_id = graphene.ID()
        stage_id = graphene.ID()

    class Meta:
        output = HelpdeskTicketType

    def mutate(self, info, **kwargs):
        ticket = get_object_or_404(HelpdeskTicket, id=kwargs['ticket_id'])
        stage = get_object_or_404(HelpdeskTicketStage, id=kwargs['stage_id'])
        ticket.change_stage(stage)
        return ticket

The this that is weird is that without mutation, it moves correctly. And when I add the mutation to change it effectively in DB too (which is done correctly) it does this weird 'clone'. I think the problem is from the apollo cache because, when I print things to console, in the change(...) method everything is okay :

Indeed, at the end of the change(...) method, I run :

  for (const stage of this.helpdeskTicketStages) {
    console.log('name:', stage.name, 'tickets:', stage.ticketIds)
  }

which gives to console :

enter image description here

So we can see that it is correct, there is 1 ticket per stage. But it displays 2 tickets in the 'New' stage !

I have added a test button to run the exact same code :

test () {
  console.log('----------------- TEST -----------------')
  for (const stage of this.helpdeskTicketStages) {
    console.log('name:', stage.name, 'tickets:', stage.ticketIds)
  }
  console.log('----------------- END -----------------')
}

And when we inspect the result in console, we can see :

enter image description here

That there are 2 tickets in 'New' stage and 1 ticket in 'In Progress' stage whereas it should be 1 in each... Of course if I press F5 it runs the query and retrieve the correct information in DB and it corrects the display.

Also in this part :

      update: (cache, { data: { changeHelpdeskTicketStage } }) => {
        console.log('cache : ', cache)
      }

If I inspect the cache we can also see that there are 2 in 'New' and 1 in 'In Progress'.

Can someone tell me why it does this ? I mean when there is no mutation the lists are correctly changed. The mutation should be there just to change it effectively in DB.

Thanks in advance !


Solution

  • Well I finally changed my mind and decided to perform the mutation on the STAGE instead of doing this on the TICKET so that I can send the source stage and the target stage with their updated list of tickets as result of the mutation. By writing all the question I realized it would be easier that way...

    Indeed the result of the mutation is then : [source_stage, target_stage] so the output type is now graphene.List(my_type).

    By doing this I don't have to change manually the stage ticketIds manually after the mutation in an update statement since it updates by itself correctly.