5

The stack I'm using


What I'm trying to do

I'm building an app that presents multiple lists to users, each of which contains multiple cards. Within a list, cards can be reordered by the user. Cards can also be moved from one list to another, which changes the parent list of a card, and the ordering of cards in both the source and destination list.

Here's a GIF showing the UI for cards/lists and reordering in my app. What you see here is all happening client-side, and changes are not persisted to the DB:

Example of drag and drop from my app

This is the query I'm using to build my UI:

const foo = gql`
  query foo {
    getAccount(id: "xxxxx") {
      cardLists {        
        edges {
          node {
            id
            name
            cards(orderBy: {field: order, direction: ASC}) {
              edges {
                node {
                  id
                  name
                  order
                }
              }
            }
          }
        }
      }
    }
  }
`

Here's a GIF from the Vue Draggable project that further illustrates what I'm doing (note the "order" value in the data):

Example of drag and drop from Vue Draggable project


Problem

I don't know how to build a mutation to handle the reordering such that the moved card, and changes to ordering of the source and destination lists, are correctly persisted.

Building the schema in Scaphold means I need to (I think) use the mutations it provides. I don't see a way to pass in multiple cards and lists to a single mutation so that I can update everything at once.

Here is an endpoint for a sample project in Scaphold.io: https://us-west-2.api.scaphold.io/graphql/soreorderingexample

And here is the schema generated by Scaphold.io: https://d3uepj124s5rcx.cloudfront.net/items/1e1m2q3F170C2G3M0v2p/schema.json


My questions

  • What is the right way to think about persisting changes like this in GraphQL?
  • Given the constraints and opinionated behaviours of Scaphold, how should my mutation be done?
Jonathan Heron
  • 191
  • 1
  • 5

1 Answers1

3

I don't know about Scaphold, but you can either keep all items in a single array that you always update in one mutation, or you can update the list items one by one.

The easiest way to have a decoupled manual sorting, is to have an order: Float field, which you set to (prev.order + next.order)/2 every time you want to move a card between two other cards, or 1 more/less than the last/first one if you move to back/front.

Given floating point precision, you can do this between the same two cards 53 times before the precision suffers, at which point you can re-distribute the order fields or manually move the offending cards up and then back down.

w00t
  • 17,944
  • 8
  • 54
  • 62
  • _"but you can either keep all items in a single array that you always update in one mutation, or you can update the list items one by one."_ — Thanks. Sorry for newbie question, but what would a query like this look like? – Jonathan Heron Apr 05 '17 at 13:01
  • Thanks w00t, unfortunately it seems I can't configure Scaphold mutations to accept a list of card inputs. – Jonathan Heron Apr 07 '17 at 11:44