Getting Started With DI in Angular 2

One of the core features of Angular 2 is dependency injection. This post serves as an introduction to using DI in Angular 2 apps.

Hierarchical DI

Angular 2 uses a hierarchical system for managing injectable objects. For developers this means that the choice of having a new instance or a previously created one is up to the consumer of the injectable. Let’s see how this works. Consider the following example of a single component and a single service (service definition not shown):

@Component({
    selector: 'parent-component'
    bindings: [MyUtilsService]
})
@View({
    template: '<h1>Hello World</h1>'
})
class ParentComponent{
    constructor(myUtils: MyUtilsService) {
        console.log(myUtils.getMessage());
    }
}

In the above sample line 3 creates a binding to “MyUtilsService”. This informs Angular that ParentComponent needs a fresh injector to provide access to MyUtilsService. The reference to MyUtilsService on line 9 is the actual request to perform injection. At this point Angular will create a new instance of MyUtilsService which is available in ParentComponent’s constructor. Let’s add another piece.

@Component({
    selector: 'child-component-1',
})
@View({
    template: '<h2>Child 1 Content</h2>'
})
class ChildComponent1{
    constructor(myUtils: MyUtilsService) {
        //Same instance of myUtils as injected into ParentComponent
        console.log(myUtils.getMessage());
    }
}

@Component({
    selector: 'parent-component'
    bindings: [MyUtilsService]
})
@View({
    template: '<child-component-1></child-component-1>'
    directives: [ChildComponent1]
})
class ParentComponent{
    constructor(myUtils: MyUtilsService) {
        console.log(myUtils.getMessage());
    }
}

In this example ChildComponent1 is also referencing an injection of MyUtilsService. Since a binding was not specified for MyUtilsService on ChildComponent1 Angular injects the same instance that was created for the ParentComponent. But what if we wanted a new instance? Let’s say that ParentComponent manipulates the state of MyUtilsService in some way that makes its use undesirable in some additional child component. To achieve this a new instance would be needed instead of using the parent’s copy.

//ChildComponent1
@Component({
    ...
})

//ChildComponent2
@Component({
    selector: 'child-component-2'
    bindings: [MyUtilsService]
})
@View({
    template: '<h2>Child 2 Content</h2>'
})
class ChildComponent2{
    constructor(myUtils: MyUtilsService) {
        //This references a different instance of myUtils from ParentComponent and ChildComponent1
        console.log(myUtils.getMessage());
    }
}
@Component({
    selector: 'parent-component'
    bindings: [MyUtilsService]
})
@View({
    template: '<child-component-1></child-component-1><child-component-2></child-component-2>'
    directives: [ChildComponent1, ChildComponent2]
})
class ParentComponent{
    constructor(myUtils: MyUtilsService) {
        console.log(myUtils.getMessage());
    }
}

Now a new instance of the MyUtilsService is requested on line 9 by creating a child injector. As a result, ChildComponent2’s constructor will be supplied with a different instance than was injected into the ParentComponent. Lets add one more layer and assume that ChildComponent2 is the only component in this hierarchy in need of a separate instance of MyUtilsService. ChildComponent2’s child wants to inject the same instance that was created for and injected into ParentComponent. One may assume the following approach can be taken:

//ChildComponent1
@Component({
    ...
})

//ChildComponent2
@Component({
    selector: 'child-component-2'
    bindings: [MyUtilsService]
})
@View({
    template: '<grandchild-component></grandchild-component>'
    directives: [GrandchildComponent]
}

//GrandchildComponent
@Component({
    selector: 'grandchild-component'
    bindings: [MyUtilsService]
})
@View({
    template: '<h3>Grandchild Content</h3>'
})
class GrandchildComponent{
    constructor(myUtils: MyUtilsService) {
        //This will look for and find the instance of MyUtilsService created by ChildComponent2 
        console.log(myUtils.getMessage());
    }
}

//ParentComponent
@Component({
    ...
}

However, the GrandChildComponent is receiving a third instance of MyUtilsService. This is also not ideal. To correct this and achieve the desired result let’s revisit ChildComponent2 and make a few small adjustments.

//ChildComponent1
@Component({
    ...
})

//ChildComponent2
@Component({
    selector: 'child-component-2'
    viewBindings: [MyUtilsService]
})
@View({
    template: '<grandchild-component></grandchild-component>'
    directives: [GrandchildComponent]
}

//GrandchildComponent
@Component({
    selector: 'grandchild-component'
})
@View({
    template: '<h3>Grandchild Content</h3>'
})
class GrandchildComponent{
    constructor(myUtils: MyUtilsService) {
        //This will look for and find the instance of MyUtilsService created by ChildComponent2 
        console.log(myUtils.getMessage());
    }
}

//ParentComponent
@Component({
    ...
}

View bindings allow for the creation of injectors that will create instances of an injectable that are only available to the component they are declared on. When MyUtilsService is injected into the GrandchildComponent the DI system will climb the hierarchy looking for an injector that is aware of MyUtilsService. The instance created by ChildComponent2 is not present in the hierarchy and instead the instance created on the ParentComponent is used.

App Level Instances

In addition to creating dependency bindings at the component level it is also possible to specify a set of top level, application dependencies. This is done using the bootstrap function to initialize the application. For example:

bootstrap(ParentComponent, [MyUtilsService])

Now any component of the application can inject the same instance of MyUtilsService or request a new copy using the binding approaches listed above.

Conclusion

There is great flexibility and power in the new dependency system. This article covers some of the basics that can be used to get your application off the ground but there is still plenty more to learn about how it works under the hood. For more information about how the Angular 2 dependency injection system works check out one of the following resources:
http://victorsavkin.com/post/102965317996/angular-2-bits-unified-dependency-injection
https://angular.io/docs/js/latest/api/di/

Angular Boot Camp, London UK

A number of companies in Europe have inquired about our Angular Boot Camp immersive Angular class, and a few threatened to send students across the ocean to attend one of our public classes. So when we saw that the 2015 European Angular conference (Angular Connect) is in easily-accessible London, we stepped in as a sponsor, and decided to offer Angular Boot Camp a few weeks thereafter, also in London.

After many weeks of paperwork delays, we have been issued the appropriate VAT number to do business there, and are pleased to announce our first offering of Angular Boot Camp across an ocean. The venue is a training facility in Wokingham, not far from Heathrow and easily accessible by train to downtown London. The dates are 3-5 November 2015, please see the site for more information and to register.

 

Early Start with Angular 2 – New Class Offering

We have been using Angular version 1.x for years now, and following version 2 development with great interest. Things have come together greatly over the last few months, after having somewhat wandered prior to that. We feel like now is the time to dig into version 2.

There been comments by the core Angular team also, which indicate that now is the time for developers to start previewing the new release.

For companies that want to dig in deep, we are now offering a brand-new “Early Start with Angular 2” class. The first scheduled date is in November in St. Louis, the second in early December in San Francisco.

(This does not replace our Angular Boot Camp class, it is firmly oriented toward immediate production use of Angular, and will remain so at least until version 2 ships as a final production form, and perhaps even thereafter for companies still using version 1.)

 

 

Learn TypeScript Now, Prepare for Angular 2.0

Like most organizations building client-side web applications (SPAs), here at Oasis Digital we have most commonly written code in plain old JavaScript, i.e. ES5, with help from linters, unit tests, etc. Lots and lots of code is out there, written in ES5 plus AngularJS and other frameworks.

There are obvious weaknesses to this approach, or rather gains that are set aside by not embracing any of the numerous newer innovations. We have dallied with CoffeeScript, worked on minor projects with ClojureScript, and so on. There are a lot of great languages out there beyond the JavaScript, but statistically JavaScript/ES5 is the winner.

(For a bit of “inside baseball”: we at Oasis Digital are generally quite willing to use unpopular, better tools. So why ES5? Because of our secondary line of business, training. When trying to train someone to use a new JavaScript library or framework, the most likely common ground we will have with them is baseline ES5.)

However, the era of mostly writing JavaScript code as it will execute in the browser is ending rapidly. Innovation of the JavaScript language is running far ahead of what browser vendors will keep up with; and even to the extent browser vendors keep up, large projects will inevitably have to support today’s browser versions (with the JavaScript version embedded therein) for years to come. A build process with compilation to JavaScript will be part of most SPA projects in the future.

So the question is, which post-JavaScript language to pick up? My personal favorite is ClojureScript, though I also see much merit in type-inference-equipped functional languages like Elm. For mass use though, I suspect the answer is simply a JavaScript successor. This is where it gets tricky. ES2015 (wow, I miss the shorter “ES6”) is the standard, and it will eventually land in all the major browsers. It will “win” in terms of mass adoption. Today is a good day to start moving your server side (NodeJS) code, test code, and as much as possible all of your JavaScript development to ES2015 or even a bit beyond – we’ve already done so. Babel works very well. Traceur works very well.

typescript2But there is at least one major exception. Angular 2.0 (which is coming soon, who knows how soon?) is built in TypeScript. You can go look right now, the source code in progress is sitting there in GitHub, and it consists mostly of TypeScript files. Most of the examples out there (including those we have published) use TypeScript. It will certainly be possible to write Angular 2 applications using plain JavaScript or any other language that compiles to JavaScript, but the first class citizen will be TypeScript.

Therefore, if you are using Angular today, and want to upgrade to Angular 2 someday, start learning TypeScript. Start using TypeScript. Start using TypeScript in some of your AngularJS 1.x work (we do).

Even aside from the obvious Angular motivation above, type systems in general (and TypeScript in particular) can be very useful. They enable a much more helpful editing/IDE experience. Numerous bugs can be caught at compile time. The incidence of runtime errors tends to be much lower. Unit testing can carry less of the load when using a typed language, so that whatever amount of effort you devote to unit testing, a greater share of it can go toward important functionality versus more trivial tests.

Here are resources to get started.

We will follow up later with examples of moving Angular 1.x code to TypeScript; we might even add a class offering to teach TypeScript for AngularJS developers. Stay tuned.

Angular 2: Working With Alphas

At the St. Louis Angular Lunch this month, I talked about working with the recent Angular 2 alpha versions. The rapid changes to the Angular framework have made it difficult to pin down its usage. As a result information explaining how one might build a full application has been mostly non-existent. The goal of this talk was to explain some of the big picture concepts of how Angular 2 applications are composed and provide live coded examples.  See the video embedded here, and transcript below.

 

Transcript

Here is the talk, transcribed to text. This is a lightly edited, draft transcription, so any errors are probably from that process.

Continue reading Angular 2: Working With Alphas

Preparing for Angular 2.0

Here at Oasis Digital, we have been excited about the possibilities for Angular 2.0 ever since its (somewhat contentious) public debut at the Fall 2014 European Angular conference. ripThat was the conference with the infamous “tombstone” slides, and the frequently misunderstood explanation by the Angular team members that they did not have a migration strategy for Angular 1-to-2 yet. Many commenters at the time seemed to misunderstand the yet part as some assertion that there would be no migration strategy at all. Fortunately, the agitation around that initial announcement has subdued, work has continued, progress is being made.

Though there has been quite a lot of progress on Angular 2, which we have been following (much of the development is being conducted in the open) our recommendation now is that if you don’t have a reason to work with A2 well before its release, you’re probably better off ignoring it a bit longer. As I write this in August 2015, the Angular 2 alpha versions are still rather rough, particularly in the experience of getting started.

But at Oasis Digital we do have a compelling reason to start using new versions before they are ready. We must do this so that we have significant experience when the time comes to start teaching our students (for our Angular class) how to use the new version, and even for the teaching we already include in the class about how to prepare for Angular 2.

One of our primary trainers, Paul Spears, has been leading the charge. Here are links to a couple of repositories he has published, showing a minimal project to get up and running with Angular 2, loaded using JSPM:

There is quite a lot to explain about what is going on in those repositories, here are a few of the most important bits.

We expect that many teams (perhaps most) will concurrently upgrade their development/build tools to the current generation of ES6/2015 module-centric build systems. The leader in the space appears to be JSPM, so we have chosen that for this work. It is also possible (and we will likely publish example this way in the future) to simply load Angular 2 along with its required dependencies using the script tags from downloaded files or from a CDN, of course.

The JSPM configuration may look quite alien compared to the familiarities of Grunt or Gulp. This is because of the above-mentioned module loader approach, and because JSPM already understands many things that must be explained to Grunt or Gulp by the user or a plugin.

These examples are set up for development, loading numerous separate tiny libraries using numerous HTTP requests; but JSPM and similar tools also have an excellent solution for production asset preparation, using essentially the same configuration information to package all of the JavaScript into a file or two.

These repositories show working examples as of right now, early August 2015. Angular 2 has been changing quite substantially from one alpha to the next. Moving up to the next version will likely require adjustments, as it has in previous versions. This is definitely alpha software.

The config.js file looks quite scary, but much of the contents there are generated by JSPM tooling. With some adjustment, it is possible to omit the hairiest block of information therein from source control, and instead treat it as a build artifact. As you look at the contents of that file, remember that you will not have to write the bulk of it.

 

Building a Configurator in Angular

Introduction

Modl Buildr is a configurator that allows users to select and configure a product of choice. It was inspired by a desktop configurator application and the question, “How can this problem be solved better in the browser?.”

As with many of our projects, we used AngularJS. Built as a framework for enhancing and augmenting the HTML language, Angular provides developers with a toolset supporting web applications consisting of dynamic, data driven content. Angular’s primary components include services for the isolation of business logic, routing for application architecture, controllers for marshaling data and directives for concise templates and view. Modl Buildr is created on these four core concepts.

We introduced Modl Buildr in a previous blog post.

If you prefer a video exclamation to text, the video below explains how it works in considerable detail.

For text, read on.

Routing

Client side routing is needed in most non-trivial Angular applications. The router allows users to navigate between features of the application without the need for additional server round-trips. When establishing the routes of the application Modl Buildr takes advantage of the syntax and creates a declarative road map of the application’s “pages”. The state declarations that are added highlight what routes are available and their associated models, views and controllers. By utilizing the resolve mechanism it is immediately clear what pieces of data are needed in order for any given route to function properly. This also removes the need for the controller to communicate with an API service or contain promise handling boilerplate.

Controllers and Services

Connecting the models to the view are various combinations of controllers and services. The router takes advantage of custom services to allow the creation of clean, simple and maintainable controllers. Consider the following code used to connect the landing page’s view to its model.

Controller:

(function () {
   'use strict';
   angular.module('app.home', [])
       .controller('HomeCtrl', function ($state, featuredProducts, popularProducts, productDataService) {
           var hctrl = this;
           hctrl.featured = featuredProducts;
           hctrl.popular = popularProducts;
           hctrl.selectProduct = selectProduct;

           //Prefetch for next route in navigation
           productDataService.getProductList();

           function selectProduct(selectedProduct) {
               $state.go('configure', {productId: selectedProduct.qsBaseID});
           }
       });
}());

Services:

that.getFeaturedList = function () {
   return that.getProductList().then(function (list) {
       return _.where(list, { Featured: true });
   });
};

that.getPopularList = function () {
   return that.getProductList().then(function (list) {
       return _.where(list, {Popular: true});
   });
};

The code responsible for obtaining and shaping the data is isolated nicely in a service, consumed by the router, and made available to the controller. Meanwhile, the controller simply passes the data to the view. This MVVM (MVC, MVW*) pattern is seen throughout the application.

Not all of the controllers and services are this simple. Some data bindings require constant updating in the form functions. For example, as a user configures a product there is a significant amount of calculation that occurs to determine if the product’s configuration is still valid. The result of this calculation is bound to the view for the user to see. Best practices encourage a clean separation of controllers and services while allowing the service to take responsibility for complex computation. The following code snippet demonstrates how Modl Buildr achieves this separation while maintaining two way data binding.

(function () {
   'use strict';
   angular.module('app.configure')
       .controller('ConfigureCtrl', function ($scope, $stateParams, $state,
                    productDataService, productStateService,appStateService) {
           var confCtrl = this;

           //the result of execution valid changes with every user input
           confCtrl.valid = valid;
           confCtrl.reset = reset;
           confCtrl.goToSummary = goToSummary;
           confCtrl.optionDisplay = optionDisplay;

           //Guard against extra API calls by only updating when the user’s selections have changed
           $scope.$watchCollection(function () {
               return confCtrl.selections;
           }, function (n, o) {
               if (n && n._seriesId) {
                  productDataService.getValidity(n).then(function () {
                       updateAll();
                   });
               }
           });

           function goToSummary() {
               var modelNumber = productStateService.productOptions.BaseLabel;
               modelNumber += _.map(productStateService.levelsToBuildModelNumber(), function (level) {
                   return productStateService.selections[level.Tag];
               }).join('');
               $state.go("summary", {productId: productStateService.productOptions.qsBaseID, number: modelNumber});
           }

           //This is called after every change to the user options
           function updateAll() {
               confCtrl.levels = productStateService.levelsToConfigure();
               confCtrl.modelDisplayOptions = productStateService.levelsToBuildModelNumber();
               confCtrl.valid = productStateService.valid;
               confCtrl.selections = productStateService.selections;
               confCtrl.productInfo = productStateService.productOptions;
           }
       });
}());

In the example above productInfo (the model number) and selections (the user’s choice of options) are bound to the view. The data in productInfo is a result of a function whose input is the selections. This approach not only provides a simple set of bindings, but also matches the application’s primary use case perfectly. The primary use case of the application is to select from a set of options and generate the corresponding model number. The challenge with this solution is that the server acts as a block box while performing the calculation. Fortunately the binding function is designed in such a way that it doesn’t matter where the complex calculation takes place or what it does. As the selections are updated the controller makes a service call and updates the bindings based upon the updated data that’s returned. The services handle the question of what to do and isolates the controller from any complexities or potential changes to this process.

Directives

There are several elements that appear on multiple screens of the application. These include simple pieces of functionality such as a hover text explaining why a button is disabled to custom widgets such as the product tiles. While controllers and services are great for laying out the big picture. Directives shine when used to create reusable and named components.

Modl Buildr contains a custom product tile directive. A reusable tile with a card-like appearance is created by combining a bootstrap panel, an image and a styled definition list. This tile is used to present products to the user. By specifying a few custom properties the same tile directive can be used across multiple situations.

Jade Template:

div.panel.panel-default.products-container(ng-click="click()",
   ng-class="{'product-tile': configure==='false', 'configure-tile': configure==='true'}")
   div.panel-heading
       | {{product.BaseLabel}}
       i.fa.fa-2x.fa-star.pull-right.featured(ng-show="product.Featured")
   div.panel-body.product-details
       img(ng-src="{{product.Image}}")
       hr
       dl.dl-horizontal.centered-block
           dt Name:
           dd {{product.BaseDesc}}
           dt Mfr:
           dd {{product.Manufacturer}}
           dt Item Type:
           dd {{product.ItemType}}
           dt Subtype:
           dd {{product.ItemSubType1}}

Javascript:

(function () {
   'use strict';
   angular.module('app.tile', [])
       .directive('descriptionTile', function () {
           return {
               restrict: 'E',
               templateUrl: "app/tile/descriptionTile.html",
               scope: {
                   product: '=info',
                   click: '&',
                   configure: '@'
               }
           };
       });
}());

With this definition and an ng-repeat these tiles are easily stamped out in a grid formation. This directive is also used on subsequent screens to display the product being configured.

Another helpful directive is the model number directive. The model number at the top of the configure and summary screens is generated by the users actions. Rather than complicate the main page controllers with the logic for displaying this interactive control a directive was created to isolate this concern. Now a model number can be displayed anywhere in the application by adding the following line of HTML (Jade) in the desired location:

model-number(product-name='{{cfg.productInfo.BaseLabel}}',
    current-selections='cfg.modelDisplayOptions',
    scroll-target='scroll-container')
// (the above is Jade, http://jade-lang.com/

Conclusions

Angular turned out to be a good fit for this application, yielding a working solution with a modest amount of code. Moreover, the application works quite nicely in a browser, at least as nicely as the native desktop application we were inspired by. The browser environment in 2015 is completely suitable for complex rules-based configurators.

 

 

Modl Buildr – A Rules Based Configurator Demo

Introduction

Modl Buildr is a demo application we created at Oasis Digital, a rules-based “configurator”. Its inspiration comes from older desktop application configurators. Modl Buildr can be used to generate model numbers for highly customizable products. A user can select a product, choose from a set of options for that product, review the final product and request a quote. This article explains the details of this process and highlights some key features.

For this demo application, we picked an example of a product with lots of options – hospital beds. All of the data used for this demo is openly available on the Internet; it is not from any customer project. (Our customers’ real information is all hidden behind firewalls and NDAs…)

Choosing a product

Users can select a product from a short list of common products, or by searching a catalog. The common products are shown first:

image05

Should the user choose to browse the product catalog, they see each product presented as a “tile” containing an image of the product and any additional spec information.

image04

Adjacent controls provide the ability to filter through the catalog. This is done by typing a product’s name or choosing one of several product categories. This was designed to resemble many other online marketplaces to create a familiar experiences for first time users.

As the user interacts with the filters the catalog responds immediately by adding or removing the products that fit the user’s criteria. The results respond to the user’s input without the need for the user to request an update. This type of workflow greatly speeds up the process of identifying the desired product and moves them forward in the process quickly.

image03

For users desiring a more compact view of the data there is also a grid view that displays the product information in a dense format. The grid view behaves in the same way as the tile view when interacting with the filtering tool. Once a user clicks on a product they are taken to the configuration page to set the product feature options.

image00

Configuration

The configuration page contains a display of the model number associated with the selected product. The display updates automatically to reflect the changes from interacting with the product options.

image02

A user configures the model by scrolling through the products feature list and selecting various options. As options are selected additional features will be added and removed automatically. If a user’s selection becomes invalid at any point that option will appear in red with an icon indicating that a conflict has occurred. The corresponding component in the model number will also turn red. The user can click on this portion of the model number and the list of features will automatically scroll to the problematic feature allowing the user to update their selection. Once a valid model number is configured the user can click on the “next” button to navigate to the review screen before requesting a quote.

image01

The rules that determine the validity of a product are not “hard-wired” into the application. Instead they are entered by the application administrator and executed on the fly. Examples include, “There are no options for TV controls unless the electric option has been selected” or “Choosing a manually positioned bed invalidates the electric footrest option.” These English phrases can be easily into rules and are associated with a product. These rules are then used by the configuration page to guide the user towards generating a product that meets their needs and the suppliers capabilities.

Having selected and configured the product the user arrives at the summary page. The details of the product and the user’s customizations are displayed and they are presented with a simple contact form from which they can request a quote.

Conclusion

Once the user submits a quote the application demo reaches its end. But the usage for this platform could be extended in a number of directions. Modl Buildr could be extended to include an additional step for browsing and manipulating the components that go into manufacturing the final products at another level of detail. The application could be expanded to include sales information and trends. Additional features common to other marketplace applications could be added such as shopping carts, order history, billing information, etc… On the administrative side of the software additional screens could be added for the management of products, orders and other common administrative tasks.

Modl Buildr is a small example of the kind of business-centric software that we create every day. If you are interested in how it works we would love to show you more.

More about Modl Buildr:

 

 

Angular 2.0 Discussion – Angular lunch

At Oasis Digital we host a St. Louis Angular Lunch each month. Many months an outside speaker comes in (especially if anyone volunteers!), other months someone from Oasis Digital speaks. In July 2015 we did something a bit unusual, several of us sat around and just talked about our Angular 2.0 preparations for a while. Although quite informal, it was well received. See the video embedded here.

 

Preparation for Angular 2.0 can include a lot of things, here are a few of the most important which came up in the discussion:

  • Now is the time to learn/use TypeScript. (We have converted a large Angular project to TypeScript.)
  • Now is the time to learn/use ES6/2015. (We have converted a large set of Protractor tests to ES2015.)
  • Angular 2.0 uses native ES6/2015 modules – which already work today.
  • The new “component router” for Angular 2 is also intended to arrive as a backcourt in Angular 1.x; it is very different from both the old Angular router and the very popular angular-ui-router. Although much work remains to be done, it is possible to start learning it now.

One topic of lively discussion was guessing when Angular 2.0 might ship. No ship date has been released, but several of us in this discussion thought it could be problematic for the Angular community if another major US spring conference goes by without A2. Therefore one obvious guess: Angular 2.0 will ship, perhaps just as “beta”, approximately around the next spring Angular conference. No one present has any connection to the Angular team, so this is just an outside, educated guess.

Transcript

We have also transcribed the discussion to text, provided below. This is a rough, first-draft transcription, so any errors are probably from that process.

 

Continue reading Angular 2.0 Discussion – Angular lunch

Angular 2 Component Router

This month at the St. Louis Angular Lunch I spoke about Angular’s upcoming “component router”. Originally created for Angular 2 and to-be-back-ported to Angular 1.x, the component router serves as a replacement to the current routing options. While still too early to use in production it looks like a promising alternative. In this talk (video below) I outline where the component router stands and a brief example of how it can be used.

 

Transcript

Here is the talk, transcribed to text. This is a lightly edited, draft transcription, so any errors are probably from that process.

Continue reading Angular 2 Component Router

Automated User Acceptance Testing – Matt Follett – Angular Lunch

e2e-painThis month (May 2015) at the Angular Lunch we had a very special guest speaker. Matt Follett (currently working at Observable Networks) shared his extensive experience working with end-to-end testing of browser-based web applications, including Angular applications. Although Matt only briefly mentioned Protractor (the Angular specific wrapper around Selenium), nonetheless almost everything he said was highly relevant to protractor.

Matt did not pull any punches in describing the difficulties of this type of test, and his comments certainly match our experiences at Oasis Digital testing Angular applications using Protractor. Still, the payoff of this level of testing is so high that we find it generally worth the effort. Automated testing is a (the?) way to keep quality up and regressions away as an Angular application grows in complexity and size.

Perhaps the best part of Matt’s talk is toward the end, when he (gently) compares the various available hosted browser/selenium services.

Transcript

We have also transcribed the the talk to text, provided below. This is a rough, first-draft transcription, so any errors are probably in that process, rather than in Matt’s actual content!

 

Continue reading Automated User Acceptance Testing – Matt Follett – Angular Lunch

ng-conf Review Roundtable – Angular Lunch

Several members of the Oasis Digital team attended ng-conf in Salt Lake City recently. This month for the St. Louis Angular Lunch (April), we had a roundtable discussion of the conference and what we all learned at it. Here’s a video of the discussion:

Transcript

Here is the discussion, transcribed to text. This is a lightly edited, draft transcription, so any errors are probably from that process.

Continue reading ng-conf Review Roundtable – Angular Lunch