Replacing JHipster UI components (Part 2. Adding SideNavbar and customizing more components)
Tags: jhipster, vue
Published: 2019-09-19 05:42:52

In the last part, I changed the top navbar with the same functionality as the JHipster one, it is time to customize it a little to add our own flavor.

# Customization for Navbar

First, I am going to use [flag-icon-css](https://github.com/lipis/flag-icon-css) to make the language bar more descriptive. As their docs says, I simply run

```
npm install flag-icon-css
```

After installation, I need to copy the `svg` files to my content folder, so the styles can be load correctly.

```
node_modules/flag-icon-css/sass/flag-icon.scss
```

to

```
app/bjt/sass/flag-icon.scss
```

But I need to override the variables file, so I can update the path where the `svg` files are, to keep things simple I will customize my new `flag-icon.scss`

```scss
// Override paths for svgs
$flag-icon-css-path: '/content/bjt/vendor/flags' !default;
$flag-icon-rect-path: '/4x3' !default;
$flag-icon-square-path: '/1x1' !default;

@import '~flag-icon-css/sass/flag-icon-base';
@import '~flag-icon-css/sass/flag-icon-list';
```

And then in my `bjt/bjt-style.scss`

```scss
@import 'sass/flag-icon.scss';
```

Now, just to run a test, I can add somewhere the styles

```html
<span class="flag-icon flag-icon-gr"></span>
<span class="flag-icon flag-icon-gr flag-icon-squared"></span>
```

And now we have some flags!

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zgot91zlns0feaikbuou.png)

But not everything could be that good, soon I hit a wall, a very difficult one.

## Vue.js and TypeScript `super` are not much of a friends

*This next part is based in some search and my little knowledge of Vue, if there is something wrong or if there is a better way please let me know!*

While in angular I could take advantage of inheritance and calling super to execute code already placed in the JHipster parent classes, in Vue.js it is not the case, as [Ashraful Islam](https://dev.to/ashraful/call-super-method-in-vue-component-3pl2) says:

> So far (VueJS v2) we don't have class based component like react. `*.vue` has it's own syntax rather than traditional javascript.

Investigating a little more, I realized that this is not only true, it is like this by design and I do not think this will change soon, as many will know this is an old discussion in [vue.js](https://github.com/vuejs/vue/issues/2371), with highlights like:

> My opinion is that ES6 classes offer no practical advantages over plain object definitions except for syntax preferences. 

or

> I don't think I'll ever change Vue's default API to use classes.

And most important:

> People who "just want classes" probably never actually tried to envision what the equivalent of Vue's current API would look like using classes ...
>
> ... Well, I have tried, and my conclusion is using only specced features from ES2017, there's simply no way to provide something that is elegant enough. You end up with tedious constructor calls (and don't forget `super`, binding instance methods to `this`), awkward workarounds like `static get option () { return { ... }}` or attaching static properties after the class declaration block, etc. etc.

*https://github.com/vuejs/vue/issues/2371#issuecomment-330068362*

While I do not entirely agree with yyx990803 opinion, I totally understand his point of view

> ... the standard today is not good enough to provide a decent equivalent of Vue's current API

There has been a lot of debate about the best approach on how to program user interfaces (functional, OOP, mutability/immutability..), I preffer to be a little more verbose to be more clear, with "type safe" and static code checking. At the same time I found vue.js more easy to develop and less ceremonial than angular (declare components, use modules if they are going to be used in other components), so, I get the fact that it has not the same design in mind, and there are always trade offs.

So vue.js preffers this

```javascript
export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    }
  }
}
```

to this

```javascript
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class YourComponent extends Vue {
  @Prop(Number) readonly propA: number | undefined
  @Prop({ default: 'default value' }) readonly propB!: string
  @Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
```

The problem is that JHipster generates the components with classes for angular and react, so trying to fit the same approach with vue.js seems the more sane approach, there is even an [official component](https://github.com/vuejs/vue-class-component) so you can declare your components as classes, but this is only a partial solution, it takes some annotations and conventions and transforms it into VueJs components with their respective properties.

This causes that, even if you are thinking that you are using classes to program your components, they are not real classes, they are "parsed" to work with vue.js, and, since it does not have classes, it also does not have the notion of `super`.

I do not know what could be best for JHipster, to change the classes to VueJs components, or leave it as is, so far this is the only major issue I found. It seems to me that it could be a barrier to hold the full VueJs design philosophy, but on the other hand, I am very used to classes and in this particular case it helped me to understand and be productive more quickly, so I will leave the decision to the reader.

In my case, I have to remember my [second rule](https://dev.to/antonioortizpola/separating-the-jhipster-layout-from-a-custom-ui-implementation-55i8)

> adapt the layout to JHipster, not the other way

So, I decided that for now, I will change the name of the methods that I need to override to add an underscore `_` before, so I do not run into problems, sadly, each modified component means one change to the code to switch between my UI and JHipster's one, it will also mean one more possible conflict when I update my JHipster, but it stills seems an easy task for now.

## Back to our show!

To finally include my flags for the language, I need a simple change to the JhiNavbar, make the language protected so I can access the property in my class, and add an underscore to the created method, so I can replace it.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/mq3r7rbefjsvdxe2mv5j.png)

Then, I just need to add some methods to my bjt/bjt-navbar

```javascript
public flagLanguages = {
  es: 'mx',
  en: 'us'
};
public flag: string;

created() {
  this._created();
  this.flag = this.flagLanguages[this.currentLanguage];
}
```

And the language drop-down now can use this to be a little more visual

```html
<b-nav-item-dropdown no-caret :right="!isRTL" v-if="languages && Object.keys(languages).length > 1">
    <template slot="button-content">
        <i class="navbar-icon align-middle flag-icon flag-icon-squared" :class="'flag-icon-' + flag"></i>
        <span class="d-lg-none align-middle" v-text="$t('global.menu.language')">&nbsp; Language</span>
    </template>

    <b-dd-item v-for="(value, key) in languages" :key="`lang-${key}`" v-on:click="bjtChangeLanguage(key)"
                     :class="{ active: isActiveLanguage(key)}">
        <i class="flag-icon flag-icon-squared mr-1" :class="'flag-icon-' + flagLanguages[key]"></i>
        {{value.name}}
    </b-dd-item>
</b-nav-item-dropdown>
```

And now our language bar looks better

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ejjv6z3ve359kigrb700.png)

And as a last touch, lets make the username accessible also

```javascript
public get username(): string {
  return this.$store.getters.account ? this.$store.getters.account.firstName : '';
}
```

And this is starting to look better

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/e66hy7yd4fx9lglq86yi.png)

# Implementing a SideNavBar in JHipster

From now on, we should be able to move a little easier, since we have resolved most of the common issues.

Checking the Appwork demo, the nice page uses the layout2, so I modify the `bjt/App.vue` file accordingly

```html
<template>
    <div class="layout-wrapper layout-2" id="app">
        <ribbon></ribbon>
        <div class="layout-inner">
            <bjt-sidebar />

            <div class="layout-container">
                <bjt-navbar />

                <div class="layout-content">
                    <div class="router-transitions container-fluid flex-grow-1 container-p-y">
                        <router-view />
                    </div>

                    <b-modal id="login-page" hide-footer lazy>
                        <span slot="modal-title" id="login-title" v-text="$t('login.title')">Sign in</span>
                        <login-form></login-form>
                    </b-modal>

                    <jhi-footer></jhi-footer>
                </div>
            </div>
        </div>
        <div class="layout-overlay" @click="closeSidenav"></div>
    </div>
</template>
```

Then I create my `bjt-sidebar.component.ts` file based on the `LayoutSidenav.vue` component from Appwork.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/p2iqwiy6ph6s3nfezk3j.png)

As you can notice, this is nothing more than a parse to a class of the component. I also created the `bjt-sidebar.component.ts` with all the view code. And now we are almost done for our base project!

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1a2i2tmm5cm5gexdrdvu.png)

Then I repeat the procedure with the footer component, creating new i18n files if necessary for translation. After replacing the menus with the entities menu, you can say we have a JHipster App base with Appwork layout working!

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/t4e5gupae31k7jcc5m9m.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/749xynz3qyo96vk1m3h9.png)

After admire our work for sometime, I want to compare how many parts did I touched to integrate my layout.

Checking the base files

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ykqjc3ypihin113xhro9.png)

We have just 5 distinct files from one JHipster untouched project

- `webpack/webpack.dev.js`: Just modified one line to load our styles instead the ones from JHipster
- `webpack/webpack.prod.js`: Same as before
- `package.json`: We installed some new libraries and updated one, this file is expected to change a lot when the system grows
- `.yo-rc.json`: This file is only changed because a random `jwtSecretKey` is generated each time you generate an application

Checking the source files we can see we did not touch many files

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zd7o7zj0panhhwyect8v.png)

- `bjt` Folder is where all my custom code resides
- `i18n` has some new files with my translations
- `core/jhi-navbar.component` required two changes, make the property `currentLanguage` protected instead of private, and an underscore to avoid conflicts when overriding a method in the child class
- `main.ts` has 3 changes, the import swap between the JHipster App and mine, the initialization of my custom components and a JHipster style commented to avoid conflicts with my styles
- `index.html` Just some minor changes in head based on the index from Appwork

So, if we want to check our JHipster app, we can make this changes:

1.- Change `webpack/webpack.dev.js` and `webpack/webpack.prod.js` so it loads the JHipster styles

```json
  entry: {
    // Change import for JHipster or BJT UX
    global: './src/main/webapp/content/scss/global.scss',
    // global: './src/main/webapp/app/bjt/style.scss',
    main: './src/main/webapp/app/main'
  }
```

2.- Change imports for App class in `main.ts`

```javascript
// Change imports for JHipster or BJT UX
import App from './app.vue';
// import App from './bjt/App.vue';
```

3.- Uncomment vendor styles in `main.ts`

```javascript
// Comment to activate BJT UX
import '../content/scss/vendor.scss';
```

4.- Change `jhi-navbar.component.ts` so it uses the `created` method instead the modified one `_created`

```javascript
  // change lines to change between JHipster and BJT UX
  created() {
  // _created(): void {
    this.translationService().refreshTranslation(this.currentLanguage);
  }
```

As you can see, I added comments so it is easy to find all the parts to change with a search

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/6brjc7361xgywb40dpz7.png)

After this simple changes, we can see JHipster UI is back!

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/qjp2b4c4j7y67l36oh89.png)

Revert these changes to return to our Appwork layout

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ja3ezmhim3daruj3qs8u.png)

Ok, so now we have an easy to update base, almost completely separated from JHipster, we can switch between implementations relatively easy.

In the last part I am going to customize my entities, so they can be more than a simple crud and we can see some examples of side by side in the server side.