Skip navigation
All People > ddraper > Dave Draper's Blog > 2017 > January > 12

Re-visiting Vue.js

Posted by ddraper Jan 12, 2017
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

I've now experimented with creating the same simple Alfresco client in Vue.js, React, Aurelia and Angular. When I created the first client in Vue.js I built up the project from scratch rather than using the CLI in order that I could better understand Node.js, Express, webpack, etc. This resulted in me creating an NPM package to configure Node.js middleware to handle authentication against an Alfresco Repository. When using the various CLIs for the other frameworks I found that they all were aimed at creating a Single Page Application and I ended up creating proxy configuration to re-route REST API requests to Alfresco. As this approach is also available in Vue I wanted to explore this option as I begin to move all the implementation forwards. 

 

Setting up the proxy was very simply a case of adding a "proxyTable" entry to the index.js file:

proxyTable: {
   '/proxy/alfresco': {
      target: 'http://localhost:8080/alfresco',
      changeOrigin: true,
      pathRewrite: {
         '^/proxy/alfresco': ''
      }
   }
},

 

...but getting the touter configured was a little more tricky because changes between versions 1 and 2 of Vue.js meant that some of the blog posts are out of date. However, following the official documentation ultimately proved most useful. 


Defining the basic application routing structure was quite straightforward as well... with a main HTML page containing:

<div id="app">
   <router-view></router-view>
</div>

...it was possible to setup up the main.js file to bind the a router with a Login and Home components as follows...

const routes = [
   {
      path: '/',
      redirect: '/home'
   },
   {
      path: '/home',
      component: Home,
      beforeEnter: (to, from, next) => {
         if (auth.loggedIn()) {
            next();
         } else {
            next('/login');
         }
      }
   },
   { path: '/login', component: Login }
];

export const router = new VueRouter({
   routes: routes
});

new Vue({
   router
}).$mount('#app');

 

The "/home" route is protected with a "beforeEnter" guard that uses my "alfresco-js-utils" NPM package for ensuring that the current user is logged in.

 

Having completed the authentication handling it was just a case of porting my previously created components to the new project (you can view the code at the time of writing by checking out this tag).

 

I was interested to see how I would feel about coming back to Vue.js having subsequently looked at React, Aurelia and Angular and in my opinion its the most satisfying to code in. There are still frustrating elements but the documentation and tooling is excellent and the CLI gives you an excellent starting point for development. 

Vanilla Angular 2 Client

Posted by ddraper Jan 12, 2017
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

Having previously created my basic Alfresco Repository browsing application in Vue.js, React and Aurelia I'm on something of a roll. The next framework I wanted to look at was Angular 2 (except that you can't call it that anymore, it's just Angular). Initially I'm going to look at vanilla Angular 2 before reviewing Alfresco's own ADF.

 

Once again there is a CLI that aims to get you up and running as quickly as possible, and as with React and Aurelia it's geared around Single Page Application creation so there was a requirement to handle authentication against the Alfresco Repository. 

 

The authentication strategy is the same (a familiar theme in reviewing all these frameworks) where a router is used to ensure that only authenticated users gain access to Alfresco content and the approach is well described in this blog post.

 

I had a few issues initially working through the instructions but most (such as this issue) were solved by a quick Google. The error messages seem good, but you still have to know what they mean... for example I hadn't declared my "HomeComponent" and "LoginComponent" in my declarations array - the error message made a lot more sense after I'd resolved the problem!

 

Creating the authentication router was quite straightforward (from app.routes.ts):

export const routes = [
  { path: 'login', component: LoginComponent },
  { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [LoggedInGuard] }
];

 

...and the UserService approach (from the previously mentioned blog post) was easily adapted to make use of the Authentication utility functions from my alfresco-js-utils NPM package (despite me needing to use "require" rather than "import" for some reason I couldn't resolve).

 

It was definitely harder to get the template for the login component working (although I'm sure there are alternative ways in which it could have been done)...

@Component({
  selector: 'login',
  template: `<form (ngSubmit)="onSubmit()">
      <label><input name="username" [(ngModel)]="username" placeholder="username" /></label>
      <label><input name="password" [(ngModel)]="password" placeholder="password" /></label><br/>
      <button type="submit">login</button>
   </form>`
})

 

Compare with the template in Aurelia: 

<template>
   <form submit.trigger="handleSubmit()">
      <label><input ref="username" placeholder="username" /></label>
      <label><input ref="pass" placeholder="password" /></label><br/>
      <button type="submit">login</button>
   </form>
</template>

 

It wasn't intuitive to have to use "ngSubmit" and "ngModel" but again this is probably something that you get used to over time.

 

It was necessary once again to configure proxies for the server to redirect REST API requests to the Alfresco Repository. This was done following the instructions in this video to create a proxy.config.json file and to update the npm script for "start" to include " --proxy-config proxy.config.json".

 

With authentication handled it was time to start building out the same set of components as before.... this was when things began to get frustrating. Due to a combination of TypeScript and the opinionated coding style enforced by Angular I became quickly bogged down in problems that were not fast to resolve. I wasn't able to easily reuse the NodeService from alfresco-js-utils and instead had to follow the patterns described in the documentation.


I also had issues with getting changes to my bound data to trigger a reactive rendering of the list (something that I'd had no problems with in the other frameworks) and on the whole I found the development process frustrating and restrictive. Passing data and events were more usefully described in this post than in the official documentation.

 

Once I'd implemented the List and ListView components it was much more straightforward to create the Toolbar and Breadcrumb. Working in Angular does feel restrictive but I can see how those restrictions might ultimately result in more robust code. Although there is lots of documentation and blog posts it can be quite difficult to find the right answer to problems as there were so many changes through the beta and release candidates phase of Angular development. 

 

Some things I found confusing (but I'm sure there will be a simple explanation for) such as why all my component dependencies needed to be in the app.module.ts "declarations" array and couldn't be declared in the appropriate location (so ListView, Breadcrumb and Toolbar should just be dependencies of List).

 

One advantage I found in Aurelia over Angular was in change detection of bound properties. In Angular you have to implement the "ngOnChanges" life-cycle function and figure out for yourself if the property you're interested in has changed, but in Aurelia you can just create a function with "Changed" appended to the property, for example compare...

 

Angular:

ngOnChanges(changes: any) {
   let newPath = changes["relativePath"];
   if (newPath)
   {
      let breadcrumbData = BreadcrumbUtil.createBreadcrumbs({
         relativePath: newPath.currentValue
      });
      this.breadcrumbs = breadcrumbData.breadcrumbs;
   }
}

 

...with Aurelia:

relativePathChanged(newPath, oldPath) {
   let breadcrumbData = BreadcrumbUtil.createBreadcrumbs({
      relativePath: newPath
   });
   this.breadcrumbs = breadcrumbData.breadcrumbs;
}

 

You can review the state of this project at the time of writing by checking out this tag from this GitHub repository.