10 Oct 2016
Brock Ellis
code Ionic Angular

Updating Ionic beta.11 to RC0

tl;dr My notes from upgrading a large-ish Ionic 2 app from beta.11 to RC.0

Huzzah! Ionic 2 Release Candidate 0 is out in the wild!!!

This is super exciting news. I’ve been using Ionic for a few months now full time and it’s an amazing framework. I love just about everything about it. However, it is still officially in beta so the constant breaking changes is difficult to deal with.

The biggest hurdle I’ve had with Ionic (and my extension, Angular, since Angular powers the framework) is how to do forms correctly. One of the apps I’ve been building uses forms fairly extensively and it’s been a lot of trial and error to get things working.

I’m working through updating this app to RC0 and found some issues with the new forms modules from Angular. I want to use this blog post as a living list of notes that I can refer to later (and maybe help someone else out in the future).


app.module.ts

The App Module is a new concept for Ionic and I’m still trying to grok it. I do know that to get forms to work properly, you’ll need to import the FormsModule into the imports section of the App Module.

import { NgModule } from '@angular/core';
import { FormsModule }   from '@angular/forms';
import { IonicApp, IonicModule, Nav } from 'ionic-angular';
import { MyApp } from './app.component';

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    FormsModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: [Nav, TokenService, MeService, HttpService, SchoolService, IssueService, ClassService, ErrorService]
})

updateValue()

I used to update a value within a FormGroup with the following code:

(<FormControl>this.assignmentForm.controls['subject']).updateValue(assignment.SubjectID);

I would need to cast the control to a FormControl instead of an AbstractControl to get access to the updateValue() method. However, in Angular 2 Final updateValue() has been deprecated and split into two separate methods: patchValue() and setValue(). You can read more about the difference and reasonings here. The code I’m using now is:

this.assignmentForm.get('subject').patchValue(assignment.SubjectID);

Moment import

My previous import statements for using Moment.JS looked like this:

import * as Moment from 'moment';

The compiler kept throwing odd errors about not being the unix not being defined. I looked around and found a quick answer posted just a few hours earlier on the Ionic Framework Forums. Changing the import to the following structure seemed to help:

import moment from 'moment';

No directive declared for [pipe]

I use 4 or 5 custom pipes for manipulating data in my app. However, after following the directions for upgrading a beta.11 app to RC.0, I was getting an error about no directive declared for one of my pipes. I know it had nothing to do with a specific pipe, because when I removed the first pipe I declared in the app.module.ts file, the error would just complain about the next one.

After re-reading the directions, it looks like I had pasted my Pipes into both the declarations AND entryComponents. Turns out, pipes are not really components, so they needed to be removed from the entryComponents array. Once removed, never saw the error again.

Remove pipes from the entryComponents of the NgModule. Keep them in the declarations.

No Provider for NavController

This was working prior. I have a provider called ErrorProvider that acts as a universal error reporter. After every HTTP request, I catch errors and send them to that provider. The provider then extracts error data and shows an Alert component. I know, its bad practice to mix a provider with UI but it works, so sue me. Also, I have yet to find a good tutorial about how to share UI elements like this. As soon as I find something, I’ll sure as hell post a blog about it.

The issue was that the ErrorProvider was accessing NavController directly (constructor(public nav:NavController) and then this.nav.pop()), when it can’t anymore.

In order to access the active nav from inside of a provider, you have to access it via the App helper.

  constructor(public app:App){
    this.nav = this.app.getActiveNav();
  }

“Cannot read property ‘parentInjector’ of undefined”

This one was a doozy. I had two TabPages (Tabs1Page and Tabs2Page) that I wanted to switch back and forth between. Each TabPage is a root element that should have it’s own navigation stack.

I was attempting to find the root nav element of Tabs1Page and set it to the new Tabs2Page using:

  this.app.getRootNav().setRoot(TabsPage);

This is now the recommended way of resetting root nav (instead of this.nav.setRoot()). Nothing new there. Except it was no longer working in RC.0. It ws giving me this error, which, by the way, has 0 documentation anywhere on the web. I guess I may be the first person ever to see it.

The solution was super simple. I had forgotten to remove the providers on my app.component.ts. All of those dependencies should have been moved to the app.module.ts, which I did. I just neglected to clean up the root component. Commenting out that one line made things work like a charm now.


@Component({
  templateUrl: 'app.template.html',
  //providers: [Nav, TokenService, MeService, HttpService, SchoolService, StudentService, IssueService, ClassService]
})
export class MyApp {
  ...