On Today's Experience Installing Ionic for Android Development (on Windows 8.1)

Miscellaneous No Comments »

This is one of those posts that's likely to become obsolete very quickly as the install process for Ionic changes, but if it helps someone else resolve the (minor) install issues I ran into today, then it's worth doing.

The installation instructions that start at http://ionicframework.com/docs/guide/installation.html are pretty good considering the number of technologies involved in getting up and running (npm, the Java JDK, the Android SDK, Cordova, etc.).  But as those technologies changes so does the install process, even if the change is slight.

The first issue I ran into occurred when I tried to run the "ionic start" command from the command line.  I got a two-part error message in the console.  The latter message, cast in red text, suggested that my version of Cordova was outdated:  not likely since I'd installed it 30 minutes ago.  The earlier message said "could not create work tree dir" and cited a nested folder under my user account folder called "plugman".  Fortunately, someone had posted the solution (the need to create the missing directory) in the Ionic forums:  http://forum.ionicframework.com/t/unable-to-add-plugins-perhaps-your-version-of-cordova-is-too-old/3807/10.

The next issue came up at the conclusion of the install process when I tried to run "ionic emulate android".  Again, the final error message wasn't that helpful; the earlier message stated that "abd" was not recognized as a command.  The reason that happened was because the instructions say to declare the ANDROID_HOME Path variable to point to the "tools" directory of the Android ADT bundle, but Google moved the adb executable from the "tools" directory to the "platform-tools" directory (they left a note in the tools directory about the move).  For Ionic to work you actually need pointers to both the "tools" and "platform-tools" directories in the path.

The last issue was particular to my machine.  I had a pre-existing Android Virtual Device (AVD) configuration from an earlier install of the Android Eclipse plugin, and when Ionic tried to use that AVD it complained that a kernel file was missing.  I ended up launching the AVD manager from the command line ("android avd") and using the "Repair" option to repair the AVD, and that apparently fixed the problem, and the emulator opened at its typical glacial pace.

 

Object Equivalency and Select Options in AngularJS ("Why Isn't the Correct Option Selected?")

AngularJS No Comments »

In my last blog post, I talked about the angular.equals() function in AngularJS and how it compares two JavaScript objects for equivalency based on the properties and property values of each object.  Angular provides that function because in JavaScript, object1 == object2 is only true if object1 and object2 are both pointers/references back to the same object in memory.

This default "equivalency by reference" can cause some counter-intuitive behavior at times.

Read more...

Determining if Data Has Changed in Your AngularJS-Powered Form

AngularJS 1 Comment »

So here's the scenario:  you've got a form enabled with AngularJS.  The form is populated with data from a data model object retrieved from a REST call.  You need to know at a certain point (perhaps at the end of every user action, or perhaps at the moment of submission) whether the form data is different from when it was originally retrieved.  How would you do that?

If you wrap your form elements within a set of HTML form tags and name the form, Angular automatically (via the ngFormController) monitors the overall state of the form and provides some status flags, one of which is the $dirty property.  Problem solved, right?  Well, not quite.

Read more...

Introducing validORM: A Development Tool for Creating ORM CFC And ValidateThis Files

AngularJS , CFML , ColdFusion 5 Comments »

In my previous post about relating different data constructs in AngularJS to each other via property names, I mentioned that I figured out that technique while working on an internal development tool.  This blog post is about that tool.

The AngularJS-powered validORM tool lets you design the ID and column properties of your ColdFusion/CFML ORM CFCs while at the same time creating a matching set of validation rules using the ValidateThis (VT) library (a great library for handling both client and server-side validation).

The first view of the tool is a menu view.  You can choose to generate an updated version of your CFC and VT rules file based on a previous session or create a new set of files from scratch.  Either choice takes you to the generator view.

The first two sections of the in the generator view are pretty obvious:  that's where you choose the name and database table for your ORM object and configue the ID property.

The third section, where you define your column properties and create your validation rules, is where AngularJS really comes into play.  The property drop-down selection, the form controls and the hover hints for each property attribute you add, and the validation rule options and parameters:  those are all AngularJS manifestations of JavaScript data constructs.  Using the "Add Attribute" button to add a property attibute simply adds a JavaScript object of that name to the dataset; the creation of the form elements on the page for that attribute is handled automatically by AngularJS based on the Angular directives in the HTML.  That's Angular's strength: driving page behavior purely through data manipulation. 

The data constructs created by your choice of property attributes and validation rules are separate from the JavaScript objects and arrays of objects that represent all of the attribute and rule options, but they reference each other via the attribute and rule key names.

The last two sections allow you to further define any ValidateThis conditions and contexts referenced in your column property rules.  When you're done, clicking the submission button will trigger the file generation process.  Your ORM and VT configuration data will be parsed by a CFC which will then generate three files in the output folder of the tool:

  • An ORM CFC written in script format.
  • A ValidateThis rules definition file matching that CFC written in JSON format.
  • A JSON-formatted snapshot of the configuration data, with a filename reflecting the name of the object and the timestamp when the file was generated.  Said file will then appear in the menu view of the tool.

Some caveats:  the tool only allows for one ID property, doesn't include absolutely every type of property attribute (just the majority of them), and it doesn't let you define ORM relationship properties.  And as my first foray with using AngularJS, I'm sure it violates one or two Angular best practices (if you're an Angular guru, feel free to chime in with any suggestions for improvement).

But it works and can provide a kickstart to creating any ORM files and ValidateThis rules for your projects.  It comes with an example "Employee" configuration set that you can play with and then delete once you start using the tool.

The tool is available for download (and modification) via GitHub:  https://github.com/bcswartz/validORM. I also created a short video of the tool in action and posted it on YouTube at: http://www.youtube.com/watch?v=-fnt_n65NWg

Quick AngularJS Tip: Relating User Input Data to Metadata

AngularJS , JavaScript , Web development 1 Comment »

I started learning AngularJS a few weeks back because I thought it would work well for an internal tool I was building (more on that in a later post).

Many AngularJS examples, including those in the current AngularJS tutorial (like this one), illustrate how to use the ng-repeat and ng-options directives using a typical Javascript array of objects.  So given such an array in the model:

$scope.plans= [
  {"name": "Basic", "cost": "$250.00"},
  {"name": "Deluxe","cost": "$325.00"},
  {"name": "Premium","cost": "$335.00"}    	
];

...you can output a list of the data like so:

<ul ng-repeat="plan in plans">
  <li>
    {{plan.name}}: {{plan.cost}}
  </li>
</ul>

But, as noted in the AngularJS API, you can also use ng-repeat and ng-options to loop through a set of properties/keys in an object, and that works even if each property references another object.  So you can accomplish the same thing with this model object:

$scope.plans= {
  "Basic": {"cost": "$250.00"},
  "Deluxe": {"cost":"$325.00"},
  "Premium": {"cost": "$335.00"}    	
};

...and this HTML:

<ul ng-repeat="(planKey,planObject) in plans">
  <li>
    {{planKey}}: {{planObject.cost}}
  </li>
</ul>

The advantage to using the latter technique comes into play when you want to relate something in the part of the model you want to preserve / process with a part of the model that provides metadata.

Taking the above examples a step further, say you wanted to create a short conference registration form. The user has to select a conference package, and you want to provide information about each package (what it entails and the cost) but you don't want that information to be part of the form submission. You can do this by having the user's conference selection pull the related data from the plan metadata.

So with the following AngularJS controller function:

function ConfReg($scope, $http) {
  $scope.reg= {};
  $scope.reg.plan= "Basic";
  
  $scope.plans= {
    "Basic": {
      "description": "Access to all first-run conference sessions on Thursday and Friday.",
      "cost": "$250.00"
    },
    "Deluxe": {
      "description": "Access to all first-run conference sessions on Thursday and Friday, access to repeat sessions on Saturday.  Complimentary breakfast included all three days.",
      "cost": "$325.00"
    },
    "Premium": {
      "description": "Access to all first-run conference sessions on Thursday and Friday, access to repeat sessions on Saturday.  Complimentary breakfast included all three days.  Also includes conference t-shirt and kazoo.",
      "cost": "$335.00"
    }

  };
}

...and the corresponding HTML:

<h3>Conference Registration</h3>
  <form name="regForm" id="regForm" ng-controller="ConfReg">
    <p>
      <label>First Name:</label>
      <input type="text" name="firstName" id="firstName" ng-model="reg.firstName" />
    </p>
			
    <p>
      <label class="control-label" for="lastName" id="lblLastName">Last Name:</label>   
      <input type="text" name="lastName" id="lastName" ng-model="reg.lastName" />
    </p>
				
    <p>
      <label class="control-label" for="plan" id="lblPlan">Conference plan:</label>   
      <select name="plan" id="plan" ng-model="reg.plan" ng-options="planName as planName for (planName,planObject) in plans"></select>
    </p>
    <div>
      <p>{{plans[reg.plan].description}}</p>
      <strong>Price:</strong> {{plans[reg.plan].cost}}
    </div>
				
</form>

...The user's selection of plan determines which plan object data is pulled from the "plans" part of the model for display in that div block, yet the data sent as the form submission (the "reg" object) only includes the plan name.

A (nicer) demo of this example can be seen here: http://www.thoughtdelimited.org/thoughts/demos/angularMetadata.