- Node 4+ (preferably the Node LTS release ) for use of npm as an installer
- Follow the steps at the root of this project to install command line tools
If you are running this HOL from behind a firewall, please make sure you have the npm proxy configurations setup properly before running any of the below steps
To get the initial project setup for your Hands-On-Lab, run the following command from the command line at the root of the /beginners-start (if you did not clone the repository on the previous page, create this directory):
ojet create myHOL2017 --template=navdrawer
Once the above command completes, you should have a directory structure that looks similar to Image 1 below.
To build the default project, run:
ojet build
By default this will build a web application for you and add a /web folder to your project root like you see in image 2 below. This is what you will be working with for this HOL, however, if you had Cordova and the appropriate SDK installed for Android, iOS, or Windows, you could also build a JET hybrid application. For details on working with Mobile applications visit the JET Developers Guide
Make all code edits in the projects /src folder.
If you make edits to any HTML, CSS, or JavaScript files while the ojet serve
command is running,
the changes will automatically be pushed to the projects /web folder and the browser will refresh.
Adding or removing libraries from the project will require a rebuild.
IMPORTANT
If you make changes to files in the projects /web folder, they will be overriden the next time you do a build or serve with what is in the projects /src folder. Only make edits to files under the projects /src folder
In JET, there is a concept of a reusable component called a composite component. You will often see this referred to as a CCA component as well. CCA stands for Composite Component Architecture. These special kinds of components are built according to the HTML5 Web Component specification and can be re-used across multiple Oracle development frameworks and tools, such as the Visual Builder Cloud Service and Sites Cloud Service.
To create your new component run the following command from the root of the project that you just created.
ojet create component my-chart
The name of your component can be different, but it must be all lowercase and have at least one hyphen in the name. This naming convention is part of the HTML5 web component specification.
Once you have created your component, you will see that it has been added to a directory called jet-composites using the name that you gave your component. This new component directory contains the default template. The directory structure of your project should now look like image 3 below
So far, you have used the command line for quickly setting up the structure of your application. From this point on, you are going to be editing code, as well as copying and pasting code from the Oracle JET Cookbook website. JET is written in regular JavaScript, HTML, and CSS. Because of this, you can use just about any editor that provides support for these technologies.
The screenshots showing code and application structure in this HOL, will be from NetBeans IDE. NetBeans can open an existing JET application without any configuration or special setup. Just choose "open project" from the NetBeans menu toolbar or menu and navigate to the root of your application.
Now that you have a new composite component, let's add it to the Dashboard page of your application. JET starter templates use a feature of JET called ojModule. This is the ability to define a view (HTML) and a viewModel (JS) and combine them to deliver a specific section of the page as a simple module. These view and viewModel files are found in the /js directory under directories of the same name.
Open the dashboard.html file from the projects src/js/views directory and add the following HTML code just under the <H1>
element.
<my-chart id="chart1"></my-chart>
The resulting code will look like image 4 below.
Now open the dashboard.js file located in the projects src/js/viewModels directory and add a reference to your new my-chart component in the define block at the top of the file.
The code you are going to add is a path to the loader.js file of your component.
my-chart/loader
and the final code will look like image 5 below.
Save both files and run your application again by typing:
ojet serve
You should see the application loaded in your default browser, and the Dashboard page will look like image 6 below. Notice the Hello from Example Component message.
By default, your new component only displays new content into your page. However you can define HTML5 attributes for your component that will allow the developer to pass in values to your component at runtime. Your component can then process those values and use them to manipulate the content that you want to display.
To make things simple, let's let the developer pass in the message that we display when the component is rendered. Re-open the dashboard.html file and add an attribute to the <my-chart>
element. Name this attribute my-message and set the value to anything you like.
<my-chart id="chart1" my-message="My new message from runtime"></my-chart>
Notice that the custom attribute starts with a prefix of my-. It's a good idea to add some kind of prefix to your attributes to help avoid the chance of naming an attribute after some existing attribute that you were not aware of. Like a reserved word for the base HTML element that your composite component could be based on.
You now have the HTML code ready to send a new message to your component. But you need to tell your component to look for that attribute first, and then decide what you are going to do with that information once you find it.
Go to the projects src/js/jet-composites/my-chart/ directory and open the component.json file. This is the main definition file for your components metadata. You can set the name, description, version, and many other propertiess in this file. One important property to set is the jetVersion property. This tells a developer what version of JET your component is written (and hopefully tested) to work with. Most of these properties will be used when you publish your component to a future component catalog.
For this Hands-on-Lab, you are going to add the definition of your attribute to the properties object. You will provide the name, and the type of data that is going to be passed by the attribute. The code that you are going to add will be:
"properties": {
"myMessage": {
"type": "string"
}
},
There are a couple of key points to notice in the above code. When you defined the attribute in your HTML code, you used a hyphen (-) to separate your prefix from your attribute name. Notice in the JSON definition, you remove that hyphen and make the first letter that followed it, an upper case letter. The basic rule is that camel-case property names are converted into case-insensitive HTML element attributes with hyphens at the camel-case break point of the original name. So myMessage has become my-message.
You have also defined the type that this attribute will pass, to be a string. The final components.json file will look like image 7 below.
The component now knows to look for the my-message attribute. Let's now connect the business logic in the viewModel of your component to use that attributes value to display the message where we want it.
Open the my-chart-viewModel.js file from your projects src/js/jet-composites/my-chart directory. In the default template, the value for the self.messageText observable is hardcoded to a set value. You will also see a commented out example section for how to check if a specific property is defined, and if it is, then set it to the new value. You are going to uncomment this section and add a line to set the observable value to the string that is passed in by the DOM elements my-message attribute.
Knockout.js observables
An "observable" or "observableArray" is a special type of two-way binding variable used by Knockout.js. When the value is changed by either the UI, or the JavaScript ViewModel, the other references to the observable are automatically updated as well.
Looking at image 8 below, there are a couple things to pay attention to:
- The original definition of the self.messageText knockout observable variable
- Using the context.properties object, we can get the value of the myMessage property and set the value of self.messageText to that value. Notice how a Knockout observable value is set by passing in the value as an argument to a method, and not by using the = assignment operator.
if (context.properties.myMessage) {
self.messageText(context.properties.myMessage);
}
Save your changes and you should see your new message being displayed instead of the default one.
If you still have the
ojet serve
command running, all of these changes will have been saved, compiled and the brower refreshed for you automatically. If you stopped the serve command earlier, re-runojet serve
to see the updates.
You have now finished your first composite component and you could make multiple instances of the element in the dashboard.html file with different messages if you liked. That is pretty boring though, so let's add something a little more complex and make multiple instance of that.
Open the my-chart-view.html from your composites directory. You will see the existing <p>
element that is rendering your runtime message right now. You are going to add a Chart component from the JET Data Visualization collection and bind the type of chart to an attribute that can be defined in the HTML DOM.
To add the chart component to your components view, you are going to copy and paste some HTML from the JET Cookbook page. Open the Bar Chart Cookbook page in a new browser window so you can easily copy and paste between two windows.
Looking at the Cookbook demo page, look for the tabs that allow you to see, demo.html, demo.js or all, and click on the All tab. It will look like image 9 below.
Selecting All will allow you to see both the HTML and the JavaScript at the same time and will be easier for doing copy and paste. Look at the HTML Editor section and copy the code that you see in image 10 below. You do not need any other HTML code from this section.
Place the HTML code into the my-chart-view.html file just below the existing <p>
element.
Remove the attributes for orientation and stack from the code that you copied over.
Also change the value for type
to be [[chartType]]
. You'll create this new variable in a few more steps.
Your code will look like image 11 below when completed.
Now that you have your HTML for the chart, open the my-chart-viewModel.js file and go back to the Cookbook page so you can copy the JavaScript code related to your chart. Image 12 below shows what you are going to copy from the JavaScript Editor section of the Cookbook page.
Paste the code into the my-chart-viewModel.js file just after the context.props
function. Make sure it's still inside of the ExampleComponentModel function though. Image 13 will show the proper location.
You now have the values for the data that will populate your chart, but you need to add a reference to the attribute that will be passed into your component from the custom element. At the top of the my-chart-viewModel.js file, just under the self.messageText
variable, add a new variable called chartType
and give it a default value of bar
self.chartType = "bar";
Now go down to where you setup the myMessage assignment and add another assignment for this attribute chartType. Image 14 below will show the final setup in the my-chart-viewModel.js file.
if (context.properties.chartType) {
self.chartType = context.properties.chartType;
}
One final step in the my-chart-viewModel.js file. At the top of the file, you will see a define statement that provides references to the libraries that this component has dependencies. Oracle JET is a module toolkit, where you can use as little or as much of that toolkit as you like. In this case, we need to add a reference to the JET Chart UI component so that our module will know to load it. Your define block should look like this after adding the reference.
define(
['ojs/ojcore', 'knockout', 'jquery', 'ojL10n!./resources/nls/my-chart-strings','ojs/ojchart'], function (oj, ko, $) {
'use strict';
If you haven't noticed yet, you are working backwards from what you did when you setup the myMessage attribute code. You now have the view and viewModel for your composite component done. Next you need to add the chartType property to the component.json file so that the component knows to listen for it from the DOM and pass it to your component logic.
Open the component.json file.
In the properties object, just below where you added your myMessage
definition, add a new one for chartType
. Set the value type to string again.
"properties": {
"myMessage": {
"type": "string"
},
"chartType": {
"type": "string"
}
}
Save your files and reload the app in the browser. Again, if you haven't stopped the ojet serve
command from earlier, all of these changes should be automatically taken care of in your product and the browser will refersh for you. You should see a chart in your Dashboard page with the default chartType of bar being used. It should look like image 15 below
Your last two steps are to update the attributes in your <my-chart>
custom element in the dashboard.html file, by adding the chart-type
attribute. Use line as the new value, and add a second instance of your <my-chart>
custom element with a different message and a different chart-type value. Try something like area or pie to mix it up. Make sure you change the id in your second <my-chart>
instance so you don't have duplicate ids.
<my-chart id="chart2" chart-type="line" my-message="My new message from runtime"></my-chart>
When you are all done, save the dashboard.html file and you should see something like image 16 below.
If your layout isn't exactly the same as what you see in image 16, try adding some of JET's flex layout classes like the code below, to easily make your layout responsive on multiple device sizes.
<div class="oj-hybrid-padding">
<h1>Dashboard Content Area</h1>
<div class="oj-flex oj-flex-items-pad">
<div class="oj-flex-item">
<my-chart id="chart1" chart-type="pie" my-message="My new message from runtime"></my-chart>
</div>
<div class="oj-flex-item">
<my-chart id="chart2" chart-type="line" my-message="My second component message"></my-chart>
</div>
</div>
</div>
Oracle JET uses a data binding layer that provides both one-way and two-way data binding.
Difference between one-way binding and two-way binding:
- one-way - Data changes in the ViewModel are sent to the UI components, and user input from the UI components does not affect the ViewModel.
- The syntax for one-way binding is: "[[ variablename ]]"
- two-way - Data changes in the ViewModel are sent to the UI components, and user input from the UI components is written back into the ViewModel.
- The syntax for two-way binding is: "{{ variablename }}"
The next thing to be done is to extend a chart with a type switcher. This is another Oracle JET component called The JET ButtonsetOne. ButtonsetOne can be used to group related buttons, where only one button may be selected at the same time.
First step is adding data to src/js/jet-composites/my-chart/my-chart-viewModel.js inside of the ExampleComponentModel function
self.chartTypes = [
{id: 'bar', label: 'Bar'},
{id: 'line', label: 'Line'},
{id: 'area', label: 'Area'},
{id: 'combo', label: 'Combo'},
{id: 'pie', label: 'Pie'}
];
Since the variable chartTypes is declared as 'class field' it will be available in the view.
Put the following code into my-chart-view.html before <oj-chart />
component.
<oj-buttonset-one class="chartType">
<oj-bind-for-each data="[[chartTypes]]" as="type">
<template>
<oj-option value='[[type.data.id]]'>
<span><oj-bind-text value="[[type.data.label]]"></oj-bind-text></span>
</oj-option>
</template>
</oj-bind-for-each>
</oj-buttonset-one>
As you remember from the previous section, you need to add a reference to the JET Chart UI component so that the module will know to load it.
In this case you use <oj-buttonset-one />
component. Simply update the define
block in src/js/jet-composites/my-chart/my-chart-viewModel.js
define(
['ojs/ojcore', 'knockout', 'jquery', 'ojL10n!./resources/nls/my-chart-strings', 'ojs/ojchart', 'ojs/ojbutton'], function (oj, ko, $) {
IMAGE 17
Here you can see the horizontal list decorated as buttons. But no button is selected. You can select any button manually but this doesn't affect anything in the view-model.
This means you have no bindings yet except to the list of elements. Let's update component my-chart
to select the first button from buttonset.
Changes in src/js/jet-composites/my-chart/my-chart-viewModel.js
// The variable can be set from context properties or 'bar' by default
self.chartType = ko.observable(context.properties.chartType || 'bar');
Changes in src/js/jet-composites/my-chart/my-chart-view.html
<oj-buttonset-one class="chartType" value="[[chartType]]">
...
<oj-chart id="barChart"
type="[[chartType]]"
...
After these changes the button labeled 'Bar' will be active and the component <oj-chart />
will have type 'bar'.
Note that any clicks on the <oj-buttonset-one />
component still have no effect.
In the previous section, you used double square brackets to bind the value from the view-model to the view. This is a one-way data binding.
If you need two-way data binding you need to use double curly braces instead brackets.
Simply, replace brackets with braces in src/js/jet-composites/my-chart/my-chart-view.html
<oj-buttonset-one class="chartType" value="{{chartType}}">
Let's try to click on the component <oj-buttonset-one />
. The chart automatically changes it's type.
IMAGE 18
This example demonstrates how data bindings work and the easiest way to make the interaction between different components.
To learn more about Oracle JET, resources such as an online training course, and other example applications are available from the Learn page of the JET website