Tuesday Jan 10, 2017

New Year: New Opportunities, New Rewards!

In Dutch they say, "Nieuwe kansen, nieuwe prijzen", at the start of the latest installment of a game show, lottery, etc. Well, each new year offers new opportunities, with new rewards, and here we are in 2017.

I haven't blogged for a while, simply because I've been too busy to do so. Oracle JET is taking up all my time. I've traveled a lot over the past months and that will continue, the first half of the year is almost completely booked full already. At the same time, there's NetBeans IDE or, should I say, "Apache NetBeans (incubating)", which is moving along really well. By that I mean everything in every sense, in that context, from the Apache process, to its continued development by Oracle engineers focused on supporting Java 9, to my continual promotion of it via demonstrations of how to use Oracle JET, to all kinds of dependencies that multiple large organizations have both on NetBeans as a development tool, tooling platform, and application framework.

Oracle JET

I must confess I'm really excited about Oracle JET, for being an open source, free, and library-based JavaScript toolkit. And, no, I'm not excited about just about everything in the world (you could not, for example, get me to promote vacuum cleaners; then again, on the other hand, if it were to be a really effective vacuum cleaner that was simply awesome and somehow open source, ok, well, never mind, I'd promote your open source vacuum cleaner and probably even for free) or even everything that my employer wants me to be excited about, i.e., there are enough things my employer has suggested I promote that I feel really lukewarm about and that didn't excite me enough to spend time understanding and promoting, simply because of not completely connecting to my areas of interest, etc.

That's also something that's underhighlighted about Oracle as a whole—it is simply such a massive ecosystem of products that once you're connected to a part of it, you really do have a lifetime's worth of interesting work ahead of you. Oracle provides a lot of opportunity for learning and meaningfulness in that sense.

Java Desktop

So. Where does that leave my erstwhile enthusiasm for the Java desktop? Now that I'm a fullblown JavaScript enthusiast, spreading the gospel of browser-oriented development, have I simply dumped my many years of advocacy of the Java desktop?

No, not at all. What I have done over the years is very simple and easy to understand—I have advocated tools and technologies for industrial application development. As opposed to what? Well, as opposed to game development, for example, which I've always considered a bit, well, trivial. I've always found it most interesting to focus on development that means something real, that makes a difference, whatever those phrases mean, as opposed to those that simply seek to entertain or that do little more than help fill time, though I don't want to necessarily pass moral judgement here either, since a lot of really skilled and artistic work is done in those areas, of course, at the same time. In general, I definitely prefer the complexities of solving problems for applications targeted for the back office, or behind the firewall, or in secure areas, over those targeted at non-technical end users.

What does that mean, concretely, in terms of what I find meaningful, i.e., industrial application development? I have, and continue to do so, promoted the open source tools and technologies that, in my humble opinion, make sense when you're creating large enterprise solutions. Are you creating large applications in the areas of finance, human resources, logistics, and the like? Well, then, moving your data to "the Cloud" and your user interface to the browser, whether on mobile or desktop, makes perfect sense. (And the Oracle Cloud is truly comprehensive and stable, with a large ecosystem of knowledgeable experts and enthusiastic partners to help you. I know this, since I have interacted with many of them directly and personally over the past months.) Are you, on the other hand, creating large applications in the areas of bioinformatics, aerospace, and defense, where you want to make maximum use of desktop resources and graphic visualization and you have a lot of in-house Java desktop experience while the volatility of the JavaScript ecosystem is a real blocker for migration to the browser? Well, great, in that case, the Java desktop is perfect and you clearly need a lot more than Java toolkits such as JavaFX or Java Swing—you also need an application framework, module system, windowing/docking framework, and so on. In fact, you need the NetBeans Platform.

Wait, am I saying that there's a place for both JavaScript and Java, for both browser and desktop? Yes, of course there is—"the right tool for the right job" is simply the best approach to anything. Therefore, my argument is that you shouldn't be "religious" about your choices, of course...

Tools

...except for your tools. :-) Ultimately, you need a comprehensive and stable development environment to create your applications, regardless of where they are to be deployed. The best thing to do is to use open source tools and technologies, uniquely provided by NetBeans IDE, which is in the process of becoming an Apache project, which means that you can participate in its development process and roadmap far more than any other development tool in the history of development tools.

Hurray, 2017 is going to be great and is filled with opportunities that all make sense and all have a logical place in unlocking data and turning it into actionable information that makes a real difference in people's lives. 

Friday Dec 16, 2016

Custom Component for Zipping and Downloading Files

Here's a handy custom component (i.e., a CCA component) for zipping files and downloading them, in an Oracle JET application:

<fileDownloadForm
    file="{{file}}"
    content1="{{htmlContent}}"
    content2="{{jsContent}}">
</fileDownloadForm>

I've created it as part of a project where we want to let developers design a CCA component and then download it as a ZIP file, so that it can be distributed to those who want to make use of the component. That's the reason you can see above that two files are assumed to be provided, with 'file' being the name of the file, used for both the view and the viewModel.

In an application, the above component is rendered as follows:

What happens when "demo" is changed to "sample" in the text field above and then the "Download" button is clicked? Well, when you do that, a download process begins and you'll have a ZIP file, with this content, yes!, a CCA component:

So... what this blog entry is about is... how to create a CCA component for downloading CCA components... 

The structure of the CCA component you'll create is as follows:

Here's the JSON file, "fileDownloadForm.json":

{
  "properties": {
    "file": {
      "description": "file name.",
      "type": "string"
    },
    "content1": {
      "description": "html content.",
      "type": "string"
    },
    "content2": {
      "description": "js content.",
      "type": "string"
    }
  }
}

Here's the view, in "fileDownloadForm.html":

<div class="oj-panel">
    <label>ZIP Name:</label>
    <input  type="text"
            data-bind="ojComponent: {
                component: 'ojInputText',
                value: file}"/>
    <button class="oj-button-primary"
            style="float: right;"
            data-bind="
                click: downloadFile,
                ojComponent: { 
                        component: 'ojButton', 
                        label: 'Download' }">
    </button>
</div>

Here's the business logic in the viewModel, "fileDownloadForm.js":

define(['knockout', 'jszip', 'file-saver'],
    function (ko, JSZip) {
        function model(context) {
            var self = this;
            self.file = null;
            self.content1 = null;
            self.content2 = null;
            context.props.then(function (properties) {
                if (properties.file) {
                    self.file = properties.file;
                }
                if (properties.content1) {
                    self.content1 = properties.content1;
                }
                if (properties.content2) {
                    self.content2 = properties.content2;
                }
            });
            self.downloadFile = function (model, event) {
                if (event.type === 'click' || 
                        (event.type === 'keypress' 
                        && event.keyCode === 13)) {
                    var zip = new JSZip();
                    zip.file(self.file+".html", self.content1);
                    zip.file(self.file+".js", self.content2);
                    zip.file("loader.js", "to be done");
                    zip.file("README.txt", "to be done");
                    zip.generateAsync({type: "blob"})
                            .then(function (content) {
                                saveAs(content, self.file+".zip");
                            });
                }
            };
        }
        return model;
    }
);

The above assumes you've set up these two libraries in your application:

I.e., somehow, via Bower or otherwise, you've included them like this:

In 'main.js', you should have these references in the 'paths' of 'requirejs.config':

   'file-saver': 'libs/file-saver/FileSaver',
   'jszip': 'libs/jszip/dist/jszip'

And, to wrap things up, tying everything together, you have "loader.js":

define(['ojs/ojcore',
    'text!./fileDownloadForm.html',
    './fileDownloadForm',
    'text!./fileDownloadForm.json',
    'ojs/ojcomposite'],
  function(oj, view, viewModel, metadata) {
    oj.Composite.register('fileDownloadForm', {
      view: {inline: view},
      viewModel: {inline: viewModel},
      metadata: {inline: JSON.parse(metadata)}
    });
  }
);

As a simple example of usage of the above, include the following in the "viewModel" of the handy custom component outlined at the start of this blog entry:

self.file=ko.observable('demo');
self.htmlContent=ko.observable('dummy html content');
self.jsContent=ko.observable('dummy javascript content');

Now, whenever you include the handy custom component, anywhere in your application, the user can click "Download" and then they'll have a ZIP file downloaded with the specified content in the specified files.

Tuesday Dec 13, 2016

Page Flow, Enablement, and ojListView (Part 2)

Before going to the next page, as shown in yesterday's blog entry, we want to display a confirmation dialog.

We'll use 'ojDialog' for this:

http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=dialog&demo=modal

Start by adding 'ojs/ojdialog' to the 'define' block of the viewModel of your Oracle JET module, together with a function for opening an ojDialog, yet to be defined, as well as a function for going to the next section:

self.next = function() {
  $("#confirmDialog").ojDialog("open");
};
self.confirm = function() {
  app.router.go('incidents');
};

Now, add your dialog in the view, i.e., probably, at the end of the HTML page that provides the view for the above functions:

<div id="dialogWrapper">
    <div style="display:none"
         id="confirmDialog"
         title="Confirm"
         data-bind="ojComponent:{
             component: 'ojDialog',
                initialVisibility: 'hide'}">
        <div class="oj-dialog-body">
            <div class="oj-panel">
                <p>
                    Do you really want
                    <span data-bind="text: $data.selectedItem()"></span>?
                </p>
            </div>
        </div>
        <div class="oj-dialog-footer">
            <button class="oj-button-primary"
                    data-bind="click: confirm,
                               ojComponent: {component: 'ojButton',
                                             label: 'Confirm'}">
            </button>
        </div>
    </div>
</div>

Monday Dec 12, 2016

Page Flow, Enablement, and ojListView (Part 1)

Let's combine a couple of recent blog entries into a scenario. We'll combine Simple JSON and ojListView Sample with From ojNavigationList to ojButton and add some additional bits and pieces. 

Start by setting up Simple JSON and ojListView Sample. Now, we have a new requirement—we need a "Next" button, i.e., for navigating to the next section of our single page application. However, that button should only be enabled if something is selected in the list. Some small tweaks are needed to achieve this.

Take a look in particular at the bits in bold below, which are the only differences to Simple JSON and ojListView Sample:

define(['text!../data/employees.json', 
    'ojs/ojcore', 'knockout',
    'jquery', 'appController', 
    'ojs/ojlistview',
    'ojs/ojarraytabledatasource'],
 function(file, oj, ko, $, app) {
    function DashboardViewModel() {
      var self = this;
      self.data = [];
      self.selectedItem = ko.observable(-1);
      var content = JSON.parse(file);
      var employees = content.employees;
      for (var i = 0; i < Object.keys(employees).length; i++) {
          var employee = employees[i];
          self.data.push({
              first: employee.firstName,
              last: employee.lastName
          });
      }
      self.optionChangeListener = function (event, ui) {
          if (ui.option === 'currentItem' && ui.value !== null) {
             self.selectedItem(ui.value);
          }
      };
      self.dataSource = new oj.ArrayTableDataSource (
          self.data,
          {idAttribute: "first"}
      );
      self.next = function() {
          app.router.go('incidents');
      };
    }
    return new DashboardViewModel();
  }
);

Here's the view, notice in particular the usage of the "disabled" property of the ojButton, while also noticing the "optionChange" property of the ojListView:

<div class="oj-hybrid-padding">
    <h2>Select Customer</<h2>
    <ul data-bind="ojComponent: {
               component: 'ojListView',
                  data: dataSource,
                  optionChange: optionChangeListener,
                  item: {template: 'employee_template'},
                  rootAttributes: {style: 'width:20%;height:80%'},
                  selectionMode: 'single'}">
    </ul>
    <script type="text/html" id="employee_template">
        <li>
            <h3 data-bind="text: first"></h3>
            <span data-bind="text: last"></span>
        </li>
    </script>
    <button id= "nextButton"
            class="oj-button-primary"
            style="width: 5%"
            data-bind="
                click: next,
                ojComponent: {
                    component: 'ojButton',
                       label: 'Next',
                       disabled: selectedItem() == -1 }">
    </button>
</div>

Thanks to my colleague Max Froeschl for these insights.

Saturday Dec 10, 2016

json2form Generator for Oracle JET applications

There's often a need to create standard forms for different purposes in an application, such as these, an incident entry form and a customer feedback form:


Imagine if all that would be needed for creating the two forms above would be this in each view:

<json2form json="{{jsonFile}}"/>

For each view containing the above, the viewModel would load a file such as this for the form on the left above:

[
    {
        "key": "incidents_form",
        "title": "Incident Entry Form",
        "description": "Enter Incident Details",
        "message": "We want incidents fixed fast!",
        "properties": [
            {"name": "Type", "options": ["Serious", "Minor"]},
            {"name": "Description"},
            {"name": "City"},
            {"name": "State"},
            {"name": "Country"}
        ]
    }
]

And this for the form on the right above:

[
    {
        "key": "customer_form",
        "title": "Customer Feedback Form",
        "description": "Enter Customer Feedback",
        "message": "We love our customers!",
        "properties": [
            {"name": "Name"},
            {"name": "Feedback"},
            {"name": "Rating", "options": ["Excellent","Good","Bad"]}
        ]
    }
]

To achieve the above, we need to make use of the composite component architecture, described here:

http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=composite&demo=basic

I have blogged about a simple getting started scenario for composite components architecture here:

https://blogs.oracle.com/geertjan/entry/minimal_oracle_jet_composite_component

We also need to make use of the metadata-driven dynamic form functionality described here:

http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=controlcombos&demo=formdynamic

In this case, what we need is a structure like this:

See yesterday's blog entry if you want your applications structured like the above.

Here's the definition of loader.js:

define([
    'ojs/ojcore',
    'text!./view.html',
    './viewModel',
    'text!./metadata.json',
    'ojs/ojcomposite'],
        function (oj, view, viewModel, metadata)
        {
            oj.Composite.register('json2form', {
                view: {inline: view},
                viewModel: {inline: viewModel},
                metadata: {inline: JSON.parse(metadata)}
            });
        }
);

Here's the definition of metadata.json:

{
  "properties": {
    "json": {
      "type": "Array"
    }
  }
}

Here's the definition of viewModel.js:

define(['ojs/ojcore', 'knockout',
    'ojs/ojinputtext',
    'ojs/ojradioset', 'ojs/ojbutton'],
function (oj, ko) {
    function CompositeModel(context) {
        var self = this;
        context.props.then(function (props) {
            self._props = props;
            _initProperties();
        });
        function _initProperties() {
            self.descriptors = ko.computed(function () {
                var mapped = self._props.json.map(
                        function (json) {
                            var def = {
                                title: json.title,
                                description: json.description,
                                message: json.message,
                                properties: json.properties
                            };
                            return def;
                        }
                );
                return mapped;
            });
        }
    }
    return CompositeModel;
});

Here's the definition of view.html:

<div data-bind="foreach: descriptors" class="oj-panel-alt2 oj-margin oj-flex-item">
    <div class="oj-flex-item oj-panel-alt2 oj-margin">
        <h1 data-bind="text: title"></h1>
        <h3 data-bind="text: description"></h3>
    </div>
    <div class="oj-flex-item oj-panel-alt2 oj-margin">
        <!-- ko foreach: $data.properties -->
        <div class="oj-flex-item oj-panel-alt oj-margin">
            <label data-bind="text: $data.name"></label>:
            <!-- ko if: $data.options -->
                <!-- ko foreach: $data.options -->
                <div data-bind="ojComponent: {
                        component: 'ojRadioset',
                        value: $data}" >
                    <span class="oj-choice-row">
                        <input type="radio" value="$data">
                        <label><span data-bind="text: $data"></span></label>
                    </span>
                </div>
                <!-- /ko -->
            <!-- /ko -->
            <!-- ko ifnot: $data.options -->
            <input id="inputcontrol"
               data-bind="ojComponent: {
                   component: 'ojInputText',
                   rootAttributes: {style:'max-width:100em'}}">
            <!-- /ko -->
        </div>
        <!-- /ko -->
    </div>
    <div class="oj-flex-item oj-panel-alt2 oj-margin">
        <b data-bind="text: message"></b>
    </div>
</div>
<hr>

And, finally, here's how the files are loaded and used in all the viewModels that need to make use of it:

define(['text!./customers.json',
    'ojs/ojcore',
    'knockout',
    'jquery',
    'ojs/ojcomposite',
    'app/jet-composites/json2form/loader'],
        function (file, oj, ko, $) {
            function CustomerViewModel() {
                var self = this;
                self.jsonFile= JSON.parse(file);
            }
            return new CustomerViewModel();
        }
);

There is more to be done to complete this scenario because right now we're only rendering the forms and not processing the input. That will be the next step of this series.

Right now, based on the above, you're able to transform a JSON file into a form, which is the first step in this scenario. Thanks to my colleague Max Starets for providing a similar scenario to this recently.

Friday Dec 09, 2016

Restructuring of Oracle JET Applications

During UKOUG 2016, this week, I learned a cool thing from my colleague Lyudmil Pelov—the response to the most frequently asked question from the Oracle JET sessions I have been doing around the world: "Isn't the 'js/views' and 'js/viewModels' structure a technical rather than a functional architecture? And wouldn't it be better to have both sides of an Oracle JET module in the same folder?"

Well, take a look at this, the "navdrawer" template restructured based on functionality, e.g., in the "app/pages/dashboard" folder, both sides of the "dashboard" module are found, rather than the viewModel being in 'js/viewModels' and the view in 'js/views':

If you prefer this structure over the default structure brought to you by the Oracle JET templates, take the following steps. I suggest you first get it working in the "navdrawer" template, before trying to apply this structure to your own application. 

  1. Set up the 'navbar' template, i.e., use the "Oracle JET QuickStart Basic" template in NetBeans IDE.

  2. Create a new folder named 'app', as shown in the structure above.

  3. Inside 'app', create a folder called 'pages', with a subfolder for each of the custom Oracle JET modules provided by the 'navbar' template, i.e., 'dashboard', 'incidents', 'customers', and 'about'. Move the 'dashboard.js' and 'dashboard.html' from 'js/viewModels' and 'js/views' into the 'app/dashboard' folder. Do the same for the other Oracle JET modules.

  4. Move the 'libs' folder into 'app' (and tweak '.bowerrc' and potentially other similar files, to download JavaScript libraries into the new location of 'libs'). In 'main.js', change all the paths to JavaScript libraries to reflect their new locations, i.e., they're no longer in 'libs'; they're in 'app/libs'.

  5. Move 'appController.js', 'main-release-paths.json', and 'main.js' into the 'app' folder. In 'index.html', correct the reference to 'main.js' to its new location in 'app' and do the same for 'require.js', which should now be in 'app/libs/require'.

  6. In the 'requirejs.config' section in 'main.js', change the 'baseUrl' to point to '.' instead of 'js'.

  7. In 'appController.js', change the router as follows and notice that you can also have a functional nested structure for your Oracle JET modules:
    function getPagePath(path) {
      return 'pages/' + path + '/' + path.substr(path.lastIndexOf('/') + 1);
    }
    self.router = oj.Router.rootInstance;
    self.router.configure({
     'dashboard': {value: getPagePath('dashboard'), label: 'Dashboard', isDefault: true},
     'incidents': {value: getPagePath('incidents'), label: 'Incidents'},
     'customers': {value: getPagePath('customers'), label: 'Customers'},
     'about': {value: getPagePath('about'), label: 'About'}
    });
    
  8. In 'main.js', as the new first lines in the 'require' block, override the default locations of the viewModels and views, i.e., rather than the default 'js/viewModels' and 'js/views', you now want them to both be found within the 'app' folder (in the location specified by the router in the previous step):
    oj.ModuleBinding.defaults.modelPath = 'app/';
    oj.ModuleBinding.defaults.viewPath = 'text!app/';
    

At this point, you should be able to delete the 'js' folder, i.e., there should be nothing in it anymore.

Run the application and everything should work exactly as before!

Thursday Dec 08, 2016

Wireframing with Oracle JET

I learned a few interesting things from my colleague Sylvain Côme in London today. Sylvain is a very big enthusiast of Oracle JET and is introducing it in a variety of contexts. For wireframing, he uses Adobe XD. For the images in his wireframes, he has installed SVG Crowbar into his Chrome browser, which enables him to download SVG files of images in the Oracle JET Cookbook. He then imports those SVG files into his wireframe in Adobe XD, where he can even edit them, resulting in a wireframe with awesome Oracle JET visualizations, which will, once the wireframe is accepted, look identical to the final app since the SVG files are created directly from the image of the related Oracle JET component in the Oracle JET Cookbook.

That's a lot of info to process all at once, so let's take it step by step.

1. Start up Chrome,  show the Chrome bookmarks bar (Ctrl + Shift + B), and then go here and follow the instructions: 

http://nytimes.github.io/svg-crowbar.

2. Go to one of the cool data visualizations in the Oracle JET Cookbook, such as this one:

http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=dataVisualizations&demo=polarWeatherPlot

3. Click "SVG Crowbar 2" in the bookmarks bar and you'll see (depending on how many SVG images are available), an icon for each SVG image. In this case, there's only one SVG image on the page, which makes it very simple and simply click the Download button:

4.  You now have an SVG image. Open Adobe XD, which is not supported yet on Windows, which is what I'm using, so let's use this instead, just to prove the point:

http://editor.method.ac

Click the link above and then go to File | Open SVG. Browse to the SVG you downloaded and open it into the above. 

Now, as you can see above, depending on the SVG image you're using, you can edit all kinds of parts of it, and then integrate it into your wireframe. Of course, before downloading it, you can edit various parts directly in the browser within the Oracle JET recipe in the Oracle JET Cookbook too, i.e., tweak code, and then click Apply.

It's pretty powerful, as you can see, that you can use the power of SVG via the Oracle JET Cookbook to create content for your wireframes, very easily indeed!

Wednesday Dec 07, 2016

Integrating Styles into Oracle JET Applications

A lot of organizations have style guidelines for their browser apps. I.e., these style guidelines consist of colors, sizes, icons, etc, normally supported by CSS stylesheets. Wouldn't it be nice if there'd be a few customizable templates for quickly styling Oracle JET applications? Well, take a look here:

http://www.oracle.com/webfolder/technetwork/jet/globalExamples-ThemeViewer.html

Welcome to the Oracle JET Theme Builder. It's been around for a while, though a bit hidden on the Oracle JET Examples page. The Oracle JET Theme Builder is an Oracle JET application that lets you create themes (i.e., CSS stylesheets), based on a set of existing themes, for your Oracle JET applications.

Click "Live Demo" and then click "Instructions" in the top right, which brings you here. Follow those steps and you'll literally have everything you need. Below I have summarized things a bit, though the Instructions speak for themselves.

1. Set Up. Download the ZIP file on the Instructions page, unzip it, and run the 4 Yeoman commands shown on the Instructions page on that folder:

  • When you run "yo oraclejet:restore", both 'npm' and 'bower' will be run, to access all the required JavaScript libraries for any Oracle JET application. 
  • When you run "yo oraclejet:add-sass" and you receive error messages about Python being needed, the simplest solution is to downgrade 'node' to v5.x, e.g., I have v5.9.1, i.e., when I was on v6x, I had all kinds of problems, e.g., needing Python and then something else, which I fixed by downgrading node. Doing this has not had adverse effects so far. 
  • When you run "yo oraclejet:add-theme mytheme", you populate "src\themes\mytheme" with content. Make sure that the name you specify is literally "mytheme", i.e., do not change it to something different. "mytheme" is the fixed name of the custom theme you'll be creating. After you've created your theme, i.e., a set of CSS files, you can name them whatever you like.
  • When you run "grunt serve --themes=all:all", the browser will show the Theme Builder running locally, which is what you want to have happen so that you can start building your themes.

2. Theming. At this point you should see this and now you can choose a combination of different buttons on the left to get to the theme that you want to base your own theme off of. Below, notice I am working on "web" and "mytheme":

Now, look at the Palette in the left column, for example, notice the first color is "$interaction1Color". In "src/themes/mytheme/web", go to "_mytheme.web.settings.scss" and look for "$interaction1Color", which you'll see is listed as follows:

// $interaction1Color: #0572ce !default;

Change the above to the below:

$interaction1Color: red !default;

When you make the change above and save it, automatically the CSS will be generated, and the browser will refresh, showing you the change you've made:

When the above works for you, get the style guide that you're wanting to integrate into your Oracle JET application. Take note of the color codes and other styles and continue tweaking the SCSS files, using the Theme Builder, as described above, to check the changes you're making. 

3. Usage. At some point, you'll want to see how the CSS files you're generating look in your own Oracle JET application. Follow the earlier blog entry, The Mechanics of Theming Oracle JET Applications, for details on how to set up theming support within your Oracle JET application. Once you've set that up, copy the CSS files that have been generated in "themes/mytheme/web", in this case, into the relevant theme folder in your own application.

Now, isn't this simply an awesome tool? Following the steps above, all the UI elements provided by Oracle JET can be restyled to match the style guidelines of your choice. Note that you do not have to use the "mytheme" theme as a starting point, there are other themes too, which might more closely resemble the end point you're trying to achieve. Pick the one that's closest to your intended theme and then start tweaking it as described in step 2 above. 

Tuesday Dec 06, 2016

From ojNavigationList to ojButton

The Oracle JET "navbar" template provides a navigation bar for switching between Oracle JET modules:

Let's remove that navigation bar and replace it with buttons:

By means of the above, you have more control over the navigation in your page, e.g., you can include validation rules, which will be handled in a future blog entry, etc. Plus, via this mechanism you have the basis of a wizard-like step-through sequence enabling the user to work through a number of different screens. To get the basics shown above, i.e., no navigation bar and buttons instead, do the following.

1. In "index.html", remove the DIV element that has its role set to "navigation". Now the navigation bar is gone.

2. In the view of all your Oracle JET modules, include your buttons, as follows:

<button class="oj-button-primary"
        data-bind="click: next,
                   ojComponent: {
                       component: 'ojButton',
                       label: 'Next'
                   }">
</button>
<button class="oj-button-primary"
        data-bind="click: prev,
                   ojComponent: {
                       component: 'ojButton',
                       label: 'Prev'
                   }">
</button>

3. In the viewModel of all your Oracle JET modules, reference the "appController.js" and use the router to switch to the page applicable to a specific button, e.g., here you see the content of "dashboard.js":

define(['ojs/ojcore', 'knockout', 'jquery', 'appController'],
 function(oj, ko, $, app) {
    function DashboardViewModel() {
      var self = this;
      self.next = function() {
        app.router.go('incidents');
      };
      self.prev = function() {
        app.router.go('about');
      };
    }
    return new DashboardViewModel();
  }
);

That's it, you now have nicely styled (thanks to the Oracle JET CSS classes) buttons for navigating through your Oracle JET modules.

Monday Dec 05, 2016

Simple JSON and ojListView Sample

Simple sample to create ojListView from a JSON file (which I copied locally from here) and therefore looks like this:

{"employees":[
    {"firstName":"John", "lastName":"Doe"},
    {"firstName":"Anna", "lastName":"Smith"},
    {"firstName":"Peter", "lastName":"Jones"}
]}

Here's the business logic:

define(['text!../data/employees.json',
    'ojs/ojcore', 'knockout', 'jquery',
    'ojs/ojlistview',
    'ojs/ojarraytabledatasource'],
        function (file, oj, ko, $) {
            function DashboardViewModel() {
                var self = this;
                self.data = [];
                var content = JSON.parse(file);
                var employees = content.employees;
                for (var i = 0; i < Object.keys(employees).length; i++) {
                    var employee = employees[i];
                    self.data.push({
                        first: employee.firstName,
                        last: employee.lastName
                    });
                }
                self.dataSource = new oj.ArrayTableDataSource(
                        self.data,
                        {idAttribute: "first"}
                );
            }
            return new DashboardViewModel();
        }
);

And the view:

<ul data-bind="ojComponent: {
               component: 'ojListView',
                  data: dataSource,
                  item: {template: 'employee_template'},
                  selectionMode: 'single'}">
</ul>
<script type="text/html" id="employee_template">
    <li>
        <h3 data-bind="text: first"></h3>
        <span data-bind="text: last"></span>
    </li>
</script>

Sunday Nov 20, 2016

React.js Calculator in Oracle JET

Using the techniques discussed here and here, you can integrate a pretty cool React calculator component into your Oracle JET application. By default, this is how it looks in the page:

When hovered over, the calculator animates and is then displayed as follows:

Here's how I'm structuring JSX composites in my Oracle JET application:

Saturday Nov 19, 2016

React.js and Oracle JET (Part 2)

Following on from part 1, the next step is to have support for React JSX in the context of our Oracle JET application. The RequireJS plugin below works perfectly in the context of Oracle JET applications, as outlined below:

https://github.com/podio/requirejs-react-jsx

To use the above in your Oracle JET applications:

  1. Include the above plugin in "bower.json": "requirejs-react-jsx": "1.0.2"

  2. Add the following to the bootstrap file (i.e., main.js) paths directive:
        'babel': 'libs/requirejs-react-jsx/babel-5.8.34.min',
        'jsx': 'libs/requirejs-react-jsx/jsx'
    
  3. Create a file named "app.jsx", e.g., in a folder named "components", with this content, i.e., this defines a simple React component in a JSX file:
    define(function (require) {
        var React = require('react');
        var ReactDOM = require('react-dom');
        function App() {
            this.HelloWorld = React.createClass({
                render: function () {
                    return (
                            <div>
                                <h1>Hello, React!!!</h1>
                            </div>
                            );
                }
            });
        }
        App.prototype.init = function () {
            ReactDOM.render(
                <this.HelloWorld />,
                document.getElementById('root')
            );
        };
        return App;
    });
  4. Now, let's use the above React component in one of our Oracle JET modules:
    define(['ojs/ojcore', 'knockout', 'jsx!components/app'],
        function (oj, ko, App) {
            function HomeViewModel() {
                var self = this;
                self.handleAttached = function (info) {
                    var app = new App();
                    app.init();
                };
            }
            return new HomeViewModel();
        }
    );
    
  5. Finally, let's render the view, i.e., this is the "home.html" for the above "home.js":
    <div id="root"></div>

That's it, the first React component expressed in JSX in an Oracle JET application.

Here's a variation whereby you use a property in your JSX component, where the value changes based on a timer:

define(function (require) {
    var React = require('react');
    var ReactDOM = require('react-dom');
    var messages = ['Hello, World', 'Hello, Planet', 'Hello, Universe'];
    function App() {
        this.Greeting = React.createClass({
            render: function () {
                return (
                        <p>{this.props.message}</p>
                       )
            }
        });
    }
    App.prototype.init = function () {
        this.repeat();
    };
    App.prototype.repeat = function () {
        var ctx = this;
        var randomMessage = messages[Math.floor((Math.random() * 3))];
        ReactDOM.render(
                <this.Greeting message={randomMessage}/>,
                document.getElementById('root')
                );
        setTimeout(function(){ctx.repeat()}, 1000);
    };
    return App;

References: 

https://www.sitepoint.com/getting-started-react-jsx/

http://stackoverflow.com/questions/3264739/image-change-every-30-seconds-loop

Thursday Nov 17, 2016

React.js and Oracle JET (Part 1)

Here is a fantastic small example that works perfectly, showing how to combine React with Require:

http://remarkablemark.org/blog/2016/09/24/react-requirejs-amd/

Let's take that and integrate it into an Oracle JET module.

  1. Include in Bower dependencies: "react": "15.3.2"

  2. Include in "paths" in bootstrap file, i.e., "main.js":
        'react': 'libs/react/react.min',
        'react-dom': 'libs/react/react-dom.min'
    
  3. In your viewModel:
    define(['ojs/ojcore', 'knockout', 'jquery', 'react', 'react-dom'],
     function(oj, ko, $, React, ReactDOM) {
        function HomeViewModel() {
          var self = this;
          self.handleAttached = function(info) {
            ReactDOM.render(
                React.createElement('h1', {}, 'hello from react!'),
                document.getElementById('root')
            );
          };
        }
        return new HomeViewModel();
      }
    );
    
  4. In your view:
    <div id="root"></div>
And that's all. You'll see the message above in your page when you load it.

Monday Nov 14, 2016

Top 5 Features of Oracle Application Container Cloud

I asked Shaun Smith, product manager of Oracle Application Container Cloud (ACC), what he considers its top 5 features to be.

He responded with this list:

  1. Polyglot platform. Use the language of your choice. Today we have Java SE, Node.js, PHP, and will be adding support for Java EE WAR deployment, as well as Python and Ruby. We're open to supporting other languages if the demand is there.

  2. Open platform. Run anything. This is an ideal platform for running open source stacks and containers like Tomcat, Jetty, Express, etc.

  3. Elastic. Applications can be scaled in/out and up/down to meet demand. Auto-scaling is coming soon so that, based on metrics, scaling actions can be triggered.

  4. Integrated with Oracle Developer Cloud Service. Handy for end-to-end continuous integration, build, test, and deployment.

  5. Integrated with Oracle Public Cloud ecosystem. This combination is ideal for building cloud native (microservice style) applications that need messaging, storage, etc.

Also, Java SE Advanced is included, i.e., you're able to interact with Flight Recorder under the Admin tab.  Once there, you'll see "Recordings".  The help text explains what you can do. The best strategy in production is to turn on Flight Recorder in "continuous" mode so that it is recording all the time, keeping a  user-specified amount of data/minutes of data. Then, in ACCS, one can trigger the dump of this data if any anomalous behavior is detected. From ACCS, you can download Flight Recorder data dumps and open in Mission Control on your desktop.

Watch Shaun in action here, where he provides a really great overview of the key features of ACC:

Updates to Oracle JET MOOC

Before JavaOne/OpenWorld this year, we ran the first session of the Oracle JET MOOC (massive open on-line course). The aim was to prepare a large number of developers all at the same time about enterprise JavaScript in the context of Oracle JET, i.e., Oracle's free and open source JavaScript platform. The MOOC is on-line, self paced, three weeks, and focused on 10 YouTube clips per week for three weeks, with many homework tasks, quizzes, and a certificate of completion at the end. We ran the second session after JavaOne/OpenWorld and have started the third session today. In the process, thousands of developers have been introducing themselves to Oracle JET.

Since the time when we put the MOOC together in August, quite a few changes have taken place and we've tried to update some of the parts of the MOOC as a result. If we were to be really thorough about it, we'd need to re-record absolutely every part, which is not really doable. So, here's an overview of all the changes and where parts of the MOOC are impacted.

  • Oracle JET Releases. Oracle JET 2.1.0 and Oracle JET 2.2.0. When we put the MOOC together, Oracle JET was at version 2.0.2. In the meantime, both 2.1.0 and 2.2.0 have been released. Read about 2.1.0 here and about 2.2.0 here. To ensure that the latest version of Oracle JET is always downloaded via "bower.json", we've changed the hardcode "2.0.2" in the GitHub samples to "latest", which will mean that in some cases you'll see different libraries and different versions of libraries in the YouTube clips than you'll see in your own code when working with Oracle JET templates.

  • Composite Component Architecture. The biggest impact of the above releases on the MOOC is the introduction of the Composite Component Architecture introduced in Oracle JET 2.1.0. Read about there here in the Oracle JET Cookbook. That topic was already mentioned in the MOOC, in Lesson 3, Part 1, where we look at integration with 3rd party components. However, the code sample for that part has been updated to include all the code samples from the Cookbook dealing with composite components. Go here to look at that code sample.

  • Oracle JET Templates. A big impact on the MOOC is that the "Oracle JET QuickStart Basic" wizard in NetBeans IDE now uses the "navdrawer" template. Read about that here. Some parts of the MOOC have been updated so that, especially at the start of the MOOC, you're not confused about the difference in the code you'll see being generated when you work through the tasks and the code you'll see in the YouTube clips. In Lesson 1, part 1, 7, 8, and 9 have all been reworked a bit, so that you see "navdrawer" code in the YouTube clips, in most cases. However, the code on GitHub continues to use the earlier templates and so on, so that, if you want to have the old structure and so on, in case you want that for reference or to understand something you're seeing in the YouTube clips, just use the code in the GitHub repos.

  • NetBeans IDE 8.2. NetBeans IDE itself has seen a new release since the initial release of the MOOC. In most of the MOOC, NetBeans IDE 8.1 is used, though in some of the updated parts, the latest release, which is NetBeans IDE 8.2 is used. The only difference is that in NetBeans IDE 8.2, you do NOT need to install the Oracle JET Support plugin, since that is now a standard part of NetBeans IDE. If you are using NetBeans IDE 8.2, do NOT go to the Plugin Manager and do NOT search for the Oracle JET Support plugin. Instead, simply use the "Oracle JET QuickStart Basic" template in "Samples | HTML5/JavaScript", which you will immediately find to be available.

  • Hybrid Oracle JET Generator for NetBeans IDE. The generator in NetBeans IDE for hybrid mobile applications, which is used in Lesson 2, Part 10, has been rewritten. That part of the MOOC will be updated during this week. Read about the changed generator here.

  • Samples on GitHub. There are several new and updated samples in the Oracle JET MOOC GitHub repository. For example, Part-001 now contains all the code shown in the related YouTube clip, Part-012 contains a lot more data visualization samples, including usage of ojThematicMap, Part-014 contains the complete MovieFactory sample, Part-021 contains all the composite components from the Oracle JET Cookbook, and Part-022 includes samples for integrating with the Application Container Cloud.
Some other parts of the Oracle JET MOOC may be changed/updated during the coming weeks, though the above points are the main areas where the differences lie between the original MOOC as published in August and the current status of Oracle JET and the MOOC itself.

Sunday Nov 13, 2016

Understanding the Enterprise JavaScript Landscape

Here's a recording (go to it directly on Vimeo here) of a session I did last week in Malmo, Sweden, at Oredev, all about the relevance of the JavaScript ecosystem for modern enterprise applications.

Get started with Oracle JET, i.e., Oracle's JavaScript enterprise platform, for free in a free three week on-line course here.

Thursday Nov 10, 2016

Understanding Oracle's JavaScript Platform

Here's a recording (go to it directly on Vimeo here) of a session I did yesterday here in Malmo, Sweden, at Oredev, all about the requirements for enterprise JavaScript and Oracle's free and open source solutions for this space.

Get started with all of this yourself for free in a free three week on-line course here.

Tuesday Nov 08, 2016

Conversations with Cab Drivers

Malmo, Sweden, November 2016

San Francisco, USA, October 2016

Monday Nov 07, 2016

Join NetBeans on Slack: https://netbeans.signup.team

One of the coolest recent developments in the NetBeans ecosystem is the establishment of the NetBeans Slack channel. We've only got this going over the past few weeks and there's a few hundred already registered and active.

What's the big deal and what's so great about Slack? Well, to me, and to how I'm using it, is that I see it as a modernized version of IRC, with the benefit of direct and quick interaction, e.g., I was holding off on publishing the new release of the One Click Open Sesame plugin because I wasn't completely sure about what new features Chris and Benno had implemented and so I quickly wrote back and forth with Chris on Slack and very quickly had my questions cleared up, rather than e-mailing back and forth for a week or two before getting the story straight.

So, want quick answers to your questions, want to resolve something without too much hassle? Join the NetBeans Slack channels and, of course, the more that join the more useful it will be since there'll be more knowledge going around.

Go here to get started, i.e., simply enter your e-mail address and you're good to go:

https://netbeans.signup.team/

And this is what the UI looks like, for me: 

Nice and neat and efficient. Thanks Wade and Chris and others for working on this and making this already a big success with the potential for much more! 

Saturday Nov 05, 2016

No More Double-Clicking To Open Files In NetBeans!

Probably to most NetBeans users, the need to double-click a file to open it has become part of your DNA.

However, consider the thought of not needing to double-click anymore. Simply select a file and it opens. That's what the "One Click Open Sesame" plugin aims to achieve for you:

http://plugins.netbeans.org/plugin/53723/one-click-open-sesame

The project was started some time ago here:

https://github.com/GeertjanWielenga/OneClickOpenSesame

Chris Lenz (@Chrizzly42) and Benno Markiewicz (@benM4) in Leipzig worked on it quite a bit over the past weeks and now usability has improved significantly:

  • The opened file does not get the focus anymore. Instead, focus stays back in the view where the click came from (Projects window, Files window, or Favorites window). This gives you the benefit that you can navigate through your view with your arrow keys and the focus will not change to the file that opens.

  • A fixed delay is added, of about 400ms, while in the next version the aim is to make it configurable, so that you can navigate through the view with your arrow keys and files don't open instantly and only after the specified delay.

  • An open document is reused while navigating through the view. If you set the focus to an open document and go back to the view, a new document will be created.

Awesome and I am using this constantly now. Well, since yesterday when I tried it out, and it's really nice. If you encounter any issues, go to the GitHub location above and report them!

Many thanks to Benno and Chris!

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« January 2017
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    
       
Today