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 in Template
  • 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 us 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-* for each attribute or v-props for an object of all the attributes.

Events

Events can be handled from Vue to AngularJS componets 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

Just like how VueJS doesn't support two-way binding we will need to do the same for ngVue components.

<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 also used as data changes being sent back to the callback 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 in Template

Just like in Angular, using constants in templates in Vue requires a little 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 now 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 Angular, Vue 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 Vue components so if you're converting an AngularJS component with broadcasting logic. You can emit the responsibility to parent (most likely 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

  • Centralized 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 Vue

  • We can move state into Vuex while migrating

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    options: {
      reveal: false,
    }
  },
  actions: {
    setReveal({commit}, show) {
      commit('setReveal', show);
    },
  },
  mutations: {
    setReveal({options}, show) {
      options.reveal = show;
    },
  },
  getters: {
    reveal: ({options: {reveal}}) => reveal,
  },
});

Store

Translate

From Web Build Tools we should be able to do the following:

That is not possible because the root of the app is Angular, not a Vue component.

Translate plugin

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

It works in the same way as mapGetters from Vuex

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

Translate plugin example

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

Resources

Copy of ngVue

By alecsx

Copy of ngVue

ngVue in FactSet

  • 41