NativeScript Vue — Creating a global side drawer.

Learn how to create a shared side drawer using RadSideDrawer in NavtiveScript Vue 2

Jamie Curnow
8 min readOct 16, 2018

TL;DR:
Creating a sidedrawer that is shared between pages can save memory, minimize CPU usage, and give a boost to performance. Check out this repo to get your hands on the code!

Don’t make so many side drawers! Create a global, shared drawer instead ;)

Coming from the wold of web app development I initially found that native dev sucked. It felt clunky, unintuitive, non-reliable and under-documented. As well as that, you were pretty much tied to using React or Angular and missing out on the awesomeness of Vue. Ohh and signing your app and publishing to the app store was a nightmare compared to my usual npm run generate && firebase deploy (yes I love nuxt.js and firebase)!

Enter {N}ativeScript-Vue 2.0!

Harnessing the power of NativeScript 4 and all (most) of the great features that Vue.js has to offer I have found my latest native app project an absolute joy to build! However, while the NativeScript community is thriving and developing at full speed, nativesctipt-vue seems to be trailing somewhat behind in usage and more importantly guides/documentation/templates.

I found myself needing to implement a sidedrawer to my app for navigation which turned out to be relatively simple - create it as a vue component, import it on pages where it was needed and open/close it with a tap on a button. This worked, but it had some undesirable side effects. Mainly on page rendering speed - the app seemed to lag quite a lot when navigating to pages that included the sidedrawer. So I did a little research and found some great guides on how to achieve a shared sidedrawer in ‘vanilla’ Nativesctipt as well as Nativescript Angular, but poor old Vue was left out of the mix… Time to freshen up on Vue render functions and come up with a global side draw implementation that can be controlled from any page and easily reused in other apps.

Get set up…

First things first, make sure you have all of the prerequisites set up. I’ll be coding this and testing on iOS so if you’d like to follow along, make sure you have your environment set up and running with node.js, nativescript-cli, Xcode etc. Here’s a great guide on getting set up - take your time, get it right:

Also, make sure you have the vue cli installed:
npm install -g @vue/cli @vue/cli-init

Once you’re set up, we’ll create a new project with a vue template provided by nativescript.

$ vue init nativescript-vue/vue-cli-template nativescript-vue-sidedrawer

If this is going to turn into an actual app make sure you enter the correct Application name and most importantly the Unique application identifier, then select the SideDrawer preset, Yes to vuex and No to vue-devtools, and any color scheme you like. This will just save us writing a few lines of code and make sure we have all the dependancies we need to get the project rolling.

Once that’s done, cd into the project folder and install all the npm modules.

$ cd nativescript-vue-sidedrawer
$ npm i

Get the project folder opened up in your fav IDE (I’m using Atom) and familiarise yourself with the project structure. Notice the app directory with main.js as your entry point.

We’re going to create some more directories right off the bat so that we can keep our project nice and organised. Create the following folders:

  • /app/mixins where we’ll keep our vue mixins
  • /app/pages where all of our app pages will be kept
  • /app/router where we’ll define our routes
  • /app/store/ where we’ll initialise our vuex store
  • /app/store/modules so we can modulalise the store

After that, head over to /app/main.js and we’ll start wiring everything up!

Let’s get coding…

You’ll notice that by choosing the SideDraw preset, we already have RadSideDrawer registered as an element with vue. If you’re adding on to an existing project or chose a different preset, just do an

$ npm i nativescript-ui-sidedrawer --save

And add the following line to your main.js before you initialise vue with new Vue() :

Vue.registerElement('RadSideDrawer', () => require('nativescript-ui-sidedrawer').RadSideDrawer)

Your main.js should look something like this:

At this point, you can check out the app locally in an emulator by running the following command from the project root:

$ tns run ios --bundle --emulator
Hello nativesctipt-vue!

Notice the ‘Menu’ text in the Action Bar - click it to check out the default RadSideDrawer.

Let’s get our router set up. Create a new file /app/router/index.js and define a handful of pages:

We’ll use that default export later to add the route pages to the Vue.prototype for easy access.

Next lets create three new files for those pages:

  • /app/pages/Home.vue
  • /app/pages/PageOne.vue
  • /app/pages/PageTwo.vue

In each of those files, we’ll just add an ActionBar with a Menu button and some text in the middle of the page. Use this as a template for the pages and just change the text data for each one:

You’ll notice that we have defined a vue mixin that doesn’t exist yet! So we better make it. Create a new file /app/mixins/sideDrawer.js and we’ll code that up:

That should be pretty self-explanatory if you know vue, and the comments should help if you don’t. We’re using this as a mixin so will import and use it on any future page that you need to control the menu from. For pages, it exposes the useful openDrawer() and closeDrawer() methods. (Open and close makes more sense to me than show and close!)

Since there are references here to the store, the next logical step would be to set up the vuex store. So lets create a new file /app/store/index.js and code it up like so:

I’m setting the store up in a modular fashion as you would more than likely want in any reasonably sized app. This means that all of the vuex store logic will be in the /app/store/modules directory which leads us nicely on to another new file /app/store/modules/sideDrawer.js which will be in charge of controlling the open/close state of the sidedrawer throughout the app:

This is a very basic vuex set up so should be easy to follow. We’re basically defining a new piece of application state data - sideDrawer, along with a mutation function to mutate that state data, and a getter to access the data.

That’s most of the wiring done… Now lets create our sidedrawer!

I’m going to make the sidedrawer as two components. One will be the sidedrawer it’s self using the <RadSideDrawer> element and the other will define the drawer content. You could make this in one component, but splitting it out like this means that in the future you could easily conditionally render the content of the side drawer based on what page you’re on or any other logic in the render function.

Let’s first scaffold the main sidedrawer. Create a new file /app/components/sideDrawer.vue and code it like this:

The important parts to note here are that we add a ref="drawer" to the RadSideDrawer element that we reference in the vue mixin that we made earlier, as well as binding the gesturesEnabled prop to the data prop in the vue mixin. RadSideDrawer requires two child nodes, one with the ~drawerContent prop and another with the ~mainContent prop (see v-view docs for an explanation as to what the ~ means). In our component we define the ~drawerContent as a <StackLayout> element. It’s worth noting that this can be changed to any element to fit your drawer design, just keep in mind that the rest of the layout for the drawer content will be in a separate component that will be rendered in place of the vue <slot> named drawerContent. More importantly is the ~mainContent that is defined by NativeScript’s <Frame> element. This is new in NativeScript 4 / NativeScript Vue 2 and is made exactly for this purpose!

NativeScript 4.0 introduced a new Frame element, and introduced a way to change the root element of our applications, allowing for sharing common view elements across pages via navigating.
https://www.nativescript.org/blog/behold-nativescript-vue-2.0

In our component we add another named slot inside the <Frame> element which is where our app pages will be rendered!

Our final component will be the actual drawer content. We could define this in the sideDrawer component, but it could be limiting in the future if we want to have different sidedrawer content for different pages. So lets code up the content in a new file /app/components/drawerContent.vue :

Here we’re just doing a v-for loop over the pages data prop. The pages array contains a name for each page and a reference to the page component to load.

Where the magic happens!

So far we’ve set everything up to for our new global sidedrawer, but in /app/main.js we have some work to do so that our app actually renders what we have just built! This is what your /app/main.js file should be looking like at the moment:

We’re going to remove the reference to ./components/App as our entry page is now at ~/pages/Home and even better is defined in our router file, so we’ll import routes from '~/router' here instead. We’ll also need to import the store from ~/store as well as the sideDrawer component from ~/components/sideDrawer and the drawerContent from ~/components/drawerContent . We’ll add the routes object to Vue.prototype, add the store in the new Vue() instance and finally change our render function to wrap the app in the sideDrawer. When we’re finished, our /app/main.js should look like this:

We won’t be needing that old App.vue component now, so go ahead and delete /app/components/App.vue

The last thing we should do is add a little styling to /app.scss :

Now we’re ready to roll!

Run (if it’s not still running):

tns run ios --bundle --emulator

And check out your app with a global, shared sidedrawer!

A nativescript vue app with a global, shared sidedrawer.

A joyful dev experience

NativeScript is just getting better and better, the dev community is thriving and if they keep making enhancements like this I think the weapon of choice for any cross platform developer will be a no-brainer. I hope this tutorial was easy to follow and that you can enhance the performance of your app by taking advantage of the new features in NativeSctipt 4 🚀

I’ve made the repo for this project available on GitHub and any suggestions/pull requests are welcome to improve the functionality!

Support your creators!

If you found this story useful and would like me to keep writing useful content, please consider supporting me on Patreon 🤗

--

--

Jamie Curnow

I am a javascript developer living in beautiful Cornwall, UK. Ever curious, always learning.