Archive

April 2015

Browsing

I recently ran into an issue where I have a fairly nested directive and within the directive itself has an input that requires a decorator type directive such as for validation. As far as the title of the blog post, I figure that with each Angular 1.x release (2 in the near future) it’s probably best to tag these posts accordingly since each version introduces new syntax, etc and might not work if you’re still on the earlier version.

The problem

I’ll be using TypeScript for my example. For simplification, let’s say that you have a directive that validates an input. The directive is called, "validateInputInner" and we would like to use this in another directive.

return <ng.IDirective>{
    restrict: 'A',
    require: 'ngModel',
    link: link
};

function link($scope, $element, $attrs, ctrl) {
    var validateInput = (inputValue)=> {

        // some validation logic goes here...
        ctrl.$setValidity('validateInputInner', isValid);

        return inputValue;
    };

    ctrl.$parsers.unshift(validateInput);
    ctrl.$formatters.push(validateInput);

    // Observe attribute change
    attrs.$observe('validateInputInner', (comparisonModel)=> {
        return validateInput(ctrl.$viewValue);
    });
}

From a normal usage, the directive can be simply be used as:

<input type="text" validate-input-inner="{{vm.someModel}}" />

It gets a little more complex when you embed the same directive within another directive such as.

<test-component data-ng-model="vm.someModel" validate-input-inner="vm.secondaryModel"></test-component>

The second directive called testComponent will be using the previous directive as part of the component’s validation. The code for the testComponent is below. Please note the placement of the validate-input-inner.

Solution

We would like to use the testComponent directive as a wrapper component that exposes a scope property that feeds into the validation directive. We also could have re-used the existing model but for this example, we’ll assume that the validate-input-inner needs to validate another model in addition to the model.

testComponent.$inject = ['$compile'];
function testComponent(
    $compile: ng.ICompileService): ng.IDirective {
    return <ng.IDirective>{
        restrict: 'E',
        replace: true,
        require: 'ngModel',
        scope: {
            model: '=ngModel',
            validateInputInner: '=?',
        },
        link: link,
        template: `<div>
            <input type="text" class="form-control" 
            data-ng-model="model" validate-input-inner="{{validateInputInner}}"  /></div>`
    };
    // more code...

You might assume that this will work "as is" since the testComponent is using the same approach as it was by itself, and the scope property gets funneled down the directive itself.

Surprisingly enough, it doesn’t. The validate-input-inner works by itself but it but becomes unaware when inside a template based directive. The validate-input-inner could have been re-written another way perhaps to use $watch as opposed to $observe but given the scenario that we’re in, one way that I found to make it work is to use a $watch insite the testComponent itself.

We will need to inject $compile which is an Angular way to dynamically compile a string into a usable DOM element. In our case, the input element is nested within a div which is why need a reference to it using jqLite.

function link($scope, $element, $attrs) {
    var $input = $element.children('input');

    $scope.$watch('validateInputInner',(val) => {
        $input.attr('validate-input-inner', val);
        $compile($input)($scope);
    });
}

I added $scope.$watch and call $compile to refresh the validateInputInner‘s state. Please keep in mind that this operation is DOM intensive and is not always the best solution. This is one way out of (I’m sure) hundreds of ways of solving this. I’ll be exploring more ways to solve this and expand on this scenario in the future.

In the mean time, if you have suggestions or other ways to solve this, please feel free to comment or contact me.

Getting started on Ionic actually isn’t a straight-forward process. While the technology being used is basic HTML, CSS and JavaScript, the underlying process still requires Android and/or iOS. I will focus on the Android piece but most of the information can easily translate to IOS.

This post assumes that Node JS and NPM are installed in your system. I’m also using Windows 8 so your file path may vary.

To get started with development on Ionic, there’s a few things that you will need which is composed of 3 main parts. The first part would be Apache Cordova itself which is a framework that allows you to use HTML, CSS and JavaScript to build the application. The advantage is, it gives you a standardized API to build on multiple mobile platforms (Android, iOS, etc) using a single code base.

The second part is the installation, or at least having the proper environment and/or SDK that the Cordova can communicate with. This part takes the longest and where there’s headache involved if you’re not familiar with the process. The third part is the tooling which uses a combination of command line (to serve, deploy, emulate, etc.) as well as the actual IDE to write the code with.

This blog post is not meant as a exhaustive guide as there’s tons of information involved. I will focus on the 3 main parts of the installation and will try to be as focused and straightforward as possible.

1. Ionic framework setup

To install Ionic and Cordova globally using NPM.

npm install ionic cordova -g

2. Environment setup

If you are developing in Android like I am, you will have to install a few things. First and foremost, you will need the Java SE Development Kit. The next step is to install the Android SDK. I chose to use the Android Studio which includes the tools+ the SDK. Next is to install WinAnt which is a Windows installer for Apache Ant. Apache Ant is a Java command line tool that will be used to build the *.apk file for deployment to an actual Android device.

After the installation, the Android environment variable will need to be added to the system path for easy access. This can be set in the control panel > system > advanced system settings > environment variables > path.

C:\Users\<User>\AppData\Local\Android\sdk\platform-tools

You will also need to add the Android package to build with. This can be done through the Android SDK Manager and by selecting and downloading the versions.

Alternative: Ionic Box

I won’t go into the details of using Ionic Box but it’s an alternative. Ionic Box is a lightweight ready-made environment to avoid the hassle of configuring Java and Android SDK altogether in a Windows environment. It requires VirtualBox and Vagrant to simulate an environment for building with Ionic and Cordova. The VirtualBox is a tool to create quick virtual machine environments and in conjuntion uses VirtualBox for the VM itself.

After you have downloaded Vagrant from GitHub, you can use the command prompt to get into that directory then type the following command to run, download and setup the environment. This will install a Ubuntu VM and configure it within VirtualBox itself. (note that this might take some time at first as this will download a few dependencies to run the environment)

3. Tooling and Ionic commands

To create a new app. Template options are blank, tabs (default) and sidemenu

ionic start <app name> <optional template name>

To configure the platform for Android (ios if you’re building for iOS)

ionic platform add android

To change the URL on where to serve up the environment

ionic address

Basic Ionic commands available

To test and make sure that everything has been installed properly as far as communicating with the emulator is concern (adb = Android Debug Bridge), open the command prompt and type

adb

To build. This step is required prior to emulating or running on actual device. This creates the *.apk files.

ionic build android 

Testing

The command for spinning up an Ionic server instance

ionic serve    

In addition, if you want to launch a side-by-side iOS and Android browser emulation

ionic serve --lab

There’s a project called Ripple Emulator which allows you to emulate on different devices via Chrome, you can install it via NPM, then run it.

npm install -g ripple-emulator
ripple emulate --path platforms/android/assets/www

To emulate in the Android environment and launch the app.

ionic emulate android

To run on an actual device (it will fallback to running on emulation mode if a device is not detected).

ionic run android

Tools

If you’re using Visual Studio as your IDE, there’s Visual Studio tools for Apache Cordova which has some built-in tools for debugging, emulating, creating new mobile project, etc. I also discovered the Telerik AppBuilder last week which I personally haven’t tried yet. I will have to do a trial and see if I find it beneficial to quickly build an app.

Lastly, if all you care about is just building the app and is OK with debugging in the browser, all you need is an IDE like Sublime or Webstorm.

On my next post, I will focus on the actual development in Ionic. I hope that you find this helpful and informative. Feel free to contact me for any questions.