<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Brian Barrow</title>
    <description>The latest articles on DEV Community by Brian Barrow (@briancbarrow).</description>
    <link>https://dev.to/briancbarrow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F346403%2F2cc05e5b-8a8e-45ae-8da4-63960afb185b.png</url>
      <title>DEV Community: Brian Barrow</title>
      <link>https://dev.to/briancbarrow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/briancbarrow"/>
    <language>en</language>
    <item>
      <title>Generating Collapsable Navigation from Nuxt Content</title>
      <dc:creator>Brian Barrow</dc:creator>
      <pubDate>Mon, 07 Feb 2022 20:34:46 +0000</pubDate>
      <link>https://dev.to/deepgram/generating-collapsable-navigation-from-nuxt-content-178d</link>
      <guid>https://dev.to/deepgram/generating-collapsable-navigation-from-nuxt-content-178d</guid>
      <description>&lt;p&gt;When we started building the &lt;a href="https://developers.deepgram.com/documentation/"&gt;Documentation page here at Deepgram&lt;/a&gt;, we had a lot of nested pages and routes. Rather than have all those links listed out on the side, we wanted the user to be able to expand and collapse them in order to have a cleaner look and feel.&lt;/p&gt;

&lt;p&gt;At the top level of our navigation, we have a &lt;code&gt;SideNavigation.vue&lt;/code&gt; component that gets the navigation information from a &lt;code&gt;navigation.yml&lt;/code&gt; file in our content folder. Each navigation element can have a &lt;code&gt;children&lt;/code&gt; property (shown below) that lists out the child routes of that page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TuWQsusJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzwohdifse7anybe98qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TuWQsusJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzwohdifse7anybe98qy.png" alt="screenshot showing navigation routes and child navigation routes" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the original template we had set up for the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt;
      &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"nav of navigation"&lt;/span&gt;
      &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"nav.to"&lt;/span&gt;
      &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;{ active: isActive(nav) }"
    &amp;gt;
      &lt;span class="nt"&gt;&amp;lt;NuxtLink&lt;/span&gt; &lt;span class="na"&gt;:to=&lt;/span&gt;&lt;span class="s"&gt;"nav.to"&lt;/span&gt; &lt;span class="na"&gt;:title=&lt;/span&gt;&lt;span class="s"&gt;"nav.title || nav.name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt;
        &lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/NuxtLink&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;NavList&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"nav.children"&lt;/span&gt; &lt;span class="na"&gt;:navigation=&lt;/span&gt;&lt;span class="s"&gt;"nav.children"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component was recursively going through the navigation object and creating new NavList components if there were children routes. Basically, it is rendering another version of itself inside of itself. So the NavList component renders another NavList component. Sort of like component Inception. Don't worry about an infinite rendering of NavLists though. It will render a child NavList only if there are children to the navigation object.&lt;/p&gt;

&lt;p&gt;I like the fact that it is recursive, making it dynamic. That way, we don't have to specify when to use a 'child' &lt;code&gt;NavList&lt;/code&gt; component. It also presented a problem. I needed some way to identify which sub-menus were open and which were not. After some thought and some rubber ducking, I settled on having a data property containing an array of the parent route paths that were expanded. I called it &lt;code&gt;childrenShow&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;childrenShow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a parent route has a path of &lt;code&gt;/documentation/getting-started/&lt;/code&gt;, the entire string gets pushed into the array. Then, as the child &lt;code&gt;NavList&lt;/code&gt; components get added to the page, I needed to check if they should be shown using a &lt;code&gt;v-show&lt;/code&gt; directive. I did this by using the &lt;code&gt;isExpanded&lt;/code&gt; method, which takes in the current &lt;code&gt;nav&lt;/code&gt; object (which comes from the original YAML file for the nav list structure via the &lt;code&gt;v-for&lt;/code&gt; above) and checks it against the &lt;code&gt;childrenShow&lt;/code&gt; array to see if should be shown.&lt;/p&gt;

&lt;p&gt;Also, since there is already a v-if on the &lt;code&gt;NavList&lt;/code&gt;, and I can't use both a v-if and a v-show on the same element, I had to create a container template to handle the v-if. So the &lt;code&gt;NavList&lt;/code&gt; line will change to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"nav.children"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;NavList&lt;/span&gt; &lt;span class="na"&gt;v-show=&lt;/span&gt;&lt;span class="s"&gt;"isExpanded(nav)"&lt;/span&gt; &lt;span class="na"&gt;:navigation=&lt;/span&gt;&lt;span class="s"&gt;"nav.children"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked well as-is. The menus collapse and expand when the user clicks on the respective expand/collapse button. The only issue now is that the transition wasn't smooth, which can be a little jarring.&lt;/p&gt;

&lt;p&gt;After playing with transitions for a while and not having much success for this use case, I talked to a co-worker, and he sent me &lt;a href="https://markus.oberlehner.net/blog/transition-to-height-auto-with-vue/"&gt;this article from Markus Oberlehner&lt;/a&gt; that talks about transitioning to an element's full height. So I created a new component called &lt;code&gt;TransitionExpand.vue&lt;/code&gt; and put this code in there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`TransitionExpand`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;functional&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`expand`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;afterEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// eslint-disable-next-line no-param-reassign&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`auto`&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="cm"&gt;/* eslint-disable no-param-reassign */&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`absolute`&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`hidden`&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`auto`&lt;/span&gt;
          &lt;span class="cm"&gt;/* eslint-enable */&lt;/span&gt;

          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="cm"&gt;/* eslint-disable no-param-reassign */&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="cm"&gt;/* eslint-enable */&lt;/span&gt;

          &lt;span class="c1"&gt;// Force repaint to make sure the&lt;/span&gt;
          &lt;span class="c1"&gt;// animation is triggered correctly.&lt;/span&gt;
          &lt;span class="c1"&gt;// eslint-disable-next-line no-unused-expressions&lt;/span&gt;
          &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;

          &lt;span class="nx"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// eslint-disable-next-line no-param-reassign&lt;/span&gt;
            &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="c1"&gt;// eslint-disable-next-line no-param-reassign&lt;/span&gt;
          &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;

          &lt;span class="c1"&gt;// Force repaint to make sure the&lt;/span&gt;
          &lt;span class="c1"&gt;// animation is triggered correctly.&lt;/span&gt;
          &lt;span class="c1"&gt;// eslint-disable-next-line no-unused-expressions&lt;/span&gt;
          &lt;span class="nx"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;

          &lt;span class="nx"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// eslint-disable-next-line no-param-reassign&lt;/span&gt;
            &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`transition`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;will-change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;backface-visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.expand-enter-active&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.expand-leave-active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.expand-enter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.expand-leave-to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a lot of stuff happening in that component. To understand it better, visit the link above to Markus' blog. He goes into the detail you need.&lt;/p&gt;

&lt;p&gt;I then changed the template tag that was containing the child &lt;code&gt;NavList&lt;/code&gt; component, to a &lt;code&gt;transition-expand&lt;/code&gt; tag like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;expand&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav.children&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavList&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isExpanded(nav)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav.children&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/transition-expand&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That made the expand/collapse transition much smoother and created a better user experience. It was a challenging problem that was fun to figure out. If you want to see a working example of it, you can check out this &lt;a href="https://codesandbox.io/s/serene-stitch-30zmi"&gt;code sandbox&lt;/a&gt;. If you want to see it on our production site, you can see it on our &lt;a href="https://developers.deepgram.com/documentation/"&gt;Documentation page&lt;/a&gt;.&lt;/p&gt;



</description>
    </item>
    <item>
      <title>Getting Started with the MediaStream API</title>
      <dc:creator>Brian Barrow</dc:creator>
      <pubDate>Mon, 13 Dec 2021 21:16:02 +0000</pubDate>
      <link>https://dev.to/deepgram/getting-started-with-the-mediastream-api-14b8</link>
      <guid>https://dev.to/deepgram/getting-started-with-the-mediastream-api-14b8</guid>
      <description>&lt;p&gt;When building web applications, you will sometimes need to work with audio and/or video inputs. You'll need to understand the MediaStream API, which is the web API that supports streaming both audio and video information. In this post, we'll cover the basics of the MediaStream API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;To get started, you'll need to gain access to the user's audio/video devices which provide data in a 'stream.' A common use case would be getting access to the user's microphone and camera. One of the most common ways to do this is through the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia"&gt;getUserMedia&lt;/a&gt; method that is built into the browser. This post is more about understanding the different parts of the API. To see this method used in action, refer to &lt;a href="https://developers.deepgram.com/blog/2021/11/live-transcription-mic-browser/"&gt;Kevin's post about getting audio in the browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's take the following code, insert it into an HTML file, and then open that file in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Getting Started With MediaStream&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MEDIA STREAM: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PERMISSION DENIED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will prompt you to allow access to the microphone on your machine. If you reject it, you'll get an alert saying &lt;code&gt;PERMISSION DENIED.&lt;/code&gt; If you allow that, then you will see the following in your console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0g1d_MLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4ap62an2sftsjdi4fhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0g1d_MLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4ap62an2sftsjdi4fhj.png" alt="Devtools console result showing the MediaStream object that is initialized on page load" width="480" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there are several properties and methods available on the MediaStream object. Before we dive into these, I want to clarify a couple of definitions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;stream&lt;/strong&gt;: A stream of media content. Regarding what we'll be discussing, this refers to the stream of information coming from a user's device. The stream will be coming from either the device's microphone or the camera, or both at the same time. A stream will consist of one or more 'tracks.'&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;track&lt;/strong&gt;: A &lt;code&gt;track&lt;/code&gt; is a piece of media within a stream. These are typically audio or video tracks. If we get access to both a microphone and a camera, our stream will consist of both an audio and a video track.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Properties
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;active&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one we see is the &lt;code&gt;active&lt;/code&gt; property. This property is simply a boolean value indicating if any part of the MediaStream object is currently active or being used. Most MediaStream objects you'll encounter will contain audio and/or video tracks. If any of these tracks is &lt;code&gt;active,&lt;/code&gt; then the &lt;code&gt;active&lt;/code&gt; property on the MediaStream object will be true.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;id&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The other property available on our MediaStream object is the id, a unique identifier for the object and contains 36 characters. This will be helpful if you need to keep track of multiple streams and do different things with them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Methods
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;addTrack&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method takes in a &lt;code&gt;MediaStreamTrack&lt;/code&gt; as an argument and adds it to the MediaStream object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zsFF-eZy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blfgwigj92fgrjdv1u0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zsFF-eZy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blfgwigj92fgrjdv1u0m.png" alt="image showing that a track gets added to the MediaStream object when addTrack is called" width="880" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;getTracks&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This returns a list of all &lt;code&gt;MediaStreamTrack&lt;/code&gt; objects associated with the stream. To test it out, let's add the &lt;code&gt;getTracks&lt;/code&gt; method to our code. I've included the &lt;code&gt;video: true&lt;/code&gt; in the constraints so we can see multiple tracks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Getting Started With MediaStream&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tracks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTracks&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PERMISSION DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see in the screenshot below that we get both the audio and the video tracks showing:&lt;br&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dQcV_Ua8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27sa3g8vpllft5qm1vc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dQcV_Ua8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27sa3g8vpllft5qm1vc5.png" alt="Console showing the results of the stream.getTracks() call" width="535" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;getAudioTracks&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This returns a list of &lt;code&gt;MediaStreamTrack&lt;/code&gt; objects that are &lt;strong&gt;audio&lt;/strong&gt; types. If we used this instead of &lt;code&gt;getTracks&lt;/code&gt; above, we would have gotten the list with only the audio track showing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getVideoTracks&lt;/strong&gt;&lt;br&gt;
This returns a list of &lt;code&gt;MediaStreamTrack&lt;/code&gt; objects that are &lt;strong&gt;video&lt;/strong&gt; types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getTrackById&lt;/strong&gt;&lt;br&gt;
This method takes in a string and will return the track from the MediaStream object with the corresponding id.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Getting Started With MediaStream&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trackId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAudioTracks&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getTrackById&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTrackById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trackId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PERMISSION DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;removeTrack&lt;/strong&gt;
This method removes the given track from the &lt;code&gt;MediaStream&lt;/code&gt; object. When we add a button to remove the track to our code and then log the &lt;code&gt;MediaStream.getTracks&lt;/code&gt; to the dev tools console, we can see it is no longer there. If we were displaying a video stream to a div on our page and removed the video track, then the stream would no longer appear.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Getting Started With MediaStream&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTracks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tracks before remove&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// remove both tracks&lt;/span&gt;
            &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tracks after remove&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTracks&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PERMISSION DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YH69baMl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3l396yunaelppbm8c63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YH69baMl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3l396yunaelppbm8c63.png" alt="browser devtools console showing the MediaStream object before and after the removeTrack has been called" width="595" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Events
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events"&gt;Events&lt;/a&gt; are simply actions that happen in the system you are programming, which the system tells you about so your code can react to them if needed. An &lt;code&gt;event listener is a function that runs when a specific event occurs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should be aware of a few events on the &lt;code&gt;MediaStream&lt;/code&gt; object.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;addtrack&lt;/strong&gt;&lt;br&gt;
Fired when a new track object is added.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Event listener:&lt;/em&gt; &lt;code&gt;onaddtrack&lt;/code&gt; is fired when a new track is added. To use the event listener, assign it to a function that you want to be called whenever a track is added.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onaddtrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// code to execute when track is added&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PERMISSION DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;removetrack&lt;/strong&gt;
Fired when a new track object is added.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Event listener:&lt;/em&gt; &lt;code&gt;onremovetrack&lt;/code&gt; is fired when a new track is removed. To use the event listener, assign it to a function you want to be called whenever a track is removed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MediaStream&lt;/code&gt; API is beneficial and can be utilized in the applications that you build. I hope this has been informative and helped you as a web developer.&lt;/p&gt;

</description>
      <category>mediastream</category>
      <category>api</category>
      <category>web</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Getting Started with Supabase</title>
      <dc:creator>Brian Barrow</dc:creator>
      <pubDate>Mon, 06 Dec 2021 17:15:11 +0000</pubDate>
      <link>https://dev.to/deepgram/getting-started-with-supabase-3egp</link>
      <guid>https://dev.to/deepgram/getting-started-with-supabase-3egp</guid>
      <description>&lt;p&gt;Getting a database set up and running can be a difficult and time-consuming process. There are quite a few options these days for "quick" solutions. Supabase is one of those options and is gaining popularity very quickly. Let's dive in and see what Supabase offers. We'll walk through an example of setting up a database for a Reading List app and learn how to add, read, edit, and delete data from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this post is for
&lt;/h2&gt;

&lt;p&gt;This post will be easier to follow if you have a general understanding of how databases work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;The first thing you'll need to do is sign up on &lt;a href="https://app.supabase.io/api/login" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;. It asks you to sign up with GitHub, so if you don't have an account, you should also sign up for one of those.&lt;/p&gt;

&lt;p&gt;Once you are signed in, you'll click the green button that says "New Project" and select the default organization that was created when you logged in. Mine was called "briancbarrow's Org." This will bring up a box where we provide some info about the project. I'll name it &lt;code&gt;reading-list&lt;/code&gt;, give it a strong password, and then I'm going to select the region &lt;code&gt;West US (North California)&lt;/code&gt; because that is closest to me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesqy2z8jmmfst1dyw2io.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesqy2z8jmmfst1dyw2io.png" alt="Setting up the project with the name reading-list and selecting the West US region."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the "Create new project" button. It will take a few minutes for the project to be ready, so sit tight until that finishes.&lt;/p&gt;

&lt;p&gt;Now that we have that set up, you should see a page with the name of the project you gave, and below that, it should say "Welcome to your new project." Below that, there are a few features that we can start exploring.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: The Supabase Database is an instance of a Postgres Database. We'll be diving into this more below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt;: The Supabase Auth service makes it relatively easy to set up authentication for your app and also manage your users. We won't be covering Auth in this post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: Supabase offers a storage service for larger files like images or audio files. We won't be covering Storage in this post either.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Initializing the Database
&lt;/h2&gt;

&lt;p&gt;Click on the button in the "Database" card that says "Table editor." This takes us to a blank dashboard where we'll be able to add and edit our database tables. Click the &lt;code&gt;+ New table&lt;/code&gt; button on the left and give it the name &lt;code&gt;books&lt;/code&gt;. For now don't check the "Enable Row Level Security (RLS)." This table will need a few columns in addition to the "id" column. I've listed them below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Column Name: &lt;code&gt;title&lt;/code&gt;, Type: &lt;code&gt;varchar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Column Name: &lt;code&gt;author&lt;/code&gt;, Type: &lt;code&gt;varchar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Column Name: &lt;code&gt;finished&lt;/code&gt; Type: &lt;code&gt;bool&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The table might already have a 'created_at' column in there by default. We won't need it so you can remove that one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pqgbyxp1r19lzh459r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0pqgbyxp1r19lzh459r0.png" alt="Add new table with the name 'books', leave Row Level Security unchecked, and add title column with type varchar, add author column with type varchar, and add finished column with type bool."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save that, and you've created a table in your database. You should now be able to see it. Let's fill in some data now. Click the button that says "Insert Row" and fill in the data with a couple of books you like. Remember that you can only insert the type of data into columns that you specified in the table setup. For example, we couldn't store a string inside the "finished" column because it only accepts booleans. &lt;a href="https://www.postgresqltutorial.com/postgresql-data-types/" rel="noopener noreferrer"&gt;Here is a link to more info on data types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is what my table looked like after I inserted two rows of data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhi2mkk9qc2ra9o2jyn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhi2mkk9qc2ra9o2jyn8.png" alt="Added two rows of data with the respective titles and authors of books. One with 'finished' set to true and the other to false."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying the Database
&lt;/h2&gt;

&lt;p&gt;With the data added, we can now look at how to send &lt;a href="https://developers.deepgram.com/blog/2021/11/getting-started-with-apis/" rel="noopener noreferrer"&gt;API requests&lt;/a&gt; to it in order to read that data.&lt;/p&gt;

&lt;p&gt;In the left hand navigation, there is a link to the API documentation. This is auto-generated for us by Supabase and allows us to connect with our database in our code. Right now, we want to test that we can get the data we want from our &lt;code&gt;books&lt;/code&gt; table. In the left hand menu, there is a section called "Tables and Views". Select the &lt;code&gt;books&lt;/code&gt; table. Since we don't have a JavaScript app set up yet, select the "Bash" tab at the top of the right hand column above the code output. This will show us how a basic request is structured. I am going to be using Postman &lt;a href="https://www.postman.com/downloads/" rel="noopener noreferrer"&gt;(which you can get here)&lt;/a&gt; to send these requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading data
&lt;/h3&gt;

&lt;p&gt;Go down to the section that says "READ ALL ROWS", where you'll find the &lt;code&gt;curl&lt;/code&gt; request to get the information from our database.&lt;/p&gt;

&lt;p&gt;Here is what it should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://swmsbxvlhkqilunwmsgs.supabase.co/rest/v1/books?select=*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"apikey: SUPABASE_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer SUPABASE_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can put this info into an app like Postman, or you can copy this code and put it directly into your terminal to get the results. Note that the &lt;code&gt;SUPABASE_KEY&lt;/code&gt; in the above code is just a placeholder for your own key. To get your API keys to populated into the example requests, there is a dropdown labeled "Key" up at the top of the screen. Select &lt;code&gt;anon key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since I'm using Postman for these requests I'll first copy the URL from the &lt;code&gt;curl&lt;/code&gt; line and paste it into the request URL field in Postman. For this request we'll keep it as a &lt;code&gt;GET&lt;/code&gt; request. I'll then click on the "Headers" tab inside Postman and add the &lt;code&gt;apikey&lt;/code&gt; and &lt;code&gt;Authorization&lt;/code&gt; headers respectively. It will look something like this, with your URL and API Keys instead of mine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg069wazhb9k8a9rg4wfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg069wazhb9k8a9rg4wfm.png" alt="Postman GET request with URL parameter specifying to select all"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Inserting data via the API
&lt;/h3&gt;

&lt;p&gt;Now we can send the request and the results will show the contents of our books table. But what if we want to add or update data using the API? Inside of the API page of our Supabase app there are examples of all these types of requests. Let's try to insert data. I'll find the "Insert Rows" section of the API documentation and create a new request in Postman with the required fields.&lt;br&gt;
The request with the new headers you'll need should look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qpc2ledtt2d8set8h5m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qpc2ledtt2d8set8h5m.png" alt="Postman POST request with just base URL and apikey, Authorization, Content-Type, and Prefer headings set as per the API documentation on Supabase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This request requires a body of data to be sent to the API endpoint. Add some raw JSON data to the body tab of the request like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozcf3rv1airbfp7p83rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozcf3rv1airbfp7p83rs.png" alt="Postman POST request showing the body tab of the above request. Body contains a JSON object with title and author values."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we send this, if it is successful, it will return with the item we just inserted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating data
&lt;/h3&gt;

&lt;p&gt;A lot of times we have data in the app that needs to be changed/updated. In the API documentation this will be found under the "Update rows" section. This request is shaped a lot like the Insert request we did above. The first difference is that this is a &lt;em&gt;PATCH&lt;/em&gt; request instead of a &lt;em&gt;POST&lt;/em&gt; request. (Note that we use a &lt;em&gt;PATCH&lt;/em&gt; to update instead of a &lt;em&gt;PUT&lt;/em&gt; because &lt;em&gt;PATCH&lt;/em&gt; allows us to update only specific fields, while &lt;em&gt;PUT&lt;/em&gt; requires us to send the entire object with the request. We could have used &lt;em&gt;PUT&lt;/em&gt; in this case, but the &lt;em&gt;PATCH&lt;/em&gt; makes it more flexible in the future. &lt;a href="https://stackoverflow.com/a/34400076" rel="noopener noreferrer"&gt;See this link&lt;/a&gt; for more details on the difference). The second difference is in the URL. At the end of the URL there is a parameter. In the example from the API documentation they have it shown as &lt;code&gt;?some_column=eq.someValue&lt;/code&gt;. This is where we tell the database which row we want updated. So in our case, we can put &lt;code&gt;?id=eq.2&lt;/code&gt; to update the book with the ID of &lt;code&gt;2&lt;/code&gt;. Let's update the title to "The Graveyard Book" and the author to "Neil Gaiman."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc7dqqxeu9np2ws60cqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc7dqqxeu9np2ws60cqk.png" alt="Postman PATCH request with URL specifying which row we want updated. Also with JSON body with new title and author values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting data
&lt;/h3&gt;

&lt;p&gt;We also need to be able to delete data from our table. Like before, look at the example request in the API documentation page. It is similar to the Update request above. There aren't as many headers needed though and we don't pass any data. We need to specify which row though using a parameter again and make sure you change the type of request to a &lt;em&gt;DELETE&lt;/em&gt; request. Let's delete the same book we just updated. The request will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwzab40l2lxem72lyuw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwzab40l2lxem72lyuw6.png" alt="Postman DELETE request specifying which row we want to be deleted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you navigate back to the Tables page of the Supabase UI, you should only see the first book you created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now you know the basics of how to set up and use a Supabase Database. This tutorial just scratched the surface of Supabase, but it should give you a solid start.&lt;/p&gt;

&lt;p&gt;Before you start using the database in an app, you'll also want to add the "Row Level Security" to your tables. This is beyond the scope of this introduction to Supabase blog, but basically it makes it so only authenticated users can affect the data in the tables. You can find out more in the &lt;a href="https://supabase.io/docs/guides/auth/row-level-security" rel="noopener noreferrer"&gt;Supabase documentation page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>database</category>
      <category>supabase</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
