DailyJS

Enyo Tutorial: Part 2

Robert Kowalski

Subscribe

@dailyjs

Facebook

Google+

tutorials frameworks mobile enyo enyo-kowalski

Enyo Tutorial: Part 2

Posted by Robert Kowalski on .
Featured

tutorials frameworks mobile enyo enyo-kowalski

Enyo Tutorial: Part 2

Posted by Robert Kowalski on .

In my introduction to Enyo, I promised that Enyo is "very modularized, reusable, and encapsulated". Today we'll create a reusable component from our monolithic and minimalistic application by refactoring the tip calculator. Afterwards we will style the application to make it ready for app stores and the web.

As mentioned in the previous part of the tutorial, the Enyo style guide suggests using double quotes instead of single quotes. Enyo also uses tabs for indentation. Although I prefer two spaces and single quotes, I will follow these rules during this tutorial.

This tutorial builds on the previous part, which is available here:

Loading Mechanism

Enyo is using files called package.js to load dependencies. If you look into the folder source/, which contains the core of the application, then you'll find a file named package.js from the bootplate project. Everything in this file will be loaded when the application starts up. Let's create a file called with the filename calc.percent.js, and add calc.percent.js to the end of the package.js:

enyo.depends(  
  "$lib/layout",
  "$lib/onyx",
  "App.css",
  "App.js",
  "calc.percent.js"
);

Components

Component objects are using events to communicate with their parent kinds. As described in the first part, components can nest other components. It would be nice to split the app into a reusable percent-calculator kind which could be used in other projects.

Published Properties

The calc.percent.js file should look like the following example -- I'll explain it in detail below.

enyo.kind({  
  name: 'PercentCalculator',
  kind: enyo.Component,
  published: {
    sum: 0, //optional default values
    percent: 0
  },
  events: {
    onCalculated: ''
  },
  create: function() {
    this.inherited(arguments);
  },
  calculate: function() {
    var result;

    result = (this.sum * this.percent) / 100;

    this.doCalculated({percentValue: result});
  }
});

Like the previous kind, this component has a name: PercentCalculator. This time the kind is not a control - we have chosen a component with kind: enyo.Component.

The next lines are the published properties of our kind. They can -- but must not -- have a default value, and it's 0 in this example. Enyo automatically creates setters and getters for our exposed properties. We will use the setters from that pair later but in this file we access them with this.sum and this.percent.

I mentioned previously that components are communicating with events. This example registers onCalculated, which is exposed to the public. It can be triggered with this.doCalculated({percentValue: result}); in the calculate method. The results are communicated to the parent kind.

Refactoring and Integration

In order to use our kind we have to add the component to our first kind from the file App.js.

{ kind: "PercentCalculator", name: "percentCalculator", onCalculated: "updateControls" }

Every time the event calculated is fired the method updateControls is called. This method is just getting the value and setting the new value of the corresponding DOM node. Here is the snippet:

updateControls: function(inSource, inEvent) {  
  this.$.tipAmount.setContent(inEvent.percentValue);

  return true; // stop bubbling
}

Notice the result is available as a property of the second argument: inEvent.percentValue.

The app, however, is not working yet. We have to give the values from the input fields to the component so it's able to calculate and pass back the result. I deleted the old calculate method and introduced the method calculateWithComponent. Also, please don't forget to update the ontap handler of the button. Here is the method:

calculateWithComponent: function(inSource, inEvent) {  
  var sum = this.$.sumControl.hasNode().value;
  var percent = this.$.percentControl.hasNode().value;

  this.$.percentCalculator.setSum(sum);
  this.$.percentCalculator.setPercent(percent);

  this.$.percentCalculator.calculate();
}

As before, the kind is accessed with this.$ and its name. The automatically generated setters are used for the published properties, and afterwards calculate can be called on our kind. At this point the component is passing the calculated result back. There are also change-Handler available for changing properties, but we do not use them here.

Here is the updated kind in full:

enyo.kind({  
  name: "App",
  kind: enyo.Control,
  style: "",
  classes: "onyx",
  components: [
    {kind: "onyx.InputDecorator", components: [
      {kind: "onyx.Input", name: "sumControl", placeholder: "Enter sum"}
    ]},
    {kind: "onyx.InputDecorator", components: [
      {kind: "onyx.Input", name: "percentControl", placeholder: "Enter percent"}
    ]},
    {kind: "onyx.Button", content: "Calculate tip", ontap: "calculateWithComponent"},
    {tag: "div", name: "tipAmount"},
    {kind: "PercentCalculator", name: "percentCalculator", onCalculated: "updateControls"}
  ],
  create: function() {
    this.inherited(arguments);
  },
  updateControls: function(inSource, inEvent) {
    this.$.tipAmount.setContent(inEvent.percentValue);

    return true; // stop bubbling
  },
  calculateWithComponent: function(inSource, inEvent) {
    var sum = this.$.sumControl.hasNode().value;
    var percent = this.$.percentControl.hasNode().value;

    this.$.percentCalculator.setSum(sum);
    this.$.percentCalculator.setPercent(percent);

    this.$.percentCalculator.calculate();
  }
});

The commit is 8f931.

Styles

I reduced the styles in the App.css to a simple background-color: #c6c6c6;, and one CSS class:

.center {
  text-align: center;
}

Then I changed the kind in our App.js from the basic enyo.Control to the kind enyo.FittableRows. A basic control was a nice choice to show you the basics of Enyo and kinds, but we want to use a more complex one which is provided by the framework.

In commit 8bb19 I've added an onyx.Toolbar as the first child of the components block:

{kind: "onyx.Toolbar", class: "center", content: 'Tip calculator'},

This will display a bar across the top of the screen (or page), in a similar fashion to the UINavigationBar used in iOS applications. The end result looks something like this:

Enyo Tip Calc

Production Build

You can run deploy.sh in the tools/ folder to start a deploy. It will minify and merge the source files of the project. The result will be saved to deploy/, and can be used with Cordova or simply uploaded to a web server.

Conclusion

You should now have learned the core concepts of Enyo and built a small application. Here is a short summary:

Part 1

  • Concept of kinds
  • Controls, and how to use and when
  • Events
  • Getters and setters
  • Constructors and destructors

Part 2

  • Components
  • Loading mechanism
  • Published properties
  • More on getters and setters
  • Production builds

References