Vue&Angular Together in One App

We have been developing a web application using VueJs for a while. A couple weeks ago, we needed to export one of our component which has already been under development with VueJs and import it to angular application. The problem was that we have never experienced such a integration between ts and js. We confused about how to make angular and vue based codes would work together in harmony. While I was doing some researches on the internet, I came to a very good article which described how to do it.

I am planing to give you some detailed insights about what we have experienced while progressing on this task.

Let’s start

Creating Vue Application

The first step, I will create a brand new Vue application to understand the structure and steps easier. I created application using following command.

vue create enginaar-vue-part

While creating the application, cli asks us to select preset. I selected default preset.

If you do not have vue cli you can run the following installation code first

npm install -g @vue/cli

After creating the application, lets run it without touching.

npm run serve

We can reach the application using http://localhost:8080 link and make sure the application has no problem.

We will develop a simple component using vuejs. It is ok to create a file in components folder. Instead, I will use HelloWorld file which has already been existed in the project.

In my earlier trials, I developed a component with input parameters, imported it to angular application and had some render problems. You can find code piece I wrote in HelloWorld.vue in following section.

<template>
  <div class="visible-component">
    <ul>
      <li v-for="i in repeats" :key="i">{{lineText}} - <button>{{btnText}}</button>
      </li>
    </ul>
</div>
</template>

<script>
export default {
  props: {
    lineText: {
      type: String,
      default: "line-text"
    },
    btnText: {
      type: String,
      default: "btn-text"
    },
    repeats: {
      type: Number,
      default:1
    }
  }
}
</script>

<style>
.visible-component {
  background-color: rgb(194, 189, 223);
}
</style>

As I mentioned in previous paragraph, I did not get this component rendered in angular application at the first time because of lacking parameter passing related issues on angular side. To overcome this problem I put some default values for parameters so that I did not pass any parameter and managed to render it correctly.

To test the HelloWorld component I put it into App.vue file and get it on the screen.

<template> 
  <HelloWorld lineText="Welcome to Your Vue component" btnText="Click This" :repeats="4"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
</style>

I think a component with input parameters is fair enough to iterate to next step. Without passing lineText, btnText and repeats fields, the component is working with default parameters.

On this point, we need to export this component as a js file. To do that we will use one of vue-cli features. Open package.json file and put following line to scripts section.

"build-wc": "vue-cli-service build --target wc --name enginaar-component ./src/components/HelloWorld.vue", 

Here we should keep in mind that –name pameter is the parameter which we are using to give a name for exported component. We will export HelloWorld.vue component from project. When we are exporting the component, we can also rename it in the same time. Following command will handle the export operation.

npm run build-wc
Exported files

You can see the result of the executed command in the screenshot.

The process generates us two js files. I will use compressed min.js file because of size.

Now lets create our angular app.

Creating Angular Application

In this section we will create an angular application. That application will be our host application for Vue component. You can use the following command.

ng new enginaar-ang-part

Cli asks if we need router. I did not want it.
Don’t touch anything and just run the application using the following command.

ng serve

Application is up and runnig on http://localhost:4200

Copy enginaar-component.min.js file from dist folder of vue application and paste it to angular /src/assets folder. This folder makes sense to put libraries.

Since we are using vuejs as the underlying framework in the first project, we need to add vue.js to angular app. You can use the following code in angular project.

npm i vue -save

The next step we will configure angular application to reach that js file as well as vuejs file.
Open angular.json file and paste following into scripts section

 "node_modules/vue/dist/vue.min.js",
 "src/assets/enginaar-component.min.js"

We can call this component in one of our pages. Let’s try.

I opened app.component.html page, cleared all the codes and added the following code to the page.

<enginaar-component></enginaar-component>

Once I run the application I had an error. You can find in screenshot

What I understand is that this is a web component and we need to configure application to accept web components. I did it by opening app.module.ts file and put the code into @NgModule section.

  schemas: ['CUSTOM_ELEMENTS_SCHEMA']

Now everything seems ok. When I open web browser I see that the component is running.

Vue component in anglar app first sight

Let’s use the parameters. I improved my code in app.component.html like following.

<div>kenan</div>
<enginaar-component line-text="this is a line text from angular" btn-text="Click from angular" repeats="5"></enginaar-component>
Running vue component in angular app with parameters

This point was ok for us. However, I pushed luck a bit forward and get some additional questions.

Additional Questions

I have some questions in my mind

  • Why do lineText, btnText fields change to line-text, btn-text?
    Basicly, camel case notation is being changed to kebap case apperantly. I still do not know why it is happening.
  • How do I handle js events?
    If I would like to fire some events from vue app/component, how can I listen them?

For the second question I improved my code a little bit, tried following approaches

  • To $emit the js event from vue and listened it from angular like click($event). But it did not give me what I expected. I think that this is because of handling approaches of vue and angular or my inefficient angular knowledge of myself.
  • To fire an js event using document.dispatchEvent with Event class.
  • In the end, I raised document.dispatchEvent with CustomEvent class and add document.addEventListener. I put additional data onto custom event.

I added some line of code to HelloWorld.vue file. You can find the final version below.

<template>
  <div class="visible-component">
    <ul>
      <li v-for="i in repeats" :key="i">{{lineText}} - 
        <button @click="btnClicked(i)">{{btnText}}</button>
      </li>
    </ul>
</div>
</template>

<script>
export default {
  methods: {
    btnClicked(i) {
      console.log("btnClickTriggered:" + i)
      document.dispatchEvent(new CustomEvent("engClick", {"detail": {clickedItem: i}}))
    }
  },
  props: {
    lineText: {
      type: String,
      default: "line-text"
    },
    btnText: {
      type: String,
      default: "btn-text"
    },
    repeats: {
      type: Number,
      default:1
    }
  }
}
</script>

<style>
.visible-component {
  background-color: rgb(194, 189, 223);
}
</style>

In angular side I added the following code to app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'enginaar-ang-part';

  
  ngOnInit() {
    document.addEventListener("engClick", this.alertMe)
  }
 
  alertMe(event){
    let a = event.detail.clickedItem
    console.log("event handling from angular." + a)
  }
}

I am firing a custom event using pure js code from vuejs component. Similarly I am listening pure js events on angular side. I tried @HostListener annotation, but could not make it.

For now, the point we have came is efficient for us, but for sure we can make it further if we need.

You can find the article that I mentioned in the first paragraph
https://www.ais.com/using-a-vue-component-in-an-angular-app/