Categories
BootstrapVue

BootstrapVue — Table Transitions and Sorting

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

We look at how to customize table contents, including transitions and sorting.

Table Body Transition

We can add table body transitions to our table’s body.

To do that, we can add the tbody-transition-prois to add transition-group properties in an object.

The tbody-transition-handlers kets us add transition-groip event handlers from an object.

primary-lkey is a string that specifies the fields to use as a unique row key.

For instance, we can write:

<template>
  <div id="app">
    <b-table primary-key="id" :tbody-transition-props="transProps" :items="items" :fields="fields"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      fields: [
        { key: "id", sortable: true },
        { key: "firstName", sortable: true },
        { key: "lastName", sortable: true }
      ],
      transProps: {
        name: "flip-list"
      },
      items: [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

<style>
table .flip-list-move {
  transition: transform 1s;
}
</style>

We added transition effects when we sort the table rows.

To do that, we added the tbody-transition-props prop which is set to the transProps object.

The object has a name for the transition.

The name should match the prefix class of the CSS transition.

Therefore, in the style tag, we have the flip-list-move class, which starts with flip-list .

primary-key is also set to the unique key column in our table, which is id .

We make the sortable with the sortable property in each fields array entry.

Now when we click the sort button on each field, we’ll see a fade effect displayed.

Sorting

BootstrapVue tables are sortable.

We can specify the props for sorting the tables.

To specify the columns to be sorted, we can use the sort-by prop.

The direction can be set by sort-desc set to true or false .

This way, we can sort the value from highest to lowest or vice versa respectively.

When foot-clone is set, the footer headings will also allow sorting by clicking.

This is true even if we have custom footers.

For example, we can write:

<template>
  <div id="app">
    <b-table sort-by="id" sortDesc :items="items" :fields="fields"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      fields: [
        { key: "id", sortable: true },
        { key: "firstName", sortable: true },
        { key: "lastName", sortable: true }
      ],
      items: [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

We added the sort-by prop with the name of the field we want to sort.

It’s set to id to sort by id .

sortDesc lets us sort the column in descending order.

Therefore we have the rows sorted by the id column in descending order.

Customizing Sort Icons

We can customize the CSS to change the sort icon.

Sort Compare

We can change how the entries are compared with the sort-compare prop set to a function to let us customize sorting.

For instance, we can write:

<template>
  <div id="app">
    <b-table sort-compare='sortCompare' :items="items" :fields="fields"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      fields: [
        { key: "id", sortable: true },
        { key: "firstName", sortable: true },
        { key: "lastName", sortable: true }
      ],
      items: [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    };
  },
  methods: {
    sortCompare(
      aRow,
      bRow,
      key,
      sortDesc,
      formatter,
      compareOptions,
      compareLocale
    ) {
      return aRow[key].localeCompare(bRow[key], compareLocale, compareOptions);
    }
  }
};
</script>

We gave the sortCompare which we set as the value of sort-compare .

In the method, we can pass in compareLocale and compareOptions to the localeCompare method of a string to sort them.

Conclusion

We can add table body transitions to add effects when manipulating rows.

Also, we can sort columns our way with the built-in props or a custom sorting function.

Categories
BootstrapVue

BootstrapVue — Customizing Progress Bars and Sidebars

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

We look at how to customize progress bars and add sidebars.

Width and Height

We can change the width of the b-progress component the way we like.

For instance, we can write:

<template>
  <div id="app">
    <b-progress :value="value" class="w-50 mb-2"></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 75
    };
  }
};
</script>

to make it fill half the screen.

The height can also be changed.

For example, we can write:

<template>
  <div id="app">
    <b-progress :value="value" height="2rem"></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 75
    };
  }
};
</script>

We set the height to 2rem , so the progress bar would be taller.

Backgrounds

We can change the background of the progress bar the way we like.

This can be done with the variant prop.

For example, we can write:

<template>
  <div id="app">
    <b-progress :value="value" variant="success"></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 75
    };
  }
};
</script>

Then we see a green bar because we set the variant to 'success' .

Striped Backgrounds

The background of a progress bar can be made striped.

To make it striped, we add the striped prop.

For example, we can write:

<template>
  <div id="app">
    <b-progress :value="value" striped></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 75
    };
  }
};
</script>

Now the bar is striped.

Animated Backgrounds

The background of the progress bar can be also be animated.

We just have to set the animated prop to do that:

<template>
  <div id="app">
    <b-progress :value="value" animated></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 75
    };
  }
};
</script>

Sidebar

We can create a sidebar with BootstrapVue.

This is a component that’s available since 2.10.0.

To create one, we use the b-sidebar component:

<template>
  <div id="app">
    <b-button v-b-toggle.sidebar>Toggle</b-button>
    <b-sidebar id="sidebar" title="Sidebar" shadow>
      <div class="px-3 py-2">
        <p>foo</p>
        <b-img src="http://placekitten.com/200/200" fluid thumbnail></b-img>
      </div>
    </b-sidebar>
  </div>
</template>

<script>
export default {};
</script>

We have the v-b-toggle directive.

The sidebar modifier matches the name of the id of the b-sidebar to let us open the sidebar.

On the b-siderbar component, we set the title prop, which sets the title.

shadow enables shadows.

And the rest of the content displayed below the title.

Placement

The placement can be changed with props.

The right prop will put the sidebar on the right instead of the left.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-toggle.sidebar>Toggle</b-button>
    <b-sidebar id="sidebar" title="Sidebar" right  shadow>
      <div class="px-3 py-2">
        <p>foo</p>
        <b-img src="http://placekitten.com/200/200" fluid thumbnail></b-img>
      </div>
    </b-sidebar>
  </div>
</template>

<script>
export default {};
</script>

Now the sidebar opens from the right instead of the left.

Styling Variants

We can use the bg-variant to change the styling variant of the background.

The text-variant is used to change the styling of the text.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-toggle.sidebar>Toggle</b-button>
    <b-sidebar id="sidebar" title="Sidebar" bg-variant="success" text-variant="light" shadow>
      <div class="px-3 py-2">
        <p>foo</p>
        <b-img src="http://placekitten.com/200/200" fluid thumbnail></b-img>
      </div>
    </b-sidebar>
  </div>
</template>

<script>
export default {};
</script>

Then the text is white since text-variant is light .

bg-variant is success so the background is green.

Borders

We can add borders with BootstrapVue’s border utility classes.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-toggle.sidebar>Toggle</b-button>
    <b-sidebar id="sidebar" title="Sidebar" sidebar-class="border-right border-success">
      <div class="px-3 py-2">
        <p>foo</p>
        <b-img src="http://placekitten.com/200/200" fluid thumbnail></b-img>
      </div>
    </b-sidebar>
  </div>
</template>

<script>
export default {};
</script>

We added the sidebar-class prop to let us set the border class.

border-right adds the border to the right.

border-success makes the border green.

Conclusion

The progress bar can be styled the way we want.

Also, we can add sidebars with BootstrapVue.

We can add content and control background, border, and text colors.

Categories
BootstrapVue

BootstrapVue — Table Rows and Columns

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

We look at how to customize table contents, including sticky columns and row selection.

Sticky Columns

We can make columns sticky with the stickyColumn property in a field entry.

For instance, we can write:

<template>
  <div id="app">
    <b-table :items="items" sticky-header :fields="fields"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      fields: [
        {
          key: "id",
          stickyColumn: true,
          isRowHeader: true,
          variant: "primary"
        },
        "a",
        "b",
        { key: "c", stickyColumn: true, variant: "info" },
        "d",
        "e",
        "f",
        "g",
        "h",
        "i"
      ],
      items: [
        {
          id: 1,
          a: 0,
          b: 1,
          c: 2,
          d: 3,
          e: 4,
          f: 5,
          g: 6,
          h: 7,
          i: 8
        },
        {
          id: 2,
          a: 0,
          b: 1,
          c: 2,
          d: 3,
          e: 4,
          f: 5,
          g: 6,
          h: 7,
          i: 8
        },
        {
          id: 3,
          a: 0,
          b: 1,
          c: 2,
          d: 3,
          e: 4,
          f: 5,
          g: 6,
          h: 7,
          i: 8
        }
      ]
    };
  }
};
</script>

We have the stickyColumn property set to true in our field entries.

We also have the sticky-header to keep the header displaying.

Now the Id and C columns will always be shown.

Row Details

We can add row details into our table rows.

To do that, we can populate the row-details slot.

For example, we can write:

<template>
  <div id="app">
    <b-table :items="items" :fields="fields">
      <template v-slot:cell(showDetails)="row">
        <b-button
          size="sm"
          @click="row.toggleDetails"
          class="mr-2"
        >{{ row.detailsShowing ? 'Hide' : 'Show'}} Details</b-button>
      </template>

<template v-slot:row-details="row">
        <b-card>
          <b-row class="mb-2">
            <b-col>
              <b>Age:</b>
            </b-col>
            <b-col>{{ row.item.age }}</b-col>
          </b-row>

<b-button size="sm" @click="row.toggleDetails">Hide Details</b-button>
        </b-card>
      </template>
    </b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      fields: ["firstName", "lastName", "showDetails"],
      items: [
        { firstName: "alex", lastName: "green", age: 20 },
        {
          firstName: "may",
          lastName: "smith",
          age: 20
        },
        { firstName: "james", lastName: "jones", age: 22 }
      ]
    };
  }
};
</script>

We referenced the row.toggleDetails method in the cell(showDetails) slot.

This lets us toggle the details.

row.detailsShowing is true if the row details are showing and false otherwise.

Then we populated the row-details slots.

It also has access to the row data.

row.item has the data.

So we can access the age with row.item.age .

It also has access to the toggleDetails method to toggle off the details.

Row Selection

We can let users select rows on the table.

To do that, we can add the select-mode prop.

The value can be 'multi' for mukltuple selection.

'single' for single selection.

And 'range' for letting people shift-click a range of rows. Ctrl-click will let them toggle the selected row.

Rows can be programmatically selected or unselected.

selectRow(index) lets us select a row with the given index.

unselectRow(index) unselectes a row with the given index.

selectAllRows() selects all rows.

clearSelected() unselects all rows.

isRowSelected(index) returns true if a row is selected.

We can write:

<template>
  <div id="app">
    <b-table :items="items" selectable select-mode="multi"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      items: [
        { firstName: "alex", lastName: "green" },
        {
          firstName: "may",
          lastName: "smith"
        },
        { firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

to make the rows selectable.

We added selectable to make the rows selectable and select-mode is set to 'multi' to let users select any rows they like.

Then to call the methods we listed above, we can write:

<template>
  <div id="app">
    <b-button [@click](http://twitter.com/click "Twitter profile for @click")='clearSelected'>clear selection</b-button>
    <b-table ref='selectableTable' :items="items" selectable select-mode="multi"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      items: [
        { firstName: "alex", lastName: "green" },
        {
          firstName: "may",
          lastName: "smith"
        },
        { firstName: "james", lastName: "jones" }
      ]
    };
  },
  methods: {
    clearSelected() {
      this.$refs.selectableTable.clearSelected();
    }
  }
};
</script>

We assigned a ref to the b-table . Then we call the clearSelected method on it to clear the selected rows.

Conclusion

We can add make columns sticky.

Also, we can add row details to our table rows that we can toggle.

Finally, we can let users select the rows and clear them.

Categories
BootstrapVue

BootstrapVue — Popovers and Progress Bars

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

We look at how to customize popovers and add progress bars.

Hiding and Showing Popovers

We can open and hide popovers the way that we want to show them with the this.$root.emit method.

The method lets us emit events globally and so it can be used to open more than one popover.

For example, we can write:

<template>
  <div id="app" class="text-center">
    <b-button v-b-popover.hover.top="'Popover 1'" title="Title 1">Button 1</b-button>
    <b-button v-b-popover.hover.top="'Popover 2'" title="Title 2">Button 2</b-button>
    <b-button @click='showAll'>Show All</b-button>
  </div>
</template>

<script>
export default {
  methods: {
    showAll() {
      this.$root.$emit("bv::show::popover");
    }
  }
};
</script>

<style>
#app {
  margin: 200px;
}
</style>

We have 2 buttons with popovers.

And we have the Show All button.

We have the showAll method to emit the 'bv::show::popover' event to show all popovers.

Also, we can write:

<template>
  <div id="app" class="text-center">
    <b-button id="popover-1" v-b-popover.hover.top="'Popover 1'" title="Title 1">Button 1</b-button>
    <b-button v-b-popover.hover.top="'Popover 2'" title="Title 2">Button 2</b-button>
    <b-button @click="showOne">Show 1</b-button>
  </div>
</template>

<script>
export default {
  methods: {
    showOne() {
      this.$root.$emit("bv::show::popover", "popover-1");
    }
  }
};
</script>

<style>
#app {
  margin: 200px;
}
</style>

We have the showOne method with 'popover-1' as the second argument.

This is the ID of the popover we want to open.

Now when we click the Show 1 button, we see the first popover open.

Likewise, there is the bv::hide::popover to hide the popover.

There’s the bv::disable::popover to disable them so they can’t be opened.

And there is bv::enable::popover to enable them so they can be opened.

We can listen to these events with this.$root.$on .

For example, we can write:

export default {
  mounted() {
    this.$root.$on('bv::popover::show', bvEventObj => {
      console.log('bvEventObj:', bvEventObj)
    })
  }
}

The callback will be run when those events are triggered.

Progress

BootstrapVue provides us with the progress component to let us display the progress of something.

To add one, we can use the b-progress and the b-progress-bar components.

For example, we can write:

<template>
  <div id="app">
    <b-progress class="mt-2" :max="max" show-value>
      <b-progress-bar :value="value * (6 / 10)" variant="success"></b-progress-bar>
      <b-progress-bar :value="value * (2.5 / 10)" variant="warning"></b-progress-bar>
      <b-progress-bar :value="value * (1.5 / 10)" variant="danger"></b-progress-bar>
    </b-progress>

<b-button class="mt-3" @click="randomValue">random number</b-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      max: 100,
      value: 0
    };
  },
  methods: {
    randomValue() {
      this.value = Math.random() * this.max;
    }
  }
};
</script>

We have the b-progress component which houses the b-progress-bar component.

We can have bar with multiple values.

In the example above, we have 6 / 10 of it being green with because of the variant is set to 'success' .

Then a quarter of the bar is yellow since we the variant to warning in the 2nd b-progress-bar .

Then we have 15% of it being red since variant is set to danger in the 3rd bar.

The value determines the portion of the bar that’s filled.

max is the maximum value.

show-value indicates whether we want to show the value or not.

Labels

We can use the show-progress to show the percentage of the max value.

Or we can use the show-value props to show the current absolute value.

For example, we can write:

<template>
  <div id="app">
    <b-progress show-value :value="value" :max="max"></b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      max: 100,
      value: 75
    };
  }
};
</script>

Then we see the absolute value in the progress bar.

Custom Progress Label

We can customize the progress label the way we like.

For example, we can write:

<template>
  <div id="app">
    <b-progress :value="value" :max="max" height="2rem">
      <b-progress-bar :value="value">
        <strong>{{ value.toFixed(2) }} / {{ max }}</strong>
      </b-progress-bar>
    </b-progress>
  </div>
</template>

<script>
export default {
  data() {
    return {
      max: 100,
      value: 75
    };
  }
};
</script>

We have b-progress-bar which takes the value and round it to 2 decimal places.

We also take the max value and display it after it.

Conclusion

Popovers can be shown, hidden, enabled, or disabled by emitting events.

Also, we can create progress bars with the b-progress-bar components.

Categories
BootstrapVue

BootstrapVue — Dynamic Tabs and Time Pickers

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

In this article, we look at how to create dynamic tabs.

Also, we look at how to add a time picker to our app.

Dynamic Tabs

We can add tabs to a page dynamically.

For instance, we can write:

<template>
  <div id="app">
    <b-tabs>
      <b-tab v-for="(i, index) in tabs" :key="i" :title="`Tab ${i}`">
        <div class="p-3">
          Tab {{ i }}
          <b-button @click="closeTab(index)">Close tab</b-button>
        </div>
      </b-tab>

      <template v-slot:tabs-end>
        <b-nav-item @click.prevent="newTab" href="#">
          <b>+</b>
        </b-nav-item>
      </template>
    </b-tabs>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      tabs: []
    };
  },
  methods: {
    newTab() {
      this.tabs = [...this.tabs, this.tabs.length + 1];
    },
    closeTab(index) {
      this.tabs.splice(index, 1);
    }
  }
};
</script>

We populate the tabs-end slot with a b-nav-item component to let us display a link to let users add a new tab.

To add a new tab, the newTab method is called to add a new tab.

It just adds a new number to tabs .

The tabs are rendered by looping through tabs and render them as b-tab components.

To remove a tab, we have the closeTab method to remove an entry by index with splice .

Then the updated set of tabs will be rendered.

Time

We can display a time picker with the b-time component.

For example, we can write:

<template>
  <div id="app">
    <b-time v-model="value" locale="en" @context="onContext"></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  },
  methods: {
    onContext(ctx) {
      console.log(ctx)
    }
  }
};
</script>

We added the b-time component which displays a time picker.

The selected time is bound to the value state via v-model .

locale is set as 'en' to set the locale to English.

onContext is called when a time component selected.

The ctx parameter is an object with the formatted time, locale, and time parts.

Disabled

We can make it non-interactive by setting the disabled prop:

<template>
  <div id="app">
    <b-time v-model="value" disabled></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

Read-Only

We can make it focusable but prevent the user from selecting a time with the readonly prop:

<template>
  <div id="app">
    <b-time v-model="value" readonly></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

Styling

There are various ways we can style a time component.

Enable the Seconds Spin Button

We can add the show-seconds prop to show the seconds spin button.

It’s not shown by default.

For example, we can write:

<template>
  <div id="app">
    <b-time v-model="value" show-seconds></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

Hiding the Top Selected Time Header

The hide-header prop will hide the selected time:

<template>
  <div id="app">
    <b-time v-model="value" hide-header></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

Border and Padding

We can add the class prop to apply styles we want:

<template>
  <div id="app">
    <b-time v-model="value" class="border rounded p-2"></b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

Default Slot

The default slot lets us add content to the bottom of the time picker.

For example, we can write:

<template>
  <div id="app">
    <b-time v-model="value" class="border rounded p-2">
      <b-button variant="outline-danger" @click="value = ''">Clear time</b-button>
    </b-time>
    <p>{{value}}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

We added a b-button to the default slot to reset value to an empty string.

Conclusion

We can make tabs dynamic by rendering b-tab with v-for .

Also, BootstrapVue comes with a time picker that we can let the user select a time.