Exercise 10: NG2 APP Component Rendered In A Browser View#

Warning

This exercise requires a working buildout using a fork of the collective.jstraining package.

For this exercise, we will run an Angular 2 application inside a Plone browser view.

We have most of the Angular 2 boiler plate code created for you so let us finish up a few things so you can customize it.

In this case we are going to use angular client to create the app inside the package.

You will be working in the exercise10 directory of the collective.jstraining package.

Bootstrap#

Install npm dependencies

cd exercise10/static/ng2app
npm install
npm install -g angular-cli

Add Your Angular 2 Component#

In your exercise10/static/ng2app directory, there is a boilerplate code for an ng2 app.

You can use ng2 CLI to create new components, modules, services, ...

We hope you like TypeScript.

We can change the exercise10/static/src/app/app.component.html to create your own template.

Like I said, you can do whatever in this module.

Register Static Resource Directory#

Next, let us register the static directory we just placed our script into.

To register, you need to add ZCML registration for the static directory your script is in.

Add this to the exercise10/configure.zcml file

<plone:static
    directory="static"
    type="plone"
    name="exercise10"
    />

Build The File With Webpack#

Our deployment is built using the ng command line tool

cd exercise10/static/ng2app
ng build --prod

Whenever you make a change to your component files, webpack will automatically re-build the distribution.

Register JavaScript Resource#

Angular CLI creates three JavaScript files, one for basic webpack instructions, one with the main JavaScript and another with the styling JavaScript.

You will need to register the three on the exercise10/profiles/default/registry.xml

<records prefix="plone.resources/exercise10-inline"
         interface='Products.CMFPlone.interfaces.IResourceRegistry'>
  <value key="js">++plone++exercise10/ng2app/dist/inline.js</value>
</records>
<records prefix="plone.resources/exercise10-main"
         interface='Products.CMFPlone.interfaces.IResourceRegistry'>
  <value key="js">++plone++exercise10/ng2app/dist/main.8b778eea5dd35968ef66.bundle.js</value>
  <value key="deps">exercise10-inline</value>
  <value key="deps">exercise10-style</value>
</records>
<records prefix="plone.resources/exercise10-style"
         interface='Products.CMFPlone.interfaces.IResourceRegistry'>
  <value key="js">++plone++exercise10/ng2app/dist/styles.b52d2076048963e7cbfd.bundle.js</value>
</records>

It is really important that, in case that you need to have dependency on loading the JavaScript, you define in the registry.xml as shown in the main JavaScript.

Finally we want to create a single entry point to load them. Create and register a JavaScript with the requires that load the app in a file called static/ng2app/main.js.

require(['exercise10-inline','exercise10-style','exercise10-main'])

With the main.js defined on the filesystem, we can now create the resource as a new resource:

<records prefix="plone.resources/exercise10"
         interface='Products.CMFPlone.interfaces.IResourceRegistry'>
  <value key="js">++plone++exercise10/ng2app/main.js</value>
</records>

Create Your Browser View#

Warning

This might be redundant with other documentation.

Skip ahead if you know how to create browser views.

Let us load our JavaScript file to only load on a specific page you need it on.

In our case, let us add a basic new page view.

The page template does not need to implement any logic and we can use the main template to bring in the content of the page we are using in the JavaScript(h1).

Add this into your exercise10/page.pt file

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
    xmlns:tal="http://xml.zope.org/namespaces/tal"
    xmlns:metal="http://xml.zope.org/namespaces/metal"
    xmlns:i18n="http://xml.zope.org/namespaces/i18n"
    lang="en"
    metal:use-macro="context/main_template/macros/master"
    i18n:domain="plone">
<body>

  <metal:content-core fill-slot="content-core">
  <metal:content-core define-macro="content-core">
    <app-root></app-root>
  </metal:content-core>
  </metal:content-core>

</body>
</html>

The app-root tag is what is used for the component selector.

You can customize this and use whatever selector you like.

Load Your JavaScript Resource#

Add in view Python code to tell Plone to render the script in the exercise10/browser.py file:

from Products.CMFPlone.resources import add_resource_on_request
from Products.Five import BrowserView


class Exercise10View(BrowserView):

    def __call__(self):
        # utility function to add resource to rendered page
        add_resource_on_request(self.request, 'exercise10')
        return super(Exercise10View, self).__call__()

The most interesting part here is to look at add_resource_on_request.

Finally, wire it up with ZCML registration in the exercise10/configure.zcml file:

<browser:page
    name="exercise10"
    for="*"
    class=".browser.Exercise10View"
    template="page.pt"
    permission="zope2.View"
    />

Installation#

  1. Start up your Plone instance

  2. Install the Exercise 10 add-on

  3. Toggle development mode to make sure the new resources are included

Then, visit the URL:http://localhost:8080/Plone/front-page/@@exercise10.

This is assuming your Plone is located at the URL http://localhost:8080/Plone.

Warning

To make sure your resource registry configuration changes apply, you will need to be in development mode.

You can also toggle development mode on and off, click save, to force configuration to be re-built after changes instead of keeping development mode on.

Production#

In this exercise, there is no special distinction between development and production builds.

Webpack re-builds the resource on every change for you and the JavaScript build file is not added to any bundle—it is loaded for this particular page.