Josh Bavari's Ramblings

tech babbles on Ruby, Javascript, Rails, Phonegap/Cordova, Grunt, and more

Using JSON Serializers in Sinatra

less than a 1 minute read

I ran into a quick little issue with serializing some of my Sequel models.

The official JSON serializer docs are great, I just wanted to shine more light on the issue.

If you’re using Sequel models, just throw in the quick line of plugin :json_serializer.

1
2
3
4
5
6
7
8
# Get our database connection
require_relative "./db"
module ScoreboardApi
  class Team < Sequel::Model(:team)
    plugin :json_serializer
    serialize_attributes :json, :name
  end
end

Then, you just use the Sinatra contrib gem to have it json serializer attach:

1
2
3
4
# Web framework
gem "sinatra", "1.4.6", require: "sinatra/base"
# Sinatra addons - JSON, Namespace
gem "sinatra-contrib", "1.4.6"

Set up your API routes and spit out JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
require "bundler"
require "sinatra/base"
require "sinatra/json"
require "sinatra/namespace"

require "./models/scoreboard"
require "./models/team"

Bundler.require

module ScoreboardApi
  class App < Sinatra::Application
    register Sinatra::Namespace
    configure do
      disable :method_override
      disable :static

      set :sessions,
          :httponly     => true,
          :secure       => production?,
          :expire_after => 31557600, # 1 year
          :secret       => ENV["SESSION_SECRET"]
    end

    use Rack::Deflater

    namespace "/api/v1" do
      get "/scores" do
        json :scoreboard => Scoreboard.all
      end

      get "/teams" do
        json :teams => Team.all
      end
    end
  end
end

That”s all folks!

Playing With Safari 9 Force Touch API

less than a 1 minute read

I just got the new Macbook Pro not too long ago and noticed they had this intimately named featured called Force Touch.

Force touch, as it sounds, lets you touch things more intimately. The gist is this – there are sensors on the new touch pad that let you determine how hard the touch pad is touched, and has some API into that.

I admit, the API is kinda just for fun since only Safari 9 and new Macbooks have the feature. Still, I wanted to play more with ES6 and create a little API wrapper to make it easier and let this feature name to be a little less creepy.

After a little googling, I found an awesome blog post by Joshua Kehn that detailed more about using Force touch. I wanted to make a quick wrapper around it to do some fun effects and animations.

The idea is – we’ll have an API called TheForce that we can attach handlers to for fun visual effects.

Joshua’s demo had a box that when tapped and applying pressure, padding would be increased. I took his gist and turned it into an ES6 module. (See the demo)

The API

I wrote it up last night in a quick hurry. The gist is this:

  • Attach to a DOM element
  • Apply a glow to the element based applied pressure to touchpad

Code to attach a button named you, and trigger it automatically:

1
2
3
var luke = TheForce.beWith('you').alter({'boxShadow');

<!-- luke.alter('boxShadow'); -->

Respect Yourself

less than a 1 minute read

I’m writing this post as a memoir for myself, a retrospect of sorts. I read Seth Godins blog about Unconscious consumption and that post inspired me to write this post.

In the last 3 years, amazing events have unfolded. I helped create a start up, RaiseMore. I moved to Boulder, Colorado. I got a job at Ionic. I met a strong, amazing, beautiful woman who is my girlfriend.

I trained jiu-jitsu 4-5 times a week, I kept working on my strength, and trying to inspire others to do the same. I was striving to always read self-help books, watching informational videos, TED talks, ignite talks, challenging and pushing myself, and helping others grow.

All these new and exciting things kept happening to me. Many times before, I’ve asked myself, ‘how did I get so lucky?’. Things just had a snowball effect and kept getting better and better!

I’d like to think what attracted all these amazing things into my life was from these advancements.

However, something happened during these last 4 months that really threw me in a rut. I developed a poor attitude. I started thinking I was a victim. I no longer work for the company that I had looked up to for so long.

As I sit here now and reflect on the last few months, I know I’ve made my fair share of mistakes. I take full responsibility for that. And due to some of those mistakes, I’m unemployed (and looking for opportunities!) and I know it’s my own fault.

I’d like to stop and take a minute to deep dive and retrospect on what happened. I know, deep in my heart, that it all changed when I stopped respecting myself and making my personal growth a priority.

I’m realizing that while all these good things were occurring, one thing remained constant – I put myself and my personal growth first.

I’d like to deep dive into what really happened, and discover the why.

Deep diving

Questions to ask:

  • What did you do right?
  • What did you do wrong?
  • What can you do better?

What did I do right?

In January, I was jumping head first into the Ionic CLI. I was familiar with Node.js, but wasn’t nearly at the level I wanted to be at. So I jumped head first into blogs, training courses, books, and more.

I learned a ton by failing forward, bouncing ideas off of others, and most importantly, maintaining a healthy work life balance.

In March, I came up with the crazy idea to make the Ionic CLI easier to consume by almost any user by just point/clicking. In my free time after working on the Ionic CLI, I started cranking out Ionic Lab – that would do just that.

It was so freeing to use my creative side and use my intuition, listening to myself as I craved to learn more about Node.js and Electron!

After demoing Ionic Lab to the Ionic team, they were convinced this was a tool that could open the door to more developers and really improve the tooling. Thus, I was instructed to work on it full time. Such a joy!

Then it hit, this thing had to ship. I had to really buckle down and work out the final kinks in integrating Cordova fully into Ionic Lab, which took me down rabbit holes into discovering more about Electron than I wanted to know, fixing stdio errors and things that occurred deep in Cordova library code.

Once we shipped out Ionic Lab in July, I was told to focus on Ionic 2. The rest of the team had been heads down working on the codebase since March, I was the new guy, so I had to really step it up and put in the time to learn Angular 2, TypeScript, ES6, Webpack, and all the other new ground to cover.

It was exciting once again to jump head first into learning and exploration. But something happened that I did not expect.. I became a cynic.

What did I do wrong?

I think it wasn’t until after July that things started to slow down and my personal happiness started to decline. I started working more hours (60 hours was the minimum). I stayed up late working most every night. I slept less. I started working out less (I gained 10-20 lbs). I started putting myself and my personal growth last.

I stopped calling my friends. I stopped reaching out to my support group as much. I wasn’t maintaining my happy upbeat attitude I’ve been told has been so inspiring.

I started putting work first. I started accepting others views of myself. I stopped valuing my work, my time, and my efforts to put that towards a company that at the end of the day, only wanted more and more. We all know what this leads to, burn out.

This all was boiling down to the AngularConnect conference, where we planned to unveil Ionic 2 to the European crowds. I was given a hefty task of learning all that was Ionic 2, adding cross platform functionality in Ionic 2, adjusting the Ionic CLI for v2, helping curate content for a workshop at the conference, as well as building the first Ionic v2 app, the Ionic conference app.

All this was going down and other life issues arise, as they do. My older (15y old) dog was getting worse by the day. My girlfriend was not happy that I was putting her second to work. My friends stopped calling me. My shoulder got injured. I lost confidence in my work because I was burning out.

Then, a personal goal I had set didn’t get delivered to a group of users I was really wanted to, the Windows Ionic CLI users.

This hurt. Failure when placed heavy, can hurt. It hurt even more when I was putting work first, and myself last.

Looking more hopefully at the situation..

What can I do better?

First off – be honest with myself. Tell others I need a helping hand when needed. Going forward, I will look out for myself better (we all know employers want employees that can look out for themselves).

Don’t accept others views of myself unless I first believe them!

Most importantly, respecting myself. I should always take the time to have a 1 on 1 with myself and really get a sense of where I’m at. If I need a break, use that vacation that we are so lucky to have!

We tend to forget that if we dont build ourselves up, the world surely wont. (Unless you are lucky enough to have awesome friends that stick through it thick and thin). Burnout happens when you don’t let your support structure help put out of the flame before you become a pile of ash.

So please, take this time to evaluate yourself and your needs. Be honest with yourself. Focus on caring for yourself. Be compassionate to yourself. Let yourself make mistakes, but learn from them.

Focus on the positive. Surround yourself with upbeat people, ditch the negativity, and remind yourself that your future is in your hands. Take it.

Don’t forget that the only difference between a victor and a victim, is their mindset.

Remember, there is no luck, only the work you put in and the effect you see afterwards.

Ionic 2.0 Generators - Services

less than a 1 minute read

This is the second post in a series covering the new Ionic Generators in Ionic 2.0. In the first post, we discussed generating pages, let’s focus now on generating some services to consume some JSON data via an http request.

Get the tools

Run this to get started:

Install Ionic CLI and start an Ionic application
1
2
3
npm install -g ionic@alpha
ionic start MyIonic2App tabs --v2
cd MyIonic2App

Generate the service

ionic g injectable MyDataService

You should see the service:

Run generate command
1
2
~/Development/testing/MyIonic2App$ ionic g injectable MyDataService
√ Create www/app/my-data-service/my-data-service.js

The basic blueprint of the generated service is as follows:

Generated Data Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import {Injectable} from 'angular2/angular2';
import {Http} from 'angular2/http';

@Injectable()
export class MyDataService {
  constructor(http: Http) {
    this.http = http;
    this.data = null;
  }

  retrieveData() {
    //Here, we're going to get a JSON data file, use the `map` call to parse json
    // and finally subscribe to the observable and set our data
    //to the value it provides once the http request is complete.
    this.http.get('path/to/data.json')
      .map(res => res.json())
      .subscribe(data => {
        this.data = data;
      }, error => {
        console.log('Error with http.get: ', error);
      });
  }
}

Wiring it in to be used

Adjust www/app/app.js to import the data service, as well as provide it for all of its components:

www/app/app.js
1
2
3
4
5
6
import {MyDataService} from './my-data-service/my-data-service';

@App({
  template: '<ion-nav [root]="root"></ion-nav>',
  providers: [Friends, MyDataService]
})

Use the service

We’ll use the tabs starter dashboard page to pull data.

Let’s modify www/app/dash/dash.ts – adding an import for MyDataService, adding MyDataService to the constructore as an injected dependency, and finally adding the call to retrieveData in the constructore method.

www/app/dash/dash.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Page, NavController, ViewController} from 'ionic/ionic';
import {MyDataService} from '../my-data-service/my-data-service';
import {About} from '../about/about';

@Page({
  templateUrl: 'app/dash/dash.html',
})
export class Dash {
  constructor(nav: NavController, view: ViewController, data: MyDataService) {
    this.nav = nav;
    this.view = view;
    data.retrieveData();
  }

  goToAboutPage() {
    this.nav.push(About);
  }

}

Additional information

If you’ve used Angular 1, you’re probably familiar with promises to return your data from http requests.

Under the hood of Angular 2 lies RxJs that builds on promises, focusing on being repeatable.

Enjoy!

Using Ionic 2.0 Generators

less than a 1 minute read

At the time of writing this, Ionic 2.0 is still in alpha.

Ionic 2.0 builds on a ton of new technologies, such as Angular v2, TypeScript (with decorators), and ES6. If you’ve never dabbled in these technologies, you can use the generators available in the ionic-cli to get ramped up quickly!

Getting started

First, install the alpha version of the Ionic CLI: npm install -g ionic@alpha, currently version 2.0.0-alpha.19.

Start an app with the tabs template: ionic start MyIonic2App tabs --v2.

Change directories and serve the app in the browser: cd MyIonic2App && ionic serve.

You’ll see, we’ve got a basic tabs starter now avilable at MyIonic2App directory.

Generating a few pages

Let’s say we want to link to a new page, ‘About’, from one of the tabs. First, let’s generate our page with this command: ionic generate page About. NOTE: You can also use the generate alias, ionic g.

You’ll see a few files added:

1
2
3
4
~/Development/testing/MyIonic2App$ ionic g page About
√ Create www/app/about/about.html
√ Create www/app/about/about.js
√ Create www/app/about/about.scss

Adding link on view to the About page

Let’s add the link to the main tab page in www/app/dash/dash.html, via the (click) handler on an anchor, like so:

1
2
3
4
5
6
7
8
<ion-card>
  <ion-card-header>
    Go to about page
  </ion-card-header>
  <ion-card-content>
    <button (click)="goToAboutPage()">About this</button>
  </ion-card-content>
</ion-card>

Navigating to the page

Modify the Dashboard TypeScript file (www/app/dash/dash.ts) to import our new about page, add the click event handler, and push the page on the nav controller, all like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import {Page, NavController} from 'ionic/ionic';
import {About} from '../about/about';

@Page({
  templateUrl: 'app/dash/dash.html',
})
export class Dash {
  constructor(nav: NavController, view: ViewController) {
    this.nav = nav;
    this.view = view;
  }

  goToAboutPage() {
    this.nav.push(About);
  }

}

Try it out!

Look in your browser, you should have an anchor available to click/tap that will then navigate you to the About page, fresh for you to get working!

Here’s a GIF of what it looks like:

I’d like to also note, Ionic 2 is much smoother than a GIF would allow.

Wiring up sass

If you want to use the custom sass styles on the about page, first wire in the about.scss page in your www/app/app.scss sass file, like so: @import 'about/about';.

A quick note on naming conventions

For Ionic 2.0, we’ve contributed to a naming convention of kabob-casing for file names (my-about-page.html) and css classes (.my-about-page), and using PascalCasing for JavaScript classes in ES6 / TypeScript (MyAboutPage).

Other generators

Check out all the generators available: ionic g --list

1
2
3
4
5
6
7
8
9
10
11
~/Development/testing/MyIonic2App$ ionic g --list
Available generators:
 * component
 * directive
 * injectable
 * page
 * page-login
 * page-sidemenu
 * page-signup
 * pipe
 * tabs

Final words

We hope you find the generators help you get started with ramping up quickly and building some awesome Ionic applications! Enjoy.

We’d love your feedback, drop us a line at Ionic v2 Github Issues.

Angular 2 and Ng-model

less than a 1 minute read

Angular 2 introduces ng-model from Angular 1 in a completely different manner. Due to this, I wanted to make a quick post on how to use Angular 2’s ng-model to build components that alert its parents app/component of changes.

I’m going to use the Ionic 2 conference app as an example.

In this post, we’ll look at the schedule page in the app and see how it uses the ion-search-bar to update its searchQuery to filter out sessions from the schedule when the user changes the search input.

The set up

On the schedule component, we set up the search query as a simple string, as such: this.searchQuery = '';.

Then in our schedule page template, we tell the ion-search-bar to use the ng-model directive and tell it to two-way bind using the schedule component’s searchQuery variable.

The template is like this:

1
<ion-search-bar [(ng-model)]="searchQuery" placeholder="Search"></ion-search-bar>

Now, in the search bar, we need to take that searchQuery as an ngModel, and ensure the search-bar has a value accessor implemented, so that we may tell the schedule component of when things change to update its shadow DOM if need be.

The ion-search-bar will take an ngControl as part of it’s injection, and sets up the value accessor to itself, like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
constructor(
  elementRef: ElementRef,
  config: Config,
  ngControl: NgControl,
  renderer: Renderer
) {
  super(elementRef, config);
  this.renderer = renderer;
  this.elementRef = elementRef;
  if(!ngControl) {
    // They don't want to do anything that works, so we won't do anything that breaks
    return;
  }

  this.ngControl = ngControl;
  this.ngControl.valueAccessor = this;
}

NOTE: ngModel extends the ngControl class in angular (source code). The valueAccessor is a ControlValueAccessor is an interface that provides certain methods, like so:

1
2
3
4
5
export interface ControlValueAccessor {
  writeValue(obj: any): void;
  registerOnChange(fn: any): void;
  registerOnTouched(fn: any): void;
}

The ControlValueAccessor gives us a method to write the new value, a method to register to listen to the changes, and the register on touched function to allow components to use.

Those are implemented in the search-bar, as seen here.

You can see that the writeValue method on search-bar updates it’s local value, so that it’s internal <input> element can update its value it shows. When that internal input is changed, it calls the inputChanged event on the search-bar, which alerts other components that it has changed, as well as updating its current value.

1
2
3
4
  inputChanged(event) {
    this.writeValue(event.target.value);
    this.onChange(event.target.value);
  }

Filtering out sessions

Since the onChange event is called, the schedule component will see this and cause re-evaluation on its searchQuery variable, and filters the code.

That makes our filtering method super easy, as seen here, copied below for convenience:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
getSessionsForTheDay() {
  if (!this.searchQuery || this.searchQuery.trim() == '') {
    return this.sessionsForTheDay;
  }
  var talks = [];
  this.sessionsForTheDay.forEach((session) => {
    var matched = session.talks.filter((v) => {
      if(v.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) >= 0) {
        return true;
      }
      return false;
    });
    if (matched.length > 0) {
      session.talks = matched;
      talks.push(session);
    }
  });
  return talks;
}

When the schedule component’s variable for searchQuery is updated, this method will be auto-magically re-evaluated, which causes the list to update.

Hope this helps you understand Angular 2 and ng-models better! Enjoy!

Windows and Webpack With TypeScript and Babel

less than a 1 minute read

I’ve recently been diving into the land of Webpack to handle all the heavy lifting of using Babel to compile my TypeScript and ES6 into ES5 JavaScript to be used in Ionic 2.

The current set up I’m working with involves having Webpack use the awesome-typescript-loader to load up TypeScript and compile the TypeScript files, as well as load up Babel and compile the ES6 JavaScript using Babel.

The set up

The file structure looks like this:

1
2
3
4
5
6
./
  ./www
    ./app
      ./components
        ./datepipe.js
        ./app.ts

This worked great on my Mac. However, one thing I ran into on my Windows machine was this particular error:

Cannot find module "./www/app/app.js"

Take a look at the webpack.config.js in the ionic-conference-app, with a portion of it below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* snipped */
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: "awesome-typescript-loader?doTypeCheck=false&useBabel=true&useWebpackText=true",
        include: /www\/app\//,
        exclude: /node_modules/
      },
      {
        test: /\.ts$/,
        loader: "awesome-typescript-loader",
        include: /www\/app\//,
        exclude: /node_modules/
       }
    ]
  },
/* snipped */

Webpack uses loaders to take the files and add them to the final build output. It knows where to get these files from the webpack config module loaders array, where each loader specifies the include paths, as per the webpack docs:

include: A condition that must be met

A condition may be a RegExp, a string containing the absolute path, a function(absPath): bool, or an array of one of these combined with “and”.

Take note of the include line we had at first: include: /www\/app\//,, line 7 and 13 in the pasted snipped above.

Sure this will work in a Unix based runtime. If you’re running on a Windows machine, these paths may be a problem. As it doesn’t understand the /. This tip came from Edward McLeod-Jones, who pointed out this issue.

You might want to try to make RegEx fun, by doing this:

1
include: /www(\/|\\)app(\/|\\)/,  // <--- Change the regex to support either type of folder separator`

However, since we’re doing Node.js, it provides APIs to help us out with cross-platform changes like this with the path module.

Do this instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var path = require('path');
var wwwPath = path.resolve(__dirname, 'www');
var outputPath = path.join(wwwPath, 'build', 'js');
var appPath = path.join(wwwPath, 'app');
var appJsPath = path.join(appPath, 'app.js');

/* snip */
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: "awesome-typescript-loader?doTypeCheck=false&useBabel=true&useWebpackText=true",
        include: [wwwPath],
        // include: /www(\/|\\)app(\/|\\)/,
        exclude: /node_modules/
      },
      {
        test: /\.ts$/,
        loader: "awesome-typescript-loader",
        // include: /www(\/|\\)app(\/|\\)/,
        include: [wwwPath],
        exclude: /node_modules/
       }
    ]
  },
/* snip */

Angular 2 Injectables

less than a 1 minute read

I’ve been fortunate enough to be working on Angular 2 while being on the Ionic team.

I really enjoyed Pascal Precht’s post about Dependency injection in Angular 2. One thing that I want to shed some more light on is how dependency injection works in an Angular 2 application using the @Injectable metadata thats passed for a class that’s to be injected.

Quick tip: take a quick look at the Angular 2 cheat sheet to see some more of these Angular 2 syntax and API.

The basics of Depdendency injection

The gist of it we need:

1) A class with @Injectable to tell angular 2 that its to be injected – DataService
2) A class with a constructor that accepts a type to be injected

A solid example, DataService marked as @Injectable that also needs Http to be injected for its use:

1
2
3
4
5
6
7
8
9
import {Injectable, bind} from 'angular2/core';
import {Http} from 'angular2/http';

@Injectable() /* This is #1 */
export class DataService {
  constructor(http: Http /* This is #2 */ ) {
    this.http = http;
  }
}

What we have in the example above is a class, DataService, that needs Http to do what it needs to be done.

An example scenario

Let’s say we have the following scenario, an angular 2 application with an app, a page for sessions, session details, speakers, and a data service that provides the data for those pages.

We’d want the app instance to instantiate the data service, then have a component schedule that can use the data service as provided by the app instance. From there, we’d have the session detail that also gets the schedule data from the data service.

The hierarchy would look like this:

1
2
3
4
5
6
7
8
          App
           |
  |.............|...............|
  |             |               |
   Schedule      Speakers     Session-detail
  |
  |
  Schedule-list

All of these components will need the instance of data service.

We’ll need:

  • A data serviced marked with @Injectable.
  • A schedule page
  • A schedule-list component
  • A speakers page

Say you have the following:

In www/app/service/data.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';

@Injectable()
export class DataService {
  constructor(http: Http) {
    this.http = http;
    this.data = null;
    console.log('DataService constructor');
  }

  retrieveData() {
    this.http.get('api/data/data.json')
    .map(res => res.json())
    .subscribe(data => {
      this.data = data;
    });
  }
}

We’d also have our Application object, www/app/app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import {App, Platform, StatusBar} from 'ionic/ionic';
import {DataService} from './service/data';
import {AboutPage} from './about/about';
import {MapPage} from './map/map';
import {SchedulePage} from './schedule/schedule';
import {SpeakersPage} from './speakers/speakers';

@App({
  templateUrl: 'app/app.html',
  providers: [DataService]
  /* 
    Here we're saying, please include an instance of 
    DataService for all my children components,
    in this case being sessions, speakers, 
    and session detail.
  */
})
class ConferenceApp {
  constructor(platform: Platform, data: DataService) {
    data.retrieveData();
  }
}

Then we’d have our speakers component, www/app/speakers/speakers.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Page} from 'ionic/ionic';
import {DataService} from '../service/data';
import {SpeakerDetailPage} from '../speaker-detail/speaker-detail';
import {SessionDetailPage} from '../session-detail/session-detail';

@Page({
  templateUrl: 'app/speakers/speakers.html'
})
export class SpeakersPage {
  constructor(nav: NavController, data: DataService) {
    this.nav = nav;
    this.speakers = null;
    this.dataService = data;
  }

  onInit() {
    this.speakers = this.dataService.getSchedule();
  }
}

Now I want to point something out above. If we had the SpeakersPage to also have a providers: [DataService], we are telling angular 2 to create an instance of DataService to make it available for SpeakersPage’s children, instead of using the DataService that ConferenceApp provided.

I repeat, we’d have two instances of DataService with this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import {Page} from 'ionic/ionic';
import {DataService} from '../service/data';
import {SpeakerDetailPage} from '../speaker-detail/speaker-detail';
import {SessionDetailPage} from '../session-detail/session-detail';

@Page({
  templateUrl: 'app/speakers/speakers.html',
  providers: [DataService]
  // This will instantiate a new DataService for its children
})
export class SpeakersPage {
  constructor(nav: NavController, data: DataService) {
    this.nav = nav;
    this.speakers = null;
    this.dataService = data;
  }

  onInit() {
    this.speakers = this.dataService.getSchedule();
  }
}

This is very important. If we had a console.log statement in the DataService constructor, we’d see it run twice with the providers: [DataService] being specified.

One thing to remember, if at the root application you specify a provider, it will be available to all children components that it contains, unless you specify a providers that then will initialize a new instance of that provided class.

I hope this post helps clear up dependency injection in Angular 2. Now get back to coding!

Npm Production Checklist

less than a 1 minute read

I recently read this post by RisingStack over the Node.js Production Checklist.

Since this was aimed at releasing node.js applications for the most part, I wanted to touch base on a ‘production checklist’ on releasing a npm module.

The npm-developers guide does a great job of explaining much you need to know about publishing your npm module.

This post will mainly serve as a work in progress document to supplement the developers guide, as well as serving as a way to help me continue to keep learning best practices all the time.

Some of the methods I use in my npm release schedule are as follows:

  1. Keeping files out of your package
  2. Locking versions
  3. Continuous integration (tests, install, etc)
  4. Alpha/beta pushes (user testing)
  5. npm-check-updates

Keeping files out of your package

We want our users to only have to download what they need to use your module. This may mean removing any files that are not beneficial for the user. Much like .gitignore for files being checked into git, npm has .npmignore.

Straight from npm docs:

Use a .npmignore file to keep stuff out of your package. If there’s no .npmignore file, but there is a .gitignore file, then npm will ignore the stuff matched by the .gitignore file. If you want to include something that is excluded by your .gitignore file, you can create an empty .npmignore file to override it. Like git, npm looks for .npmignore and .gitignore files in all subdirectories of your package, not only the root directory.

We can also use a command in the npm CLI called prune.

Again, straight from the npm documentation:

This command removes “extraneous” packages. If a package name is provided, then only packages matching one of the supplied names are removed. Extraneous packages are packages that are not listed on the parent package’s dependencies list. If the —production flag is specified or the NODE_ENV environment variable is set to production, this command will remove the packages specified in your devDependencies. Setting —production=false will negate NODE_ENV being set to production.

This is a great way to ensure you dont have any extra packages you might have installed via npm install and either forgot to pass the --save flag or were just testing functionality.

You can also use this command inline with the --production flag when installing node modules to avoid having the extra cruft of the devDependencies, which are mainly used for developing the modules (think testing, etc).

Locking versions

Theres a few methods to use with npm to lock down your versions. You can use the npm shrinkwrap command or specify node modules to bundle in your module with bundleDependencies.

The strategy is, you can either pack those in with your tarball as they are in your node_modules folder, or you can lock down those exact versions by storing the exact tarball to download when the user npm installs your module.

Edit: I’ve just learned on a new method to package bundle up node modules by using the bundledDependencies attribute in your projects package.json file.

Bundling

By specifying bundleDependencies in your package.json, you are telling npm on its publishing process to include those modules listed in the tarball it creates and pushes up to the npm registry. For example, if you go to any npm repo and download the tarball in the url there, unzip it and open it, you’ll see those exact node modules in them as you’ve got in your own node_modules folder.

This effectively locks down your modules versions, at the cost of a larger tarball size the user will download intially. Any modules that are not bundled, will then be downloaded and installed after the tarball is downloaded.

Shrinkwrapping

If you’ve ever done any Rails, you’ve probably seen the gemfile.lock. The equivalent in Node land is the npm-shrinkwrap.json file.

What the npm shrinkwrap command does is looks at your node_modules folder and looks at the packages installed there and compares those to what is in your package.json file.

Straight from npm documentation:

The shrinkwrap command has locked down the dependencies based on what’s currently installed in node_modules. The installation behavior is changed to:

The module tree described by the shrinkwrap is reproduced. This means reproducing the structure described in the file, using the specific files referenced in “resolved” if available, falling back to normal package resolution using “version” if one isn’t.

The tree is walked and any missing dependencies are installed in the usual fasion.

A huge misconception is that shrinkwrap locks down what versions are in your package.json file. This is incorrect. Just to reiterate, it will look in your node_modules and use that compared to your package.json file.

Edit: Another thing to note, if you take a look in your npm-shrinkwrap.json, you’ll see the exact URL for that versions tarball to download, which npm cli will use to grab without taking a peep at anything else. This may cause issues for some users, as stated by Forrest on this Ionic CLI issue:

Due to how shrinkwrap works, it ends up bypassing the npm cache and redownloading every package mentioned in the shrinkwrap each time npm install is run. If users have any issues with their network, or something gets sticky with npm’s CDN, the whole install can fail, forcing them to start over again.

Heed this warning, friends.

Testing

Try to avoid the old addage, ‘it worked on my machine’, by having a CI server pull your package, run some tests, and even sometimes install the module to make sure it works on other machines besides your own.

I really enjoy using CircleCI, as it is free for open source projects! You can normally specify a config file that says what version of node/npm to use and the rest is automated.

Alpha/beta pushes

I covered this in a previous article about using npm tags.

The idea is, before publishing your version to npm, try doing a alpha/beta push first (to save the version in npm you’re about to publish, since there can only be one version) to let users npm install the module to run some tests before commiting that to the latest tag for everyone to install.

npm Check Updates

There’s a nice module that looks at your package.json file and looks to see the latest tags on the modules you specify in your dependencies.

It will give you some heads up if there are latest packages, so you can update if you have too many out of date packages.

Hope this helps!

References:

Using Npm Tags

less than a 1 minute read

If you do any kind of deployments to npm, you’ll probably find learning more about npm tags very helpful.

Just as git tags mark commits in your repository history, npm tags mark a specific version in the npm registry of your published versions.

If you didn’t know, npm manages a tag ‘latest’ that points to the last version you put out with npm publish.

The syntax to publish a new version and tag that version with the name beta, use: npm publish --tag beta.

Installing from tags

To have your users install your node module, they just type npm install. What that does is looks at npm’s latest tag for your repository, and installs that version.

They can also specify a version by passing it after the @ character after the module name: npm install module@1.7.3.

Lets say you have some beta users and always want them to grab the beta, without having to remember the latest version you’ve pushed.

You just run npm publish --tag beta, then have them run npm install module@beta.

At any time, they can still specify the beta version npm install module@1.7.3-beta.1 if they want to hop down or up a version, for example.

Looking up npm tags

Using the npm CLI, you can easily see the versions by running npm view ionic dist-tags. Just replace ionic with whatever module you’d want to see.

You can also look up the entire list of versions npm maintains at the url, registry.npmjs.org/ionic.

As a fun fact, npm uses tags on its own tool, npm, to mark the latest, latest-2, next, next-2, as well as their next versions in their current major/minor versions, for example:

latest => 3.3.8 next => 3.3.9 latest-2 => 2.14.7 next-2 => 2.14.8 v3.x-latest => 3.3.8 3.x-latest => 3.3.8 3.x-next => 3.3.9 v3.x-next => 3.3.9

Also, I made a quick tool to look up tags for you npm version.

Assigning a tag

Let’s say you have a blessed version you now want to promote. It’s super simple to set up that tag to the previous version.

Just run npm dist-tags add ionic-app-lib@0.6.5 latest and you’ll have the latest tag point at 0.6.5.

Whoops, I accidently published without a tag!

This has happened to me thousands of times. I’ve run npm publish without specifying a tag, and now, my latest points at an alpha version. How embarassing.

The scenario is this – my module ionic-app-lib currently has its latest tag at 0.6.4, i’m working on 2.0.0-alpha.18, and I type in npm publish. I wanted to tag this as alpha, but because of my haste, now all my users will grab this version blindly without wanting it.

Thankfully, this is easily fixed – we just have to point latest tag back to its version.

First, just put latest back to 0.6.4, like so: npm dist-tags add ionic-app-lib@0.6.4 latest.

Now we put alpha to what we wanted originally, like so: npm dist-tags add ionic-app-lib@2.0.0-alpha.18 alpha.

Bam! Now everything is back to how we want it!

Removing tags

This is super simple: npm dist-tags rm alpha – this wipes it out.

Hope this helps!