Categories
BootstrapVue

BootstrapVue — Customizing Spinner and Basic Tables

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 spinners and add basic tables.

Aligning Spinners

We can add classes or alignment.

For instance, we can write:

<template>
  <div id="app">
    <b-spinner class="m-5"></b-spinner>
  </div>
</template>

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

to add the m-5 class to add some margins around the spinner.

Placement

The placement of the spinner can be changed.

For example, we can write:

<template>
  <div id="app">
    <div class="d-flex align-items-center">
      <b-spinner></b-spinner>
    </div>
  </div>
</template>

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

to center align the spinner.

Floats

We can apply the float classes that come with Bootstrap to put the spinner left or right.

So we can write:

<template>
  <div id="app">
    <div class="clearfix">
      <b-spinner class="float-right"></b-spinner>
    </div>
  </div>
</template>

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

to use the clearfix class so that we can float the spinner to the right.

Text Align

We can use the text-center class to align the spinner to the center of the page:

<template>
  <div id="app">
    <div class="text-center">
      <b-spinner></b-spinner>
    </div>
  </div>
</template>

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

Spinners in Buttons

We can put spinners in buttons.

For example, we can write:

<template>
  <div id="app">
    <b-button variant="primary" disabled>
      <b-spinner small></b-spinner>Loading...
    </b-button>
  </div>
</template>

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

We have the spinner inside a button along with some text.

Tables

BootstrapVue comes with the b-table component to let us display tables.

There are 2 lighter weight alternatives, which are b-table-lite and b-table-simple .

For example, we can write:

<template>
  <div id="app">
    <b-table striped hover :items="items"></b-table>
  </div>
</template>

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

We have the items prop that takes an array of objects to render into a table.

striped makes the rows alternate in color.

hover makes the rows highlight when it’s hovered.

The property names are automatically mapped to individual words and capitalize each word.

This conversion is done for kebab case, snake case, or camelCase property names.

We can add the _rowVariant or _cellVariant properties to change the styles of various cells.

For example, we can write:

<template>
  <div id="app">
    <b-table striped hover :items="items"></b-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { firstName: "alex", lastName: "green", _rowVariant: "success" },
        {
          firstName: "may",
          lastName: "smith",
          _cellVariants: { lastName: "info", firstName: "warning" }
        },
        { firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

_rowVariant makes the whole row the same color.

'success' makes the background green

_cellVariants makes individual cells a different color.

So lastName is light blue since it hs variant 'info' .

And firstName ‘s variant is 'warning' so it’s yellow.

The _cellVariants and _rowVariants only applies to the entry that they are in.

Fields

We can specify how the fields are displayed explicitly.

b-table can take a fields prop with an array of field to display.

For example, we can write:

<template>
  <div id="app">
    <b-table striped hover :items="items" :fields='fields'></b-table>
  </div>
</template>

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

Since fields is [“firstName”] , only the First Name column is displayed.

Fields as an Array of Objects

We can have an array of objects for the fields array.

For example, we can write:

<template>
  <div id="app">
    <b-table striped hover :items="items" :fields="fields"></b-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      fields: [
        {
          key: "lastName",
          sortable: true
        },
        {
          key: "firstName",
          sortable: false,
          variant: "success"
        }
      ],
      items: [
        { firstName: "alex", lastName: "green" },
        {
          firstName: "may",
          lastName: "smith"
        },
        { firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

We have the fields array with the entries being key , sortable , and variant .

key is the property name of the items entries.

variant is the styling variant like primary or success ,

sortable indicates whether the column is sortable.

Therefore, the Last Column is sortable and First Name is not.

Conclusion

We can style and place spinners the way we like with some classes.

Also, we can create simple tables by passing in a few arrays as props into the b-table component.

Categories
BootstrapVue

BootstrapVue — Pagination Nav

l)

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 add pagination nav links to our page.

Page Number Generation

We can generate links with any content we like.

All we have to do is to change he link-gen prop to return the URL path we want.

The page-gen prop can generate any link text we want:

<template>
  <div class="overflow-auto">
    <b-pagination-nav :link-gen="linkGen" :page-gen="pageGen" :number-of-pages="links.length"></b-pagination-nav>
  </div>
</template>

<script>
export default {
  data() {
    return {
      links: ["#foo", "#bar", "#baz", "#qux"]
    };
  },
  methods: {
    linkGen(pageNum) {
      return this.links[pageNum - 1];
    },
    pageGen(pageNum) {
      return this.links[pageNum - 1].slice(1);
    }
  }
};
</script>

We have the linkGen method to return the path that we want. And the pageGen method returns the same entry as linkGen but without the hash.

So we’ll see ‘foo’, ‘bar’, ‘baz’, ‘qux’ are displayed.

And when we click on them, then we go to those links.

Array of Pages

We can use the use-router prop, then the links won’t be a tags. Navigation will be done with JavaScript instead of regular links.

For example, we can write:

<template>
  <div>
    <b-pagination-nav :pages="pages" use-router></b-pagination-nav>
  </div>
</template>

<script>
export default {
  data() {
    return {
      pages: ["?page=1", "?page=2", "?page=3"]
    };
  }
};
</script>

Then we get 3 links with the query strings in pages as the URLs to go to.

We can also have objects in the array with the link and text properties.

For example, we can write:

<template>
  <div>
    <b-pagination-nav :pages="pages" use-router></b-pagination-nav>
  </div>
</template>

<script>
export default {
  data() {
    return {
      pages: [
        { link: "?page=1", text: "one" },
        { link: "?page=2", text: "two" },
        { link: "?page=3", text: "three" }
      ]
    };
  }
};
</script>

We have the link property with the URL to go to.

text has the text for each link.

Alternatively, we can write the query string with the query property instead.

For example, we can write:

<template>
  <div>
    <b-pagination-nav :pages="pages" use-router></b-pagination-nav>
  </div>
</template>

<script>
export default {
  data() {
    return {
      pages: [
        { link: { query: { page: 1 } }, text: "one" },
        { link: { query: { page: 2 } }, text: "two" },
        { link: { query: { page: 3 } }, text: "three" }
      ]
    };
  }
};
</script>

We have the same query string as before.

But creating the query strings is much easier since we can just add key-value pairs.

Button Content

We can change the button contents the way we want.

To do that, we can set the first-text , prev-text , next-text , and last-next props.

For example, we can write:

<template>
  <div>
    <b-pagination-nav
      number-of-pages="15"
      base-url="#"
      first-text="First"
      prev-text="Prev"
      next-text="Next"
      last-text="Last"
    ></b-pagination-nav>
  </div>
</template>

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

We set the first-text prop to set the text for going to the first page.

The prev-text prop is set to change the text of the link to go to the previous page.

The next-text prop is set to change the text for the next button.

last-text is used to set the text for the link that goes to the last page.

Also, we can populate the slots for more customization.

For instance, we can write:

<template>
  <div>
    <b-pagination-nav number-of-pages="15" base-url="#">
      <template v-slot:first-text>
        <span class="text-success">First</span>
      </template>
      <template v-slot:prev-text>
        <span class="text-success">Prev</span>
      </template>
      <template v-slot:next-text>
        <span class="text-success">Next</span>
      </template>
      <template v-slot:last-text>
        <span class="text-success">Last</span>
      </template>
      <template v-slot:ellipsis-text>
        <b-spinner small type="grow"></b-spinner>
        <b-spinner small type="grow"></b-spinner>
      </template>
      <template v-slot:page="{ page, active }">
        <b v-if="active">{{ page }}</b>
        <span v-else>{{ page }}</span>
      </template>
    </b-pagination-nav>
  </div>
</template>

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

We populate the slots to make the content look our way.

We set the first-text slot to set the text for going to the first page.

The prev-text slot is set to change the text of the link to go to the previous page.

The next-text slot is set to change the text for the next button.

last-text is used to set the text for the link that goes to the last page.

ellipsis-text slot is used to change the ellipsis content.

We changed it to flashing dots.

page has the current page and active indicates if the page is active.

Conclusion

We can customize pagination nav buttons with our own content.

Also, we can customize the paths or query string that the links go to the way we like.

Categories
BootstrapVue

BootstrapVue — Modals and Dialogs

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’ll look at how to use modal and dialog components.

Disable Footer Buttons

We can disable footer buttons with the cancel-disabled and ok-disabled props.

They disable the cancel and OK buttons respectively.

We can disable both at the same time with the busy prop.

So if we have:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" busy>
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

Then both buttons will be grayed out.

Custom Rendering with Slots

We can customize the render of our modal parts with slots.

The header can be customized by populating the header slot.

The body can be customized by populating the default slot.

And the footer can be customized by populating the footer slot.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" busy>
      <template v-slot:modal-header="{ close }">
        <b-button @click="close()">Close Modal</b-button>
        <h5>Header</h5>
      </template>

      <template v-slot:default="{ hide }">
        <p>Body</p>
        <b-button @click="hide()">Hide</b-button>
      </template>

      <template v-slot:modal-footer="{ ok, cancel, hide }">
        <p>Footer</p>
        <b-button @click="ok()">OK</b-button>
        <b-button @click="cancel()">Cancel</b-button>
        <b-button @click="hide('hide')">Hide</b-button>
      </template>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

The slots provide us with the methods we can call with each section.

The close method closes the modal in the header.

hide hides the modal in the body.

The footer has the ok , cancel , and hide methods to close the modal.

Multiple Modals

We can have multiple models on one page.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal-1>Open First Modal</b-button>

    <b-modal id="modal-1" size="lg" title="First Modal" ok-only no-stacking>
      <p>First</p>
      <b-button v-b-modal.modal-2>Open Second Modal</b-button>
    </b-modal>

    <b-modal id="modal-2" title="Second Modal" ok-only>
      <p class="my-2">Second</p>
      <b-button v-b-modal.modal-3>Open Third Modal</b-button>
    </b-modal>

    <b-modal id="modal-3" title="Third Modal" ok-only>
      <p class="my-1">Third</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We have 3 modals which are opened one after the other.

When we click Open First Modal, we open the first modal.

It has an Open Second Modal button to open the second modal.

That modal has the Open Third Modal button to open the 3rd modal.

When we close the top one, the rest are closed.

Modal Message Boxes

We can create simple message boxes with the msgBoxOk and msgBoxConfirm methods.

For example, we can write:

<template>
  <div id="app">
    <b-button @click='openMsgBox'>Open Message Box</b-button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    async openMsgBox(){
      const value  = await this.$bvModal.msgBoxOk('hello')
      console.log(value);
    }
  }
};
</script>

We added a button to call the openMsgBox method.

It opens a message box with the word 'hello' in it from the string we pass on.

It returns a promise.

When we close it, it’ll resolve to true when we close it.

Also, we can pass in an object with some options as the 2nd argument.

For example, we can write:

<template>
  <div id="app">
    <b-button @click="openMsgBox">Open Message Box</b-button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    async openMsgBox() {
      const value = await this.$bvModal.msgBoxOk("hello", {
        title: "Confirmation",
        size: "sm",
        buttonSize: "sm",
        okVariant: "success",
        headerClass: "p-2 border-bottom-0",
        footerClass: "p-2 border-top-0",
        centered: true
      });
      console.log(value);
    }
  }
};
</script>

We added a title to the title property.

size sets the size of the modal.

buttonSize sets the button size.

okVariant sets the style of the OK button.

headerClass sets the header’s class.

footerClass sets the footer’s class.

centered makes the modal vertically centered.

Confirm Dialog

The confirm dialog is similar except that it also has a cancel button.

We call the msgBoxConfirm method instead msgBoxOk to open a confirm dialog.

For instance, we can write:

<template>
  <div id="app">
    <b-button @click="openMsgBox">Open Confirm Box</b-button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    async openMsgBox() {
      const value = await this.$bvModal.msgBoxConfirm("hello", {
        title: "Confirmation",
        size: "sm",
        buttonSize: "sm",
        okVariant: "danger",
        okTitle: "YES",
        cancelTitle: "NO",
        footerClass: "p-2",
        hideHeaderClose: false,
        centered: true
      });
      console.log(value);
    }
  }
};
</script>

We added the okTitle and cancelTitle properties to the options.

When we click the cancel button, the promise will resolve to false .

If we click the ‘x’ on the top right, it’ll resolve to null .

If we click the OK button, it’ll resolve to true .

Conclusion

We can customize the rendering of the modal by populating slots.

Also, we can display simple dialog boxes that returns a promise.

It resolves to different values depending on what is done to close it.

Categories
BootstrapVue

BootstrapVue — Modals

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’ll look at how to use modal components.

Prevent Closing

We can stop a modal from closing with the .preventDefault method.

For instance, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" @ok="handleOk">
      <div>Hello!</div>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    handleOk(bvModalEvt) {
      bvModalEvt.preventDefault();
    }
  }
};
</script>

We have the handleOk method which is set as the value of the ok event handler.

We called prevetnDefault on bvModalEvt , which is the event object for the modal.

Now when we click the OK button, the modal won’t close.

Modal Content

We can add content to a modal.

For instance, we can add tooltips and popovers:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" ok-only>
      <p>
        <b-button v-b-popover="'Popover'" title="Popover">Button</b-button>
      </p>
      <p>
        <a href="#" v-b-tooltip title="Tooltip">Link</a>
        .
      </p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We have a modal with a button that has a popover.

We added it with the v-b-popover directive.

The v-b-tooltip lets us add a tooltip.

Styling

We can style models with various props.

We can change the modal size with the size prop.

For instance, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" size="xl" title="Extra Large Modal">Hello!</b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We have the size prop to change the size of the modal.

It’s responsive so it won’t overflow the screen.

Other values include 'lg' for large and 'sm' for small.

Scrolling Long Content

We can make long content scrollable.

For instance, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" scrollable>
      <p class="my-4" v-for="i in 20" :key="i">foo</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We have the scrollable prop on the modal to make it scrollable.

Vertically Centered Modal

We can vertically center our modal with the centered prop.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" centered>
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

Now we see the modal is vertically centered.

Variants

There are various props to change the styling variant of various parts of the modal.

They are the following:

  • header-bg-variant
  • header-text-variant
  • body-bg-variant
  • body-text-variant
  • footer-bg-variant
  • footer-text-variant

The value can be danger , warning , info , success , dark , light , etc.

For instance, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" header-bg-variant="success" body-text-variant="info">
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

Then the title will have a green background and the body text will be green.

Hide the Backdrop

The backdrop of the modal can be hidden.

We just have to add the hide-backdrop prop.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title="Modal" hide-backdrop>
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We just add it and the background won’t be darkened.

Disable Animation

To disable the modal animation, we can add the no-fade prop to our modal.

For instance, we write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" no-fade>
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

and we won’t get any animation when we open or close it.

Footer Button Sizing

We can change the footer button sizing with the button-size prop.

The possible values are sm for small or lg for large.

For example, we can write:

<template>
  <div id="app">
    <b-button v-b-modal.modal>Open</b-button>

    <b-modal id="modal" title=" Modal" button-size="sm">
      <p>hello</p>
    </b-modal>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We have button-size set to 'sm' , so the buttons are extra small.

Conclusion

There are many customizations we can do with models. We can stop them from closing.

Categories
BootstrapVue

BootstrapVue — Customizing Pagination

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’ll look at how to add pagination buttons to our page.

First and Last Button Type

We can change which buttons are shown in our pagination component.

The first-number prop indicates whether we want to always show the button for the first page.

Likewise, the last-number prop indicates whether we want to always show the button for the last page.

For example, we can write:

<template>
  <div id="app">
    <b-pagination first-number v-model="page" :total-rows="rows" :per-page="perPage"></b-pagination>

    <p>Current Page: {{ page }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      rows: 100,
      perPage: 10,
      page: 1
    };
  }
};
</script>

Now we always see the button for going to the first page.

Likewise, if we have:

<template>
  <div id="app">
    <b-pagination last-number v-model="page" :total-rows="rows" :per-page="perPage"></b-pagination>

<p>Current Page: {{ page }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      rows: 100,
      perPage: 10,
      page: 1
    };
  }
};
</script>

Then we always see the button for going to the last page.

Button Size

The button size can be changed with the size prop.

The value sm makes them smaller than the default.

lg makes them larger than the default.

For example, we can write:

<template>
  <div id="app">
    <b-pagination size="sm" v-model="page" :total-rows="rows" :per-page="perPage"></b-pagination>

<p>Current Page: {{ page }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      rows: 100,
      perPage: 10,
      page: 1
    };
  }
};
</script>

Now they look smaller.

Pill Style

We can add the pills prop to make the buttons look like pills:

<template>
  <div id="app">
    <b-pagination pills v-model="page" :total-rows="rows" :per-page="perPage"></b-pagination>

    <p>Current Page: {{ page }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      rows: 100,
      perPage: 10,
      page: 1
    };
  }
};
</script>

Alignment

The pagination buttons can be aligned in the position we want.

We can use the align prop to set the alignment.

The default alignment is left.

Other possible values are right to right-align, center for center align, and fill to fill the screen’s width.

For example, we can write:

<template>
  <div id="app">
    <b-pagination align="center" v-model="page" :total-rows="rows" :per-page="perPage"></b-pagination>

<p>Current Page: {{ page }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      rows: 100,
      perPage: 10,
      page: 1
    };
  }
};
</script>

Since we set align to 'center' , we have the pagination bar at the center of the screen.

Pagination Navigation

BootstrapVue also provides the b-pagination-nav component that lets us set the navigation position.

For instance, we can write:

<template>
  <div id="app">
    <b-pagination-nav :link-gen="linkGen" :number-of-pages="10" use-router></b-pagination-nav>
  </div>
</template>
<script>
export default {
  name: "App",
  methods: {
    linkGen(pageNum) {
      return pageNum === 1 ? "?" : `?page=${pageNum}`;
    }
  }
};
</script>

The difference between b-pagination and b-pagination-nav is that the pagination links can go to the URL that we want.

We have the link-gen prop which returns something that we can append to the current URL.

number-of-page lets us display the number of page buttons that we want.

use-router lets us navigate to URL generated by the Vue or Nuxt router.

The linkGen method can also return an object.

For instance, we can write:

<template>
  <div id="app">
    <b-pagination-nav :link-gen="linkGen" :number-of-pages="10" use-router></b-pagination-nav>
  </div>
</template>
<script>
export default {
  name: "App",
  methods: {
    linkGen(pageNum) {
      return { path: `/foo/page/${pageNum}` };
    }
  }
};
</script>

The object has the have the path property which is appended to the current URL.

It can also have the name and query properties for the route name and the query string respectively:

<template>
  <div id="app">
    <b-pagination-nav :link-gen="linkGen" :number-of-pages="10" use-router></b-pagination-nav>
  </div>
</template>
<script>
export default {
  name: "App",
  methods: {
    linkGen(pageNum) {
      return {
        name: "page",
        params: { page: pageNum }
      };
    }
  }
};
</script>

or:

linkGen(pageNum) {
  return {
    path: '/foo/',
    query: { page: pageNum }
  }
}

Conclusion

We can customize the pagination buttons on the b-pagination component.

Also, we can add a b-pagination-nav to generate links that we can click to go to a URL.