How to use data from apollo-client as data-source of QTable?



  • After switching from static data to the result of an apollo-client query I got the following error:

    TypeError: "can't define property "__index": Object is not extensible"
        rows QTable.js:101
        computedData QTable.js:100
        VueJS 3
        computedRowsNumber QTable.js:140
        VueJS 3
        pagesNumber table-pagination.js:52
        VueJS 9
    
    TypeError: "can't define property "__index": Object is not extensible"
        rows QTable.js:101
        computedData QTable.js:100
        VueJS 3
        computedRows QTable.js:136
        VueJS 3
        getTableBody table-body.js:30
        getBody QTable.js:207
        render QTable.js:179
        VueJS 7
    

    Working with a simple table and iterating over the result array works fine.



  • Found a solution:

    • use a different variable for QTable data
    • implement a “watch” on the result variable of apollo-client
    • reset QTable data variable with an empty array
    • iterate with forEach over the result variable of apollo-client in the watch function and push each item inside “value” to it’s counterpart in the QTable data variable
    watch: {
      books () {
        this.tableData = []
        this.books.forEach((value) => {
          this.tableData.push({ id: value.id, author: value.author, title: value.title })
        })
      }
    }
    

    Is there a better solution?



  • How are you calling your data? Can you show the whole code of your component?

    Scott



  • @s-molinari: Hi Scott, thank you for your quick reply.
    Here ist the code of my component:

    <template>
      <div>
        <q-table
            :columns="columns"
            :data="tableData"
            row-key="id"
            selection="single"
            binary-state-sort
            dense
        />
      </div>
    </template>
    
    <script>
    import gql from 'graphql-tag'
    
    const BOOKS = gql`
      query {
        books {
          nodeId
          id
          title
          author
        }
      }
    `
    
    const BOOKS_SUBSCRIPTION = gql`
      subscription {
        listen (topic: "books") {
          relatedNode {
            ... on Book {
              nodeId
              id
              title
              author
            }
          }
        }
      }
    `
    
    export default {
      name: 'BooksSubscribeToMore',
      apollo: {
        books: {
          query: BOOKS,
          subscribeToMore: {
            document: BOOKS_SUBSCRIPTION,
            updateQuery: (previousResult, { subscriptionData }) => {
              if (previousResult.books.find(book => book.id === subscriptionData.data.listen.relatedNode.id)) {
                return previousResult
              }
    
              return {
                books: [...previousResult.books, subscriptionData.data.listen.relatedNode]
              }
            }
          }
        }
      },
      watch: {
        books () {
          this.tableData = []
          this.books.forEach((value) => {
            this.tableData.push({ id: value.id, author: value.author, title: value.title })
          })
        }
      },
      data () {
        return {
          columns: [
            { name: 'id', label: 'ID', field: 'id', sortable: true, required: true },
            { title: 'title', label: 'Title', field: 'title', align: 'left', sortable: true },
            { name: 'author', label: 'Author', field: 'author', align: 'left', sortable: true }
          ],
          books: [],
          tableData: []
        }
      }
    }
    </script>
    


  • Try just using books as your data (table data) directly.

    Scott



  • This was my first approach resulting in the errors above.
    After this I take a look at the structure of data (table data) and books.



  • Here ist the original code:

    <template>
      <div>
        <q-table
            :columns="columns"
            :data="books"
            row-key="id"
            selection="single"
            binary-state-sort
            dense
        />
      </div>
    </template>
    
    <script>
    import gql from 'graphql-tag'
    
    const BOOKS = gql`
      query {
        books {
          nodeId
          id
          title
          author
        }
      }
    `
    
    const BOOKS_SUBSCRIPTION = gql`
      subscription {
        listen (topic: "books") {
          relatedNode {
            ... on Book {
              nodeId
              id
              title
              author
            }
          }
        }
      }
    `
    
    export default {
      name: 'BooksSubscribeToMore',
      apollo: {
        books: {
          query: BOOKS,
          subscribeToMore: {
            document: BOOKS_SUBSCRIPTION,
            updateQuery: (previousResult, { subscriptionData }) => {
              if (previousResult.books.find(book => book.id === subscriptionData.data.listen.relatedNode.id)) {
                return previousResult
              }
    
              return {
                books: [...previousResult.books, subscriptionData.data.listen.relatedNode]
              }
            }
          }
        }
      },
      data () {
        return {
          columns: [
            { name: 'id', label: 'ID', field: 'id', sortable: true, required: true },
            { title: 'title', label: 'Title', field: 'title', align: 'left', sortable: true },
            { name: 'author', label: 'Author', field: 'author', align: 'left', sortable: true }
          ],
          books: []
        }
      }
    }
    </script>
    

    The code with the watcher works fine but it doesn’t feel “smooth”.



  • If you inspect data (table data) after “linking” with QTable you’ll find some aditional things like getters, setters, etc. inside. To protect these additional things QTable seems to use Object.preventExtensions().



  • @SB my hguess is you’ll have to deepcopy the table data and thats the one you use for your apollo, re assigned that copy to the model that you gave to your q-table when it changes maybe with a watcher or computed props.


Log in to reply