ngVue in FactSet

Using ngVue to create VueJS Components in an AngularJS 1.5 Codebase

Alexandru Olteanu

Marty Dimitrova

Thomas Truong

Agenda

  • What is ngVue?
  • How to use ngVue?
  • Constants
  • Broadcasting
  • Vuex Store
  • Translate

What is ngVue?

ngVue, is an Angular module that allows you to develop/use Vue components in AngularJS applications.

 

It can be used in the existing Angular applications and helps migrate the view parts of the application from Angular 1.x to Vue 2.

How to install it?

ngVue is an open source project found on https://github.com/ngVue/ngVue 

yarn add ngVue
npm install ngVue
import 'ngVue';
angular.module('appName', ['ngVue']);

How to use ngVue?

The basic principle of ngVue is that you write Vue components and simply insert them in your Angular code.

Props

You can use the component in Angular templates like any normal directive.

<batman 
	v-props-forename="$ctrl.batman.forename" 
	v-props-surname="$ctrl.batman.surname">
</batman>

However, for the props you need to prefix with v-props-* or v-props for an object of all the prop attributes.

Events

Events can be handled from VueJS to AngularJS components by binding functions references as v-on-

<version
   v-on-framework="$ctrl.update()">
</version>

It will be emitted on the Vue component side.

changeFramework() {
  this.$emit('framework', this.currentFramework);
  ...
}

Two-Way Binding

VueJS doesn't support two-way binding, therefore in the  Angular directive we will need to cater for this via props and events.

<version 
  v-props-framework="$ctrl.framework"
  v-on-framework="$ctrl.update()">
</version>

In this example framework is passed down as one-way binding from the parent (container) to the component Version. The event framework is being used as data changes are being sent back to the callback function update().

Create Vue Component

We first use the createVueComponent factory to create usable Angular directive which is bound to a specific Vue component.

import app from '~ngAppModule';
import Vue from 'vue';
import Component from './Batman.vue';

app.directive('vueBatman', createVueComponent =>
  createVueComponent(
    Vue.component('Batman', Component)
  )
);

Constants

Just like in AngularJS, using constants in templates in VueJS requires a bit of work.

 

Our recommended approach is utilising the capabilities of Vue - defining a constant plugin.

Using the $const Plugin

In order to add your constants to the plugin, all you need to do is register your plugin with a constants file.

Using them in a template is as easy as:

const definition: Record<string, string> = {
  Robin1: 'Dick Grayson',
  Robin2: 'Jason Todd',
  Robin3: 'Tim Drake',
  Robin4: 'Damien Wayne',
};

export default definition;
<strong>{{ $const('Robin1') }}</strong>

Broadcasting

Unlike AngularJS, VueJS components are designed to be very self-contained (plug-and-play) and have no relation to the parent unless passed in via a prop or through the store.

 

Event Handling in Parent

The ability to $emit is still available in VueJS components so if you're converting an AngularJS component with broadcasting logic. You can emit the responsibility to parent (most likely an Angular Component) for now.

Event Bus

import bus from './eventBus';

const eventBusPlugin = ($rootScope: any): void => {
  bus.$on('ng:broadcast', (name: string, params: any) => {
    $rootScope.$broadcast(name, params);
  });
};

eventBusPlugin.$inject = ['$rootScope'];

export default eventBusPlugin;
    import {eventBus} from '../../../plugins'
    ...
    send() {
      eventBus.$emit('ng:broadcast', 'like', this.framework);
    }

In the event if you HAVE to broadcast from a Vue component, you can use an Event Bus plugin.

Vuex Store

State management pattern + library for Vue.js applications.

 

Centralised store for all the components in an application.

 

Has rules ensuring that the state can only be mutated in a predictable fashion.

https://vuex.vuejs.org/

How is AngularJS managing shared state?

All applications have one root scope.

All other scopes are descendants of the root scope.

Commonly components would access the root scope to modify state on the application level.

What is the single source of truth in an ngVue app?

The goal is to migrate everything to VueJS.

 

We can move the state into Vuex by migrating any shared states such as rootScope from Angular to Vuex.

Translate

We SHOULD be able to do the following:

However, this is not possible because the root of the app is Angular and not Vue.

<template>
  <div>
    {{ $vtranslate('welcomeMessage') }}
  </div>
</template>

Translate Plugin

$vtranslate can be accessed from the template as such. The key 'welcomeMessage' is the key in the language file.

To solve this issue, we wrote a plugin that will inject translate into our Vue components globally.


ngVue utils

Team ATM wrote a library to register plugins for assisting the migration from Angular to Vue.

 

https://github.factset.com/FactSet/ng-vue-utils

 

Register

import ngAppModule from '~ngAppModule';
import Vue from 'vue';

import constants from './constants';
import {translate} from '../lang/en-US.messageformat.json';
import store from './components/vue/store';

import {registerNgVuePlugins} from '@fds/ng-vue-utils';

registerNgVuePlugins(ngAppModule, Vue, {
  constants,
  translate,
  store
});

Resources

ngVue

By Thomas Truong

ngVue

ngVue in FactSet

  • 79