Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrate Angular2 into existing JSF project

I'm looking into a new frontend framework for our company's JSF portal and am considering Angular2. I want to gradually migrate specific components on the page from JSF to Angular2 / REST. I don't want to use Angular2 for routing, at least not yet, and I don't want Angular to completely take over the page: some components will still need to be JSF for the foreseeable future.

Ideally, I'd wrap the content of the body of my JSF template with my Angular root component and project the HTML rendered by JSF into the root component, so that the JSF works as before and any Angular components within the template are picked up and can all communicate. E.g.:

<h:body>
  <my-app>
    <h:panelGroup styleClass="languageSwitcher">
      <h:form>
        <h:selectOneMenu value="#{languageHandler.language}" onchange="submit()">
          <f:selectItem itemValue="en" itemLabel="English" />
          <f:selectItem itemValue="nl" itemLabel="Dutch" />
        </h:selectOneMenu>
      </h:form>
    </h:panelGroup>

    <my-angular-component data-source="/rest/mydata"></my-angular-component>
  </my-app>
<h:body>

With Angular 1, I'd use transclusion to make this work. However, as I understand it, Angular 2 content projection does not work on the root component, as the rendered HTML is not considered an Angular-compiled view.

I also considered using the root component's templateURL to get the JSF rendered page dynamically, but this is difficult to implement and doesn't play well with the numerous POST's that JSF does.

The only way I can think to make this work is to make a root component of each Angular component that replaces a bit of JSF, and on every page bootstrap all components I use. The drawback here is that I need a lot of boilerplate code to bootstrap every Angular component I build, and they don't have a shared root component so communication between them is limited. Furthermore, I'll need to configure each Angular component through attributes, but as these aren't picked up automatically either I'll need to add custom code to each component to pick them up:

class MyAngularComponent {
  constructor(public elementRef: ElementRef) {
    this.dataSourceUrl = this.elementRef.nativeElement.getAttribute("data-source");
  }
}

Then when I finally replace the entire frontend with Angular, I have to refactor each component again to use @Input in stead of retrieving information from attributes manually.

Does anybody know a better way to do this? Or do JSF and Angular2 simply not mix well?

like image 493
Romke van der Meulen Avatar asked Feb 04 '16 17:02

Romke van der Meulen


1 Answers

If you can't make a full page the unit of rewrite, you will have to split the page in sections and migrate them one section at a time.

Just take a section of the page, create a JSF component and make it a fully bootstrapped angular 2 app, by reusing the HTML and CSS only.

If you need to integrate this into the JSF lifecycle instead of calling REST web services, you need to inject the data produced by the angular 2 in a hidden field of a JSF form. Place the data in JSON format and deserialize it on the server using Jackson.

Its likely all not worth it, compared to rewriting the app one page at a time using angular 2 and rest controllers.

You can configure the server to redirect certain pages to serve static files which are Angular 2 pages, while the rest remains under JSF.

like image 96
Angular University Avatar answered Oct 14 '22 00:10

Angular University