{"componentChunkName":"component---src-pages-tutorial-vue-step-3-mdx","path":"/tutorial/vue/step-3/","webpackCompilationHash":"aaa6c4cbb44f8ca938e9","result":{"pageContext":{"isCreatedByStatefulCreatePages":true,"frontmatter":{"title":"3. Using APIs","description":"Welcome to Carbon! This tutorial will guide you in creating a Vue app with the Carbon Design System.","internal":false,"tabs":["Overview","Step 1","Step 2","Step 3","Step 4","Step 5","Wrapping up"]},"relativePagePath":"/tutorial/vue/step-3.mdx","titleType":"prepend","MdxNode":{"id":"968bfbae-2bce-574d-ad20-33abdaa31442","children":[],"parent":"81b7a469-c871-54ad-b470-cf87bbcb881d","internal":{"content":"---\ntitle: 3. Using APIs\ndescription: Welcome to Carbon! This tutorial will guide you in creating a Vue app with the Carbon Design System.\ninternal: false\ntabs:\n  ['Overview', 'Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5', 'Wrapping up']\n---\n\nimport Preview from 'components/Preview';\n\n### This step takes our static components and populates them with data from the GitHub GraphQL API – loading states and all. We'll be displaying Carbon repository information in a data table.\n\n<AnchorLinks>\n\n<AnchorLink>Fork, clone and branch</AnchorLink>\n<AnchorLink>Install dependencies</AnchorLink>\n<AnchorLink>Create access token</AnchorLink>\n<AnchorLink>Connect to Apollo</AnchorLink>\n<AnchorLink>Fetch data</AnchorLink>\n<AnchorLink>Populate data table</AnchorLink>\n<AnchorLink>Add loading</AnchorLink>\n<AnchorLink>Add pagination</AnchorLink>\n<AnchorLink>Submit pull request</AnchorLink>\n\n</AnchorLinks>\n\n### Preview\n\nThe [GitHub GraphQL API](https://developer.github.com/v4/) is very well documented, and even though the focus of this tutorial isn't learning and using GraphQL, it's a great opportunity to fetch Carbon-related data for this Carbon tutorial.\n\nTo do so, we'll be using Apollo Client, the front-end component of the [Apollo Platform](https://www.apollographql.com/docs/intro/platform). Apollo provides several open source tools for using GraphQL throughout your application’s stack. Apollo Client is a sophisticated GraphQL client that manages data and state in an application.\n\nA [preview](https://vue-step-4--carbon-tutorial-vue.netlify.com) of what you will build (see repositories page):\n\n<Preview\n  height=\"400\"\n  title=\"Carbon Tutorial Step 3\"\n  src=\"https://vue-step-4--carbon-tutorial-vue.netlify.com\"\n  frameborder=\"no\"\n  allowtransparency=\"true\"\n  allowfullscreen=\"true\"\n  class=\"bx--iframe bx--iframe--border\"\n/>\n\n## Fork, clone and branch\n\nThis tutorial has an accompanying GitHub repository called [carbon-tutorial-vue](https://github.com/carbon-design-system/carbon-tutorial-vue) that we'll use as a starting point for each step. If you haven't forked and cloned that repository yet, and haven't added the upstream remote, go ahead and do so by following the [step 2 instructions](/tutorial/vue/step-2#fork-clone--branch).\n\n### Branch\n\nWith your repository all set up, let's check out the branch for this tutorial step's starting point.\n\n```bash\n$ git fetch upstream\n$ git checkout -b vue-step-3 upstream/vue-step-3\n```\n\n### Build and start app\n\nInstall the app's dependencies:\n\n```bash\n$ yarn\n```\n\nThen, start the app:\n\n```bash\n$ yarn serve\n```\n\nYou should see something similar to where the [previous step](/tutorial/vue/step-2) left off. Stop your app with `CTRL-C` and let's get everything installed.\n\n## Install dependencies\n\nWe'll shortcut this using the Vue CLI, if you'd like more information head over to [Vue Apollo Installation](https://vue-apollo.netlify.com/guide/installation.html#vue-cli-plugin) for details.\n\n_Note: If you have not yet installed the Vue CLI, you will need to [install the Vue CLI](https://cli.vuejs.org/) before running the Vue Apollo Installation._\n\nInstall the following\n\n- `apollo-boost` - package containing everything you need to set up Apollo Client\n- `graphql` - parses your GraphQL queries\n- `vue-apollo` - Apollo integration for Vue\n\nUsing the command:\n\n```bash\n$ vue add apollo\n```\n\nAt the following prompts answer 'No' to each of the questions.\n\n- Add example code? No\n- Add a GraphQL API Server? No\n- Configure Apollo Engine? No\n\n## Create access token\n\nYou'll need a personal access token from your GitHub account in order to make requests to the GitHub API. Check out [this guide](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) to see how to get one.\n\nWhen you get to the scope/permissions step, you can leave them all unchecked. We don't need any special permissions, we just need access to the public API.\n\nOnce you have your token, we need to put it in a place where `create-vue-app` can use it. When your application is being built and developed, create-vue-app will parse environmental variables in any file that starts with `.env` and make them available under `process.env.MY_VARIABLE`.\n\nOne caveat is that we need to start our variables with `VUE_APP_`. You can read more about environmental variables in [create-vue-app's guide](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables).\n\n_Note: If you already have a valid GitHub Personal Access Token, you can use that token here._\n\nSince we don't want to commit this file to Git, we can put it in `.env.local` which is in our `.gitignore` list. Your file should just have a single line like this one, where the `x`s are replaced with your unique token.\n\n##### .env.local\n\n```bash\nVUE_APP_GITHUB_PERSONAL_ACCESS_TOKEN=xxxxxx\n```\n\nGo ahead and start your app with `yarn serve`, or, if your app is running, you'll need to restart it to get access to this token.\n\n## Connect to Apollo\n\nThe `vue-apollo` plugin has made a number of changes to our project.\n\nIf you open `src/main.js` you will see that the CLI has updated this file with the following:.\n\n##### src/main.js\n\n```javascript\nimport { createProvider } from 'vue-apollo';\n\nnew Vue({\n  router,\n  apolloProvider: createProvider(),\n  render: h => h(App),\n}).$mount('#app');\n```\n\nThis is loading from a file the CLI created for you `src/vue-apollo.js` which we need to update to target the github api.\n\n#### src/vue-apollo.js\n\nUpdate the following values:\n\n```javascript\n// Use our access token\nconst AUTH_TOKEN = process.env.VUE_APP_GITHUB_PERSONAL_ACCESS_TOKEN;\n\n// Target github api\nconst httpEndpoint =\n  process.env.VUE_APP_GRAPHQL_HTTP || 'https://api.github.com/graphql';\n```\n\nUpdate only the `wsEndpoint` and `getAuth` properties of the `defaultOptions` object:\n\n```javascript\nconst defaultOptions = {\n  // set wsEndpoint to null\n  wsEndpoint: process.env.VUE_APP_GRAPHQL_WS,\n\n  // Use the form expected by github for authorisation\n  getAuth: tokenName => `Bearer ${tokenName}`,\n};\n```\n\n## Fetch data\n\n### Imports\n\nAdd the following imports to the top of the script section of `RepoPage.vue`:\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\nimport gql from 'graphql-tag';\n```\n\n### Query\n\nNext we'll assemble our GraphQL query to fetch only the data we need from the GraphQL API. We'll do this using the `gql` helper we just imported. The `gql` helper lets you write GraphQL queries using interpolated strings (backticks) in JavaScript. In addition, we'll be using the `Query` component from `vue-apollo` which gives us some great information about our query's loading state in addition to the data.\n\nYou can use GitHub's [explorer](https://developer.github.com/v4/explorer/) tool to write and test your own queries. Try copying the query below and experiment with changing the properties. You can also click the \"Docs\" button in the top right of the explorer to view all of the available data and query parameters.\n\nIf you'd like some more information regarding writing queries and using the Query component, we recommend [Apollo's documentation](https://www.apollographql.com/docs/tutorial/queries) on this topic.\n\nAdd this after your imports:\n\n##### src/views/RepoPage/RepoPage.vue\n\n```graphql\nconst REPO_QUERY = gql`\n  query REPO_QUERY {\n    # Let's use carbon as our organization\n    organization(login: \"carbon-design-system\") {\n      # We'll grab all the repositories in one go. To load more resources\n      # continuously, see the advanced topics.\n      repositories(first: 75, orderBy: { field: UPDATED_AT, direction: DESC }) {\n        totalCount\n        nodes {\n          url\n          homepageUrl\n          issues(filterBy: { states: OPEN }) {\n            totalCount\n          }\n          stargazers {\n            totalCount\n          }\n          releases(first: 1) {\n            totalCount\n            nodes {\n              name\n            }\n          }\n          name\n          updatedAt\n          createdAt\n          description\n          id\n        }\n      }\n    }\n  }\n`;\n```\n\nNext let's we need to configure apollo in our component script, adding the following after the data() declaration.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\napollo: {\n  organization: REPO_QUERY\n},\n```\n\nAt this point, we should run our query view the raw the results to verify that the request is working.\n\nIn RepoPage.vue add the following before the `RepoTable` tag.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```html\n{{ this.organization }}\n```\n\nWhen the data loads you should see the response rendered on your repository page. If not, check the console to see if there are any errors and fix.\n\nRevert this last change and continue.\n\nThis data is not quite in the format our `RepoTable` component is expecting so we'll use a computed property to transform it. Computed properties in Vue cache and watch their reactive dependencies for us.\n\nRemove the 'rows' constant and its use in the data declaration, and add this computed property.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\ncomputed: {\n  rows() {\n      if (!this.organization) {\n      return [];\n    } else {\n      return this.organization.repositories.nodes.map(row => ({\n        ...row,\n        key: row.id,\n        stars: row.stargazers.totalCount,\n        issueCount: row.issues.totalCount,\n        createdAt: new Date(row.createdAt).toLocaleDateString(),\n        updatedAt: new Date(row.updatedAt).toLocaleDateString(),\n        links: { url: row.url, homepageUrl: row.homepageUrl }\n      }));\n    }\n  }\n}\n```\n\nAt this point you have a working table but the links column clearly isn't what we want.\n\n### Helper component\n\nThis column in the data table will be a list of repository and home page links, so let's create a component called `LinkList`.\n\nAdd the following to create your component:\n\nA template section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```html\n<ul class=\"link-list\">\n  <li>\n    <cv-link :href=\"url\">GitHub</cv-link>\n  </li>\n\n  <li v-if=\"homepageUrl\">\n    <span>&nbsp;|&nbsp;</span>\n    <cv-link :href=\"homepageUrl\">Homepage</cv-link>\n  </li>\n</ul>\n```\n\nA script section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```javascript\nexport default {\n  name: 'LinkList',\n  props: {\n    url: String,\n    homepageUrl: String,\n  },\n};\n```\n\nAnd a style section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```scss\n.link-list {\n  display: flex;\n}\n```\n\nNow let's make use of this component in our `RepoTable` component.\n\nAt the top of the script section import the link list component:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\nimport LinkList from './LinkList';\n```\n\nAnd below the name of the component add:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\n  components: { LinkList },\n```\n\nThen make use of it in our template replacing:\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-cell\n  v-for=\"(cell, cellIndex) in row.data\"\n  :key=\"`${cellIndex}`\"\n  >{{cell}}</cv-data-table-cell>\n```\n<!-- prettier-ignore-end -->\n\nwith\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-cell v-for=\"(cell, cellIndex) in row.data\" :key=\"`${cellIndex}`\">\n  <template v-if=\"!cell.url\">\n    {{cell}}\n  </template>\n  <link-list v-else :url=\"cell.url\" :homepage-url=\"cell.homepageUrl\" />\n</cv-data-table-cell>\n```\n<!-- prettier-ignore-end -->\n\nHere in order to switch between the standard rendering of a data cell we've wrapped our standard `{{cell}}` rendering in a template tag. The template tag is non-rendering so it will dissapear, leaving us with the same content as before.\n\nUsing the v-if and v-else directives we switch based on the contents of the cell between the standard rendering and the LinkList component.\n\nChecking our output again, you should now see the LinkList component rendering the final column.\n\nNext we'll update our row description. Update the computed property data() in `RepoTable.vue` to have the following description:\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```javascript\n  description: row.description\n```\n<!-- prettier-ignore-end -->\n\nCheck the output again and you should find the descriptions are updated.\n\nAfter this many refreshes you may have noticed a slight delay in the data loading. As outlined in the [documentation](https://vue-apollo.netlify.com/guide/apollo/#apollo), all components contained under one with an apolloProvider have a `$apollo` attribute. As we added the `apolloProvider` to our app when creating the Vue instance it is available to us everywhere.\n\nWe can use the property to react to [loading state](https://vue-apollo.netlify.com/guide/apollo/queries.html#loading-state).\n\nFirst let's demonstrate that this works.\n\n#### src/views/RepoPage/RepoPage.vue\n\nPass the loading state into our `RepoTable` component by updating the template with the following:\n\n```html\n<repo-table\n  :headers=\"headers\"\n  :rows=\"rows\"\n  title=\"Carbon Repositories\"\n  helperText=\"A collection of public Carbon repositories.\"\n  :loading=\"$apollo.loading\"\n/>\n```\n\nNext add this property to the `RepoTable` component:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\n  props: {\n    headers: Array,\n    rows: Array,\n    title: String,\n    helperText: String,\n    loading: Boolean,\n  },\n```\n\nMaking use of the property to display a loading message.\n\nReplace:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```html\n<cv-data-table\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n></cv-data-table>\n```\n\nwith:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```html\n<div v-if=\"loading\">Loading...</div>\n<cv-data-table\n  v-else\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n></cv-data-table>\n```\n\nHere we have made use of the v-if and v-else directives to switch content based on the state of `$apollo.loading`. If you refresh your app you should see this take effect.\n\nNow that we know this is works let's try something a bit more sophisticated and replace the div containing our loading message with use of the `CvDataTableSkeleton` component.\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-skeleton\n  v-if=\"loading\"\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n  :rows=\"10\"\n/>\n```\n<!-- prettier-ignore-end -->\n\nWe need to tell the loading skeleton how many rows to render, so let's use 10 skeleton rows to prepare for the next enhancement...\n\n## Add pagination\n\nPagination! Instead of rendering every repository, let's add pagination to the data table to only render 10 at a time. Depending on your specific requirements, you may need to fetch new data each time that you interact with the pagination component, but for simplicity, we're going to make one request to fetch all data, and then paginate the in-memory row data.\n\nLet's start by adjusting our `PageTable` component template to add pagination. If you review the [storybook notes](http://vue.carbondesignsystem.com/?path=/info/components-cvdatatable--default) you'll see that pagination is added to the data table by supplying a pagination object and listening for pagination events as follows.\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n  <cv-data-table\n    v-else\n    :columns=\"columns\"\n    :title=\"title\"\n    :helper-text=\"helperText\"\n    :pagination=\"{ numberOfItems: this.totalRows }\"\n    @pagination=\"$emit('pagination', $event)\"\n>\n```\n<!-- prettier-ignore-end -->\n\n_Note: `:prop` is an abbreviation of `v-bind:prop`_\n_Note: `@event` is an abbreviation of `v-on:event`_\n\nIn the pagination event we've used $emit and $event to re-raise the pagination event to our `RepoPage` component so that it can arrange to pass only the rows we want to see to the `RepoTable` component.\n\nWe also need to add the `totalRows` property used in the data tables pagination property.\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\ntotalRows: Number,\n```\n\nNext to our `RepoPage` component, let's first update our template by updating our `RepoTable` use with the following attributes.\n\n##### src/views/RepoPage/RepoPage.vue\n\n<!-- prettier-ignore-start -->\n```html\n:rows=\"pagedRows\"\n:totalRows=\"rows.length\"\n@pagination=\"onPagination\"\n```\n<!-- prettier-ignore-end -->\n\nreplacing\n\n##### src/views/RepoPage/RepoPage.vue\n\n```html\n:rows=\"rows\"\n```\n\nNext in the data property of our component add values for `pageSize`, `pageStart` and `page` into the data method return to support our pagination.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\n  data() {\n    return {\n      headers,\n      pageSize: 0,\n      pageStart: 0,\n      page: 0\n    };\n  },\n```\n\n_Note: We could have passed values for `pageSize` and `page` into our pagination component if we had a specific page or page size we wanted to start with. Instead we are relying on the pagination component to set some sensible defaults and provide us with the details through an event._\n\nThen before we can see our paginated table we need to add: a `pagedRows` computed property to select the slice of input rows we are interested in, and a method to handle the pagination event.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\n  computed: {\n    // other computed properties\n    // ...\n    pagedRows() {\n      return this.rows.slice(this.pageStart, this.pageStart + this.pageSize);\n    }\n  },\n  methods: {\n    onPagination(val) {\n      this.pageSize = val.length;\n      this.pageStart = val.start;\n      this.page = val.page;\n    }\n  }\n```\n\n_Note: Like the other Carbon Vue components,_ `Pagination` _component examples can be found in [Storybook](http://vue.carbondesignsystem.com/?path=/story/components-cvpagination--default) by browsing the story and knobs._\n\nThat does it! Your data table should fetch GitHub data on first render. You can expand each row to see the repository's description. You can modify the pagination items per page and cycle through pages or jump to a specific page of repositories.\n\n## Mystery\n\nHmmm, there is at least one more issue to resolve. If you expand a row or two to see the repository descriptions you will and then change page. What happens?\n\nAssuming you didn't catch this earlier you will find that the expanded rows, stay expanded after paging. That is if row two was expanded before pagination it is expanded after.\n\nThis is because we chose poor values to use as our row and cell keys as we iterated over them. The result is that Vue sees these items as having the same key and makes the assumption that content but not state has changed.\n\nTo fix this add the following to the RepoPage component you should be able to find something better.\n\n```javascript\n  watch: {\n    rows() {\n      if (this.organization) {\n        console.dir(this.organization.repositories.nodes);\n      }\n    }\n  },\n```\n\n_Hint: `id` and `url` are likely unique properties, you could use either of these to update the prototype. In fact we already pass the id value to RepoTable._\n\nCan you fix it?\n\n## Submit pull request\n\nWe're going to submit a pull request to verify completion of this tutorial step.\n\n### Continuous integration (CI) check\n\nRun the CI check to make sure we're all set to submit a pull request.\n\n```bash\n$ yarn ci-check\n```\n\n_Note: Having issues running the CI check? [Step 1](/tutorial/vue/step-1#continuous-integration-ci-check) has troubleshooting notes that may help._\n\n### Git commit and push\n\nBefore we can create a pull request, stage and commit all of your changes:\n\n```bash\n$ git add --all && git commit -m \"feat(tutorial): complete step 3\"\n```\n\nThen, push to your repository:\n\n```bash\n$ git push origin vue-step-3\n```\n\n_Note: Having issues pushing your changes? [Step 1](/tutorial/vue/step-1#git-commit-and-push) has troubleshooting notes that may help._\n\n### Pull request (PR)\n\nFinally, visit [carbon-tutorial-vue](https://github.com/carbon-design-system/carbon-tutorial-vue) to \"Compare & pull request\". In doing so, make sure that you are comparing to `vue-step-3` into `base: vue-step-3`.\n\n_Note: Expect your tutorial step PRs to be reviewed by the Carbon team but not merged. We'll close your PR so we can keep the repository's remote branches pristine and ready for the next person!_\n","type":"Mdx","contentDigest":"3a40a77e58ebb09adef437df58a180a8","counter":1259,"owner":"gatsby-plugin-mdx"},"frontmatter":{"title":"3. Using APIs","description":"Welcome to Carbon! This tutorial will guide you in creating a Vue app with the Carbon Design System.","internal":false,"tabs":["Overview","Step 1","Step 2","Step 3","Step 4","Step 5","Wrapping up"]},"exports":{},"rawBody":"---\ntitle: 3. Using APIs\ndescription: Welcome to Carbon! This tutorial will guide you in creating a Vue app with the Carbon Design System.\ninternal: false\ntabs:\n  ['Overview', 'Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5', 'Wrapping up']\n---\n\nimport Preview from 'components/Preview';\n\n### This step takes our static components and populates them with data from the GitHub GraphQL API – loading states and all. We'll be displaying Carbon repository information in a data table.\n\n<AnchorLinks>\n\n<AnchorLink>Fork, clone and branch</AnchorLink>\n<AnchorLink>Install dependencies</AnchorLink>\n<AnchorLink>Create access token</AnchorLink>\n<AnchorLink>Connect to Apollo</AnchorLink>\n<AnchorLink>Fetch data</AnchorLink>\n<AnchorLink>Populate data table</AnchorLink>\n<AnchorLink>Add loading</AnchorLink>\n<AnchorLink>Add pagination</AnchorLink>\n<AnchorLink>Submit pull request</AnchorLink>\n\n</AnchorLinks>\n\n### Preview\n\nThe [GitHub GraphQL API](https://developer.github.com/v4/) is very well documented, and even though the focus of this tutorial isn't learning and using GraphQL, it's a great opportunity to fetch Carbon-related data for this Carbon tutorial.\n\nTo do so, we'll be using Apollo Client, the front-end component of the [Apollo Platform](https://www.apollographql.com/docs/intro/platform). Apollo provides several open source tools for using GraphQL throughout your application’s stack. Apollo Client is a sophisticated GraphQL client that manages data and state in an application.\n\nA [preview](https://vue-step-4--carbon-tutorial-vue.netlify.com) of what you will build (see repositories page):\n\n<Preview\n  height=\"400\"\n  title=\"Carbon Tutorial Step 3\"\n  src=\"https://vue-step-4--carbon-tutorial-vue.netlify.com\"\n  frameborder=\"no\"\n  allowtransparency=\"true\"\n  allowfullscreen=\"true\"\n  class=\"bx--iframe bx--iframe--border\"\n/>\n\n## Fork, clone and branch\n\nThis tutorial has an accompanying GitHub repository called [carbon-tutorial-vue](https://github.com/carbon-design-system/carbon-tutorial-vue) that we'll use as a starting point for each step. If you haven't forked and cloned that repository yet, and haven't added the upstream remote, go ahead and do so by following the [step 2 instructions](/tutorial/vue/step-2#fork-clone--branch).\n\n### Branch\n\nWith your repository all set up, let's check out the branch for this tutorial step's starting point.\n\n```bash\n$ git fetch upstream\n$ git checkout -b vue-step-3 upstream/vue-step-3\n```\n\n### Build and start app\n\nInstall the app's dependencies:\n\n```bash\n$ yarn\n```\n\nThen, start the app:\n\n```bash\n$ yarn serve\n```\n\nYou should see something similar to where the [previous step](/tutorial/vue/step-2) left off. Stop your app with `CTRL-C` and let's get everything installed.\n\n## Install dependencies\n\nWe'll shortcut this using the Vue CLI, if you'd like more information head over to [Vue Apollo Installation](https://vue-apollo.netlify.com/guide/installation.html#vue-cli-plugin) for details.\n\n_Note: If you have not yet installed the Vue CLI, you will need to [install the Vue CLI](https://cli.vuejs.org/) before running the Vue Apollo Installation._\n\nInstall the following\n\n- `apollo-boost` - package containing everything you need to set up Apollo Client\n- `graphql` - parses your GraphQL queries\n- `vue-apollo` - Apollo integration for Vue\n\nUsing the command:\n\n```bash\n$ vue add apollo\n```\n\nAt the following prompts answer 'No' to each of the questions.\n\n- Add example code? No\n- Add a GraphQL API Server? No\n- Configure Apollo Engine? No\n\n## Create access token\n\nYou'll need a personal access token from your GitHub account in order to make requests to the GitHub API. Check out [this guide](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) to see how to get one.\n\nWhen you get to the scope/permissions step, you can leave them all unchecked. We don't need any special permissions, we just need access to the public API.\n\nOnce you have your token, we need to put it in a place where `create-vue-app` can use it. When your application is being built and developed, create-vue-app will parse environmental variables in any file that starts with `.env` and make them available under `process.env.MY_VARIABLE`.\n\nOne caveat is that we need to start our variables with `VUE_APP_`. You can read more about environmental variables in [create-vue-app's guide](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables).\n\n_Note: If you already have a valid GitHub Personal Access Token, you can use that token here._\n\nSince we don't want to commit this file to Git, we can put it in `.env.local` which is in our `.gitignore` list. Your file should just have a single line like this one, where the `x`s are replaced with your unique token.\n\n##### .env.local\n\n```bash\nVUE_APP_GITHUB_PERSONAL_ACCESS_TOKEN=xxxxxx\n```\n\nGo ahead and start your app with `yarn serve`, or, if your app is running, you'll need to restart it to get access to this token.\n\n## Connect to Apollo\n\nThe `vue-apollo` plugin has made a number of changes to our project.\n\nIf you open `src/main.js` you will see that the CLI has updated this file with the following:.\n\n##### src/main.js\n\n```javascript\nimport { createProvider } from 'vue-apollo';\n\nnew Vue({\n  router,\n  apolloProvider: createProvider(),\n  render: h => h(App),\n}).$mount('#app');\n```\n\nThis is loading from a file the CLI created for you `src/vue-apollo.js` which we need to update to target the github api.\n\n#### src/vue-apollo.js\n\nUpdate the following values:\n\n```javascript\n// Use our access token\nconst AUTH_TOKEN = process.env.VUE_APP_GITHUB_PERSONAL_ACCESS_TOKEN;\n\n// Target github api\nconst httpEndpoint =\n  process.env.VUE_APP_GRAPHQL_HTTP || 'https://api.github.com/graphql';\n```\n\nUpdate only the `wsEndpoint` and `getAuth` properties of the `defaultOptions` object:\n\n```javascript\nconst defaultOptions = {\n  // set wsEndpoint to null\n  wsEndpoint: process.env.VUE_APP_GRAPHQL_WS,\n\n  // Use the form expected by github for authorisation\n  getAuth: tokenName => `Bearer ${tokenName}`,\n};\n```\n\n## Fetch data\n\n### Imports\n\nAdd the following imports to the top of the script section of `RepoPage.vue`:\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\nimport gql from 'graphql-tag';\n```\n\n### Query\n\nNext we'll assemble our GraphQL query to fetch only the data we need from the GraphQL API. We'll do this using the `gql` helper we just imported. The `gql` helper lets you write GraphQL queries using interpolated strings (backticks) in JavaScript. In addition, we'll be using the `Query` component from `vue-apollo` which gives us some great information about our query's loading state in addition to the data.\n\nYou can use GitHub's [explorer](https://developer.github.com/v4/explorer/) tool to write and test your own queries. Try copying the query below and experiment with changing the properties. You can also click the \"Docs\" button in the top right of the explorer to view all of the available data and query parameters.\n\nIf you'd like some more information regarding writing queries and using the Query component, we recommend [Apollo's documentation](https://www.apollographql.com/docs/tutorial/queries) on this topic.\n\nAdd this after your imports:\n\n##### src/views/RepoPage/RepoPage.vue\n\n```graphql\nconst REPO_QUERY = gql`\n  query REPO_QUERY {\n    # Let's use carbon as our organization\n    organization(login: \"carbon-design-system\") {\n      # We'll grab all the repositories in one go. To load more resources\n      # continuously, see the advanced topics.\n      repositories(first: 75, orderBy: { field: UPDATED_AT, direction: DESC }) {\n        totalCount\n        nodes {\n          url\n          homepageUrl\n          issues(filterBy: { states: OPEN }) {\n            totalCount\n          }\n          stargazers {\n            totalCount\n          }\n          releases(first: 1) {\n            totalCount\n            nodes {\n              name\n            }\n          }\n          name\n          updatedAt\n          createdAt\n          description\n          id\n        }\n      }\n    }\n  }\n`;\n```\n\nNext let's we need to configure apollo in our component script, adding the following after the data() declaration.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\napollo: {\n  organization: REPO_QUERY\n},\n```\n\nAt this point, we should run our query view the raw the results to verify that the request is working.\n\nIn RepoPage.vue add the following before the `RepoTable` tag.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```html\n{{ this.organization }}\n```\n\nWhen the data loads you should see the response rendered on your repository page. If not, check the console to see if there are any errors and fix.\n\nRevert this last change and continue.\n\nThis data is not quite in the format our `RepoTable` component is expecting so we'll use a computed property to transform it. Computed properties in Vue cache and watch their reactive dependencies for us.\n\nRemove the 'rows' constant and its use in the data declaration, and add this computed property.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\ncomputed: {\n  rows() {\n      if (!this.organization) {\n      return [];\n    } else {\n      return this.organization.repositories.nodes.map(row => ({\n        ...row,\n        key: row.id,\n        stars: row.stargazers.totalCount,\n        issueCount: row.issues.totalCount,\n        createdAt: new Date(row.createdAt).toLocaleDateString(),\n        updatedAt: new Date(row.updatedAt).toLocaleDateString(),\n        links: { url: row.url, homepageUrl: row.homepageUrl }\n      }));\n    }\n  }\n}\n```\n\nAt this point you have a working table but the links column clearly isn't what we want.\n\n### Helper component\n\nThis column in the data table will be a list of repository and home page links, so let's create a component called `LinkList`.\n\nAdd the following to create your component:\n\nA template section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```html\n<ul class=\"link-list\">\n  <li>\n    <cv-link :href=\"url\">GitHub</cv-link>\n  </li>\n\n  <li v-if=\"homepageUrl\">\n    <span>&nbsp;|&nbsp;</span>\n    <cv-link :href=\"homepageUrl\">Homepage</cv-link>\n  </li>\n</ul>\n```\n\nA script section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```javascript\nexport default {\n  name: 'LinkList',\n  props: {\n    url: String,\n    homepageUrl: String,\n  },\n};\n```\n\nAnd a style section:\n\n##### src/views/RepoPage/LinkList.vue\n\n```scss\n.link-list {\n  display: flex;\n}\n```\n\nNow let's make use of this component in our `RepoTable` component.\n\nAt the top of the script section import the link list component:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\nimport LinkList from './LinkList';\n```\n\nAnd below the name of the component add:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\n  components: { LinkList },\n```\n\nThen make use of it in our template replacing:\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-cell\n  v-for=\"(cell, cellIndex) in row.data\"\n  :key=\"`${cellIndex}`\"\n  >{{cell}}</cv-data-table-cell>\n```\n<!-- prettier-ignore-end -->\n\nwith\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-cell v-for=\"(cell, cellIndex) in row.data\" :key=\"`${cellIndex}`\">\n  <template v-if=\"!cell.url\">\n    {{cell}}\n  </template>\n  <link-list v-else :url=\"cell.url\" :homepage-url=\"cell.homepageUrl\" />\n</cv-data-table-cell>\n```\n<!-- prettier-ignore-end -->\n\nHere in order to switch between the standard rendering of a data cell we've wrapped our standard `{{cell}}` rendering in a template tag. The template tag is non-rendering so it will dissapear, leaving us with the same content as before.\n\nUsing the v-if and v-else directives we switch based on the contents of the cell between the standard rendering and the LinkList component.\n\nChecking our output again, you should now see the LinkList component rendering the final column.\n\nNext we'll update our row description. Update the computed property data() in `RepoTable.vue` to have the following description:\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```javascript\n  description: row.description\n```\n<!-- prettier-ignore-end -->\n\nCheck the output again and you should find the descriptions are updated.\n\nAfter this many refreshes you may have noticed a slight delay in the data loading. As outlined in the [documentation](https://vue-apollo.netlify.com/guide/apollo/#apollo), all components contained under one with an apolloProvider have a `$apollo` attribute. As we added the `apolloProvider` to our app when creating the Vue instance it is available to us everywhere.\n\nWe can use the property to react to [loading state](https://vue-apollo.netlify.com/guide/apollo/queries.html#loading-state).\n\nFirst let's demonstrate that this works.\n\n#### src/views/RepoPage/RepoPage.vue\n\nPass the loading state into our `RepoTable` component by updating the template with the following:\n\n```html\n<repo-table\n  :headers=\"headers\"\n  :rows=\"rows\"\n  title=\"Carbon Repositories\"\n  helperText=\"A collection of public Carbon repositories.\"\n  :loading=\"$apollo.loading\"\n/>\n```\n\nNext add this property to the `RepoTable` component:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\n  props: {\n    headers: Array,\n    rows: Array,\n    title: String,\n    helperText: String,\n    loading: Boolean,\n  },\n```\n\nMaking use of the property to display a loading message.\n\nReplace:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```html\n<cv-data-table\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n></cv-data-table>\n```\n\nwith:\n\n##### src/views/RepoPage/RepoTable.vue\n\n```html\n<div v-if=\"loading\">Loading...</div>\n<cv-data-table\n  v-else\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n></cv-data-table>\n```\n\nHere we have made use of the v-if and v-else directives to switch content based on the state of `$apollo.loading`. If you refresh your app you should see this take effect.\n\nNow that we know this is works let's try something a bit more sophisticated and replace the div containing our loading message with use of the `CvDataTableSkeleton` component.\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n<cv-data-table-skeleton\n  v-if=\"loading\"\n  :columns=\"columns\"\n  :title=\"title\"\n  :helper-text=\"helperText\"\n  :rows=\"10\"\n/>\n```\n<!-- prettier-ignore-end -->\n\nWe need to tell the loading skeleton how many rows to render, so let's use 10 skeleton rows to prepare for the next enhancement...\n\n## Add pagination\n\nPagination! Instead of rendering every repository, let's add pagination to the data table to only render 10 at a time. Depending on your specific requirements, you may need to fetch new data each time that you interact with the pagination component, but for simplicity, we're going to make one request to fetch all data, and then paginate the in-memory row data.\n\nLet's start by adjusting our `PageTable` component template to add pagination. If you review the [storybook notes](http://vue.carbondesignsystem.com/?path=/info/components-cvdatatable--default) you'll see that pagination is added to the data table by supplying a pagination object and listening for pagination events as follows.\n\n##### src/views/RepoPage/RepoTable.vue\n\n<!-- prettier-ignore-start -->\n```html\n  <cv-data-table\n    v-else\n    :columns=\"columns\"\n    :title=\"title\"\n    :helper-text=\"helperText\"\n    :pagination=\"{ numberOfItems: this.totalRows }\"\n    @pagination=\"$emit('pagination', $event)\"\n>\n```\n<!-- prettier-ignore-end -->\n\n_Note: `:prop` is an abbreviation of `v-bind:prop`_\n_Note: `@event` is an abbreviation of `v-on:event`_\n\nIn the pagination event we've used $emit and $event to re-raise the pagination event to our `RepoPage` component so that it can arrange to pass only the rows we want to see to the `RepoTable` component.\n\nWe also need to add the `totalRows` property used in the data tables pagination property.\n\n##### src/views/RepoPage/RepoTable.vue\n\n```javascript\ntotalRows: Number,\n```\n\nNext to our `RepoPage` component, let's first update our template by updating our `RepoTable` use with the following attributes.\n\n##### src/views/RepoPage/RepoPage.vue\n\n<!-- prettier-ignore-start -->\n```html\n:rows=\"pagedRows\"\n:totalRows=\"rows.length\"\n@pagination=\"onPagination\"\n```\n<!-- prettier-ignore-end -->\n\nreplacing\n\n##### src/views/RepoPage/RepoPage.vue\n\n```html\n:rows=\"rows\"\n```\n\nNext in the data property of our component add values for `pageSize`, `pageStart` and `page` into the data method return to support our pagination.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\n  data() {\n    return {\n      headers,\n      pageSize: 0,\n      pageStart: 0,\n      page: 0\n    };\n  },\n```\n\n_Note: We could have passed values for `pageSize` and `page` into our pagination component if we had a specific page or page size we wanted to start with. Instead we are relying on the pagination component to set some sensible defaults and provide us with the details through an event._\n\nThen before we can see our paginated table we need to add: a `pagedRows` computed property to select the slice of input rows we are interested in, and a method to handle the pagination event.\n\n##### src/views/RepoPage/RepoPage.vue\n\n```javascript\n  computed: {\n    // other computed properties\n    // ...\n    pagedRows() {\n      return this.rows.slice(this.pageStart, this.pageStart + this.pageSize);\n    }\n  },\n  methods: {\n    onPagination(val) {\n      this.pageSize = val.length;\n      this.pageStart = val.start;\n      this.page = val.page;\n    }\n  }\n```\n\n_Note: Like the other Carbon Vue components,_ `Pagination` _component examples can be found in [Storybook](http://vue.carbondesignsystem.com/?path=/story/components-cvpagination--default) by browsing the story and knobs._\n\nThat does it! Your data table should fetch GitHub data on first render. You can expand each row to see the repository's description. You can modify the pagination items per page and cycle through pages or jump to a specific page of repositories.\n\n## Mystery\n\nHmmm, there is at least one more issue to resolve. If you expand a row or two to see the repository descriptions you will and then change page. What happens?\n\nAssuming you didn't catch this earlier you will find that the expanded rows, stay expanded after paging. That is if row two was expanded before pagination it is expanded after.\n\nThis is because we chose poor values to use as our row and cell keys as we iterated over them. The result is that Vue sees these items as having the same key and makes the assumption that content but not state has changed.\n\nTo fix this add the following to the RepoPage component you should be able to find something better.\n\n```javascript\n  watch: {\n    rows() {\n      if (this.organization) {\n        console.dir(this.organization.repositories.nodes);\n      }\n    }\n  },\n```\n\n_Hint: `id` and `url` are likely unique properties, you could use either of these to update the prototype. In fact we already pass the id value to RepoTable._\n\nCan you fix it?\n\n## Submit pull request\n\nWe're going to submit a pull request to verify completion of this tutorial step.\n\n### Continuous integration (CI) check\n\nRun the CI check to make sure we're all set to submit a pull request.\n\n```bash\n$ yarn ci-check\n```\n\n_Note: Having issues running the CI check? [Step 1](/tutorial/vue/step-1#continuous-integration-ci-check) has troubleshooting notes that may help._\n\n### Git commit and push\n\nBefore we can create a pull request, stage and commit all of your changes:\n\n```bash\n$ git add --all && git commit -m \"feat(tutorial): complete step 3\"\n```\n\nThen, push to your repository:\n\n```bash\n$ git push origin vue-step-3\n```\n\n_Note: Having issues pushing your changes? [Step 1](/tutorial/vue/step-1#git-commit-and-push) has troubleshooting notes that may help._\n\n### Pull request (PR)\n\nFinally, visit [carbon-tutorial-vue](https://github.com/carbon-design-system/carbon-tutorial-vue) to \"Compare & pull request\". In doing so, make sure that you are comparing to `vue-step-3` into `base: vue-step-3`.\n\n_Note: Expect your tutorial step PRs to be reviewed by the Carbon team but not merged. We'll close your PR so we can keep the repository's remote branches pristine and ready for the next person!_\n","fileAbsolutePath":"/tmp/42b44a0/src/pages/tutorial/vue/step-3.mdx"}}}}