Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

5.0.0-beta

Compare
Choose a tag to compare
@matanlurey matanlurey released this 29 Jun 19:12
· 1471 commits to master since this release

angular

5.0.0-beta

Welcome to the first release candidate of AngularDart v5.0.0, with full support
for Dart 2. Please note that an up-to-date copy of dev channel Dart SDK is
required (at least 2.0.0-dev.65 as of this writing) to use this version of
AngularDart. Additionally:

  • Dartium is no longer supported. Instead, use the new DartDevCompiler
  • Pub transformers are no longer used. Instead, use the new webdev
    CLI, or, for advanced users, the build_runner CLI.

More details of changes to Dart 2 for web users
are available on our webiste.

We are no longer expecting further breaking changes as we get closer to a final
release (which itself is pending a final release of the Dart 2 SDK). Please
continue to report stability issues, bugs, or requests for small non-breaking
enhancements.

Thanks, and enjoy AngularDart!

Dependency Injection

Dependency injection was enhanced greatly for 5.0.0, primarily around using
proper types (for Dart 2), and paths to enable much smaller code size (for
everyone).

New features

  • Provider (and provide) are soft deprecated, and in their place are four
    new classes with more precise type signatures. Additionally, Provider now
    supports an optional type argument <T>, making it Provider<T>.

    • ValueProvider(Type, T) and ValueProvider.forToken(OpaqueToken<T>, T)
      instead of Provider(typeOrToken, useValue: ...).

    • FactoryProvier(Type, T) and FactoryProvider.forToken(OpaqueToken<T>, T)
      instead of Provider(typeOrToken, useFactory: ...).

    • ClassProvider(Type, useClass: T) and
      ClassProvider.forToken(OpaqueToken<T>, useClass: T) instead of
      Provider(typeOrToken, useClass: ...) or an implicit Type.

    • ExistingProvider(Type, T) and
      ExistingProvider.forToken(OpaqueToken<T>, T) instead of
      Provider(typeOrToken, useExisting: ...).

  • OpaqueToken is now much more useful. Previously, it could be used to define
    a custom, non-Type to refer to something to be injected; commonly instead of
    types like String. For example, you might use an OpaqueToken to refer to
    the a URL to download a file from:

    const downloadUrl = OpaqueToken('downloadUrl');
    
    @Component(
      providers: [
        Provider(downloadUrl, useValue: 'https://a-site.com/file.zip'),
      ],
    )
    class Example {
      Example(@Inject(downloadUrl) String url) {
        // url == 'https://a-site.com/file.zip'
      }
    }

    First, OpaqueToken adds an optional type argument, making OpaqueToken<T>.
    The type argument, T, should be used to refer to the Type of the object
    this token should be bound to:

    const downloadUrl = OpaqueToken<String>('downloadUrl');

    Coupled with the new named Provider classes and their .forToken named
    constructor (see below), you now also have a way to specify the type of
    providers using type inference:

    @Component(
      providers: [
        // This is now a Provider<String>.
        ValueProvider.forToken(downloadUrl, 'https://a-site.com/file.zip'),
      ],
    )

    Second, MultiToken<T> has been added, and it extends OpaqueToken<List<T>>.
    This is an idiomatic replacement for the now deprecated multi: true
    argument to the Provider constructor:

    const usPresidents = MultiToken<String>('usPresidents');
    
    @Component(
      providers: [
        ValueProvider.forToken(usPresidents, 'George'),
        ValueProvider.forToken(usPresidents, 'Abe'),
      ],
    )
    class Example {
      Example(@Inject(usPresidents) List<String> names) {
        // names == ['George', 'Abe']
      }
    }

    Third, we heard feedback that the String-based name of tokens was
    insufficient for larger teams because the names could collide. Imagine 2
    different tokens being registered with a name of 'importantThing'! It is now
    possible (but optional) to extend either OpaqueToken or MultiToken to
    create scoped custom token names:

    class DownloadUrl extends OpaqueToken<String> {
      const DownloadUrl();
    }
    
    class UsPresidents extends MultiToken<String> {
      const UsPresidents();
    }
    
    class Example {
      providers: const [
        ValueProvider.forToken(DownloadUrl(), 'https://a-site.com/file.zip'),
        ValueProvider.forToken(UsPresidents(), 'George'),
        ValueProvider.forToken(UsPresidents(), 'Abe'),
      ],
    }

    Fourth, and finally, we'd like to repurpose @Inject in the future, and let
    you write less to inject tokens. So, OpaqueToken and MultiToken
    instances may now be used directly as annotations:

    class Example {
      Example(@DownloadUrl() String url, @UsPresidents() List<String> names) {
        // url == 'https://a-site.com/file.zip'
        // names == ['George', 'Abe']
      }
    }
  • InjectorFactory, a function type definition of
    Injector Function([Injector parent]), was added and started to be used
    across the framework. It normally indicates the ability to create a new
    Injector instance with an optional parent.

  • A new annotation, @GenerateInjector, was added. It is now posibble to
    generate, at compile-time, a standalone InjectorFactory method for
    providers, without explicitly wrapping in an @Component:

    // example.dart
    
    import 'example.template.dart' as ng;
    
    @GenerateInjector([
      ClassProvider(HelloService),
    ])
    final InjectorFactory rootInjector = ng.rootInjector$Injector;
  • Module has been added as a new, more-typed way to encapsulate a collection
    of Provider instances. This is an optional feature to use instead of
    nested const lists to represent shared providers. For example:

    const httpModule = [ /* Other providers and/or modules. */ ];
    
    const commonModule = [
      httpModule,
      ClassProvider(AuthService, useClass: OAuthService),
      FactoryProvider.forToken(xsrfToken, useFactory: readXsrfToken),
    ];

    ... you can represent this with the new typed Module syntax:

    const httpModule = Module( /* ... Configuration ... */);
    
    const commonModule = Module(
      include: [httpModule],
      provide: [
        ClassProvider(AuthService, useClass: OAuthService),
        FactoryProvider.forToken(xsrfToken, useFactory: readXsrfToken),
      ],
    );

    The advantages here are numerous:

    • Less ambiguity around ordering of providers. Engineers would tend to try
      and sort providers alphabetically, would of course, would lead to
      problems. Module specifically outlines that order is significant, and
      that include is processed before provide.

    • Module rejects using a Type implicitly as a ClassProvider. This
      removes additional ambiguity around supporting List<dynamic>, and while
      more verbose, should lead to more correct use.

    • Module tends to be more understandable by users of other dependency
      injection systems such as Guice or Dagger, and reads better than a const
      List (which is a very Dart-only idiom).

    NOTE: It is also possible to use Module in @GenerateInjector:

    @GenerateInjector.fromModules([
      commonModule,
    ])
    final InjectorFactory exampleFromModule = ng.exampleFromModule$Injector;

    NOTE: It is also possible to use Module in ReflectiveInjector:

    // Using ReflectiveInjector is strongly not recommended for new code
    // due to adverse effects on code-size and runtime performance.
    final injector = ReflectiveInjector.resolveAndCreate([
      commonModule,
    ]);

Breaking changes

  • OpaqueToken no longer overrides operator== or hashCode. In practice this
    should have no effect for most programs, but it does mean that effectively
    that only const instances of OpaqueToken (or MultiToken) are valid.

  • It is no longer valid to provide a token type of anything other than Type or
    an OpaqueToken (or MultiToken). In the past anything from aribtrary
    literals (such as a string - 'iAmAToken') or a custom const instance of a
    class were supported.

  • For defining whether a componenr or directive should provide itself for
    injection, Visibility.none has been renamed Visibility.local to make it
    more clear that it is accessable locally (within providers for example).

  • Classes annotated with @Component or @Directive are no longer treated like
    services annotated with @Injectable, and not accessible (by default) to
    ReflectiveInjector. @Injectable can always be added to these classes in
    order to return to the old behavior.

Bug fixes

  • Fixed a bug where calling get on an Injector injected in the context of an
    @Component or @Directive-annotated class and passing a second argument
    always returned null (instead of that second argument) if the token was not
    found.

  • Setting @Component(visibility: Visibility.none) no longer applies to
    providers, if any. Note that Visibility.none was always renamed
    Visibility.local in breaking changes above.

  • Fixed a bug where Provider(SomeType) was not parsed correctly as an implicit
    use of Provider(SomeType, useClass: SomeType).

  • Fixed a bug where <ReflectiveInjectior>.get(X) would throw with a message
    of no provider found for X, even when the acutal cause was a missing
    downstream dependency Y. We now emit the correct message.

Other improvements

  • Some injection failures will display the chain of dependencies that were
    attempted before a token was not found ('X -> Y -> Z') in development mode.
    We are working on making sure this better error message shows up always but
    it is likely to slip until after the v5 release.

  • It is no longer a build warning to have an @Injectable-annotated service
    with more than one constructor. This was originally meant to keep injection
    from being too ambiguous, but there are understood patterns now (first
    constructor), and there is no alternative present yet. We may re-add this as
    a warning if there ends up being a mechanism to pick a constructor in the
    future.

  • It is no longer a build warning to have @Injectable-annotated services
    with named constructor parameters. While they are still not supported for
    injected, they were always successfully ignored in the past, and showing a
    warning to the user on every build served no purpose.

  • If a private class is annotated with @Injectable() the compiler fails. In
    practice this caused a compilation error later in DDC/Dart2JS, but now the
    AngularDart compiler will not emit invalid code.

  • Removed spurious/incorrect warnings about classes that are used as
    interfaces needing @Injectable (or needing to be non-abstract), which are
    wrong and confusing.

  • The compiler behind initReflector() has changed implementations and now
    uses fully-scoped import statements instead of trying to figure out the
    original scope (including import prefixes) of your source code. This was not
    intended to be a breaking change.

Components and Templates

New features

  • NgTemplateOutlet added ngTemplateOutletContext for setting local
    variables in an embedded view. These variables are assignable to template
    input variables declared using let, which can be bound within the template.
    See the NgTemplateOutlet documentation for examples.

  • Added a lifecycle event AfterChanges, which is similar to OnChanges, but
    with a much lower performance cost - it does not take any parameters and is
    suitable when you have multiple fields and you want to be notified when any
    of them change:

    class Comp implements AfterChanges {
      @Input()
      String field1;
    
      @Input()
      String field2;
    
      @override
      void ngAfterChanges() {
        print('Field1: $field1, Field2: $field2');
      }
    }
  • It is possible to directly request Element or HtmlElement types from
    content or view children instead of ElementRef (which is deprecated). For
    example:

    @Component(
      selector: 'uses-element',
      template: '<div #div>1</div>'
    )
    class UsesElement {
      @ViewChild('div')
      // Could also be HtmlElement.
      Element div;
    }
  • Additionally, List<Element> and List<HtmlElement> for @ViewChildren
    and @ContentChildren no longer require read: Element, and the type is
    correctly inferred the same as a single child is.

  • Static properties and methods of a component may now be referenced without a
    receiver in the component's own template. For example:

    Before: ExampleComponent as receiver is necessary.

    @Component(
      selector: 'example',
      template: '<h1>{{ExampleComponent.title}}</h1>',
    )
    class ExampleComponent {
      static String title;
    }

    After: No receiver is necessary.

    @Component(
      selector: 'example',
      template: '<h1>{{title}}</h1>',
    )
    class ExampleComponent {
      static String title;
    }
  • @HostListener() can now automatically infer the const ['$event']
    parameter when it is omitted but the bound method has a single argument:

    class Comp {
      @HostListener('click')
      void onClick(MouseEvent e) {}
    }
  • Added <ng-container>, an element for logical grouping that has no effect
    on layout. This enables use of the *-syntax for structural directives, without requiring the cost an HTML element.

    Before

    <ul>
      <template ngFor let-user [ngForOf]="users">
        <li *ngIf="user.visible">{{user.name}}</li>
      </template>
    </ul>

    After

    <ul>
      <ng-container *ngFor="let user of users">
        <li *ngIf="user.visible">{{user.name}}</li>
      </ng-container>
    </ul>
  • In dev mode only, an attribute named from is now added to each <style>
    tag whose value identifies the source file URL and name of the component from
    which the styles originate.

  • Support for the suffix .if for attribute bindings, both in a template and
    in a @HostBinding(). Accepts an expression of type bool, and adds an
    attribute if true, and removes it if false and closes
    #1058:

    <!-- These are identical -->
    <button [attr.disabled]="isDisabled ? '' : null"></button>
    <button [attr.disabled.if]="isDisabled"></button>

Breaking changes

  • We now have a new, more stricter template parser, which strictly requires
    double quotes ("...") versus single quotes, and in general enforces a
    stricter HTML-like syntax. It does produce better error messages than before.

  • We removed support for ngNonBindable in the new template syntax.

  • The fields inputs: , outputs: , and host: have been removed from
    @Directive(...) and @Component(...). It is expected to use the member
    annotations (@Input(), @Output(), @HostBinding(), @HostLitsener())
    instead.

  • The default for @Component(preserveWhitespace: ...) is now true. Many
    improvements were put into the whitespace optimziation in order to make the
    results easier to understand and work around.

  • <AsyncPipe>.transform no longer returns the (now removed) WrappedValue
    when a transformed result changes, and relies on regular change detection.

  • Pipes no longer support private types in their transform method signature.
    This method's type is now used to generate a type annotation in the generated
    code, which can't import private types from another library.

  • Using @deferred no longer supports the legacy bootstrap processes. You must
    use runApp (or runAppAsync) to bootstrap the application without relying
    on initReflector().

  • <ComponentRef>.componentType always throws UnsupportedError, and will be
    removed in a later minor release. This removes our last invocation of
    .runtimeType, which has potentially severe code-size implications for some
    apps.

  • QueryList for @ViewChildren and @ContentChildren has been removed, in
    favor of just a plain List that is replaced with a new instance when the
    children change (instead of requiring a custom collection and listener):

    class Comp {
      @ViewChildren(ChildComponent)
      set viewChildren(List<ChildComponent> viewChildren) {
        // ...
      }
    
      // Can also be a simple field.
      @ContentChildren(ChildComponent)
      List<ChildComponent> contentChildren;
    }
  • EventEmitter was removed in favor using Stream and StreamController.

  • COMMON_DIRECTIVES was renamed commonDirectives.

  • CORE_DIRECTIVES was renamed coreDirectives.

  • COMMON_PIPES was renamed commonPipes.

  • Private types can't be used in template collection literals bound to an
    input. This is a consequence of fixing a cast warning that is soon to be an
    error caused by the code generated for change detecting collection literals
    in templates. See #844 for more
    information.

  • SafeInnerHtmlDirective is no longer injectable.

  • The following types were never intended for external use and are no longer
    exported by package:angular/security.dart:

    • SafeHtmlImpl
    • SafeScriptImpl
    • SafeStyleImpl
    • SafeResourceUrlImpl
    • SafeUrlImpl
    • SafeValueImpl

    To mark a value as safe, users should inject DomSanitizationService and
    invoke the corresponding bypassSecurityTrust*() method, instead of
    constructing these types directly.

  • ComponentResolver was removed, and SlowComponentLoader was deprecated.

  • Methods in lifecycle hooks have void return type. This is breaking change
    if the override doesn't specify return type and uses return without any
    value. To fix add a void or Future<void> return type to the override:

    class MyComp implements OnInit {
      @override
      void ngOnInit() {
        // ...
      }
    }
  • Removed the rarely used template attribute syntax. Uses can be replaced
    with either the * micro-syntax, or a <template> element.

    Before

      <div template="ngFor let item of items; trackBy: trackById; let i=index">
        {{i}}: {{item}}
      </div>

    After

    <!-- * micro-syntax -->
    <div *ngFor="let item of items; trackBy: trackById; let i=index">
      {{i}}: {{item}}
    </div>
    
    <!-- <template> element -->
    <template
        ngFor
        let-item
        [ngForOf]="items"
        [ngForTrackBy]="trackById"
        let-i="index">
      <div>
        {{i}}: {{item}}
      </div>
    </template>
  • It is now a compile error to implement both the DoCheck and OnChanges
    lifecycle interfaces. DoCheck will never fill in values for the Map in
    OnChanges, so this compile-error helps avoid bugs and directs the user to
    use DoCheck and AfterChanges instead.

  • Using a suffix/unit for the [attr.name.*] syntax other than the newly
    introduced [attr.name.if] is now a compile-error. These binding suffixes
    were silently ignored (users were likely confused with [style.name.px],
    which is supported).

Bug fixes

  • Fixed a bug where an @deferred components were still being linked to in
    initReflector().

  • Fixed a bug where errors thrown in event listeners were sometimes uncaught
    by the framework and never forwarded to the ExceptionHandler.

  • Fixed a bug where DatePipe didn't format millisecondsSinceEpoch in the
    local time zone (consistent with how it formats DateTime).

  • Testability now includes ComponentState updates. Due to prior use of
    animationFrame callback, NgTestBed was not able to detect a stable state.

  • String literals bound in templates now support Unicode escapes of the form
    \u{?-??????}. This enables support for Unicode supplementary planes, which
    includes emojis!

  • Inheriting from a class that defines a @HostBinding() on a static member
    no longer causes the web compiler (Dartdevc or Dart2JS) to fail. We
    previously inherited these bindings and generated invalid Dart code. Given
    that static members are not inherited in the Dart language, it made sense
    to give a similar treatment to these annotations. Instance-level members are
    still inherited:

    class Base {
      @HostBinding('title')
      static const hostTitle = 'Hello';
    
      @HostBinding('class')
      final hostClass = 'fancy';
    }
    
    // Will have DOM of <fancy-button class="fancny"> but *not* title="Hello".
    @Component(
      selector: 'fancy-button',
      template: '...',
    )
    class FancyButton extends Base {}
  • Fixed a bug where a recursive type signature on a component or directive
    would cause a stack overflow. We don't support generic type arguments yet
    (the reified type is always dynamic), but the compiler no longer crashes.

Other improvements

  • Types bound from generics are now properly resolved in a component when
    inheriting from a class with a generic type. For example, the following used
    to be untyped in the generated code:

    class Container<T> {
      @Input()
      T value;
    }
    
    class StringContainerComponent implements Container<String> {}
  • Both ComponentFactory and ComponentRef now have a generic type parameter
    <T>, which is properly reified where T is the type of the component class.

  • The $implicit (iterable) value in *ngFor is now properly typed whenever
    possible. It was previously always typed as dynamic, which caused dynamic lookups/calls at runtime, and hid compilation errors.

  • The type of <EmbeddedViewRef>.rootNodes and <ViewRefImpl>.rootNodes has
    been tightened from List<dynamic> to List<Node> (where Node is from
    dart:html).

  • A combination of compile errors and warnings are produced when it seem that
    template, templateUrl, style, or styleUrls are either incorrect or
    missing when required.

  • The compiler now reports an actionable error when an annotation is used on a
    private class member. We also report errors when various annotations are used
    improperly (but not in all cases yet).

  • The compiler optimizes *ngIf usages where the content is pure HTML.

  • The view compiler is able to tell when exports: [ ... ] in an @Component
    are static reads and are immutable (such as String). This allows us to
    optimize the generated code.

Application Bootstrap

New features

  • The process for starting your AngularDart application changed significantly:

    • For most applications, we recommend now strongly recommend using the new
      runApp function. Instead of starting your application by passing the
      Type of an @Component-annotated class, you now pass a
      ComponentFactory, the generated code for a component:

      import 'package:angular/angular.dart';
      
      // ignore: uri_has_not_been_generated
      import 'main.template.dart' as ng;
      
      void main() {
          runApp(ng.RootComponentNgFactory);
      }
      
      @Component(
          selector: 'root',
          template: 'Hello World',
      )
      class RootComponent {}

      To provide top-level services, use the createInjector parameter, and
      pass a generated InjectorFactory for a top-level annotated with
      @GenerateInjector:

      import 'package:angular/angular.dart';
      
      // ignore: uri_has_not_been_generated
      import 'main.template.dart' as ng;
      
      void main() {
        runApp(ng.RootComponentNgFactory, createInjector: rootInjector);
      }
      
      class HelloService {
        void sayHello() => print('Hello!');
      }
      
      @GenerateInjector([
         ClassProvider(HelloService),
      ])
      final InjectorFactory rootInjector = ng.rootInjector$Injector;

      A major difference between runApp and previous bootstrapping code is
      the lack of the initReflector() method or call, which is no longer
      needed. That means using runApp disables the use of
      SlowComponentLoader and ReflectiveInjector, two APIs that require
      this extra runtime metadata.

      To enable use of these classes for migration purposes, use
      runAppLegacy:

      import 'package:angular/angular.dart';
      
      // ignore: uri_has_not_been_generated
      import 'main.template.dart' as ng;
      
      void main() {
        runAppLegacy(
          RootComponent,
          createInjectorFromProviders: [
            ClassProvider(HelloService),
          ],
          initReflector: ng.initReflector,
        );
      }

      NOTE: initReflector and runAppLegacy disables tree-shaking on
      any class annotated with @Component or @Injectable. We strongly
      recommend migrating to the runApp pattern.

Breaking changes

  • The top-level function bootstrap was deleted. This function always threw a
    runtime exception since 5.0.0-alpha+5, and was a relic of when a code
    transformer rewrote it automatically as bootstrapStatic.

  • Dropped support for @AngularEntrypoint and rewriting entrypoints to
    automatically use initReflector() and bootstrapStatic. This is no longer
    supported in the new build system.

  • RenderComponentType is no longer part of the public API.

  • <ApplicationRef> .componentFactories, .componentTypes, .zone, and
    .registerBootstrapListener were removed; these were used internally by the
    legacy router and not intended to be part of the public API.

  • PLATFORM_INITIALIZERS was removed.

  • APP_INITIALIZER was removed. A similar functionality can be accomplished
    using the runAppAsync or runAppLegacyAsync functions with the
    beforeComponentCreated callback.

  • PlatformRef and PlatformRefImpl were removed.

Misc

Breaking changes

  • <NgZone>.onStable has been renamed to onTurnDone.

  • <NgZone>.onUnstable has been renamed to onTurnStart.

  • The context parameter was removed from <TemplateRef>.createEmbeddedView.

  • The following relatively unused fields and functions were removed:

    • APPLICATION_COMMON_PROVIDERS
    • BROWSER_APP_COMMON_PROVIDERS
    • BROWSER_APP_PROVIDERS
    • PACKAGE_ROOT_URL
    • ErrorHandlingFn
    • UrlResolver
    • WrappedTimer
    • WrappedValue
    • ZeroArgFunction
    • appIdRandomProviderFactory
    • coreBootstrap
    • coreLoadAndBootstrap
    • createNgZone
    • createPlatform
    • disposePlatform
    • getPlatform
  • Running within the NgZone will no longer cause addtional turns to occur
    within it's parent's zone. <NgZone>.run() will now run inside the parent
    zone's run() function as opposed to the other way around.

  • The compilation mode --debug (sparingly used externally) is now no longer
    supported. Some flags and code paths in the compiler still check/support it
    but it will be removed entirely by the final release and should no longer
    be used. We will rely on assertion-based tree-shaking (from Dart2JS)
    going forward to emit debug-only conditional code.

Bug fixes

  • We longer invoke <ExceptionHandler>.call with a null exception.

Other improvements

  • Misspelled or otherwise erroneous annotations on classes now produce a more
    understandable error message, including the element that was annotated and
    the annotation that was not resolved.

Breaking changes

  • Removed SafeScript and its associated APIs. There was no path through the
    compiler that made use of this type.

  • Removed the sanitize() method from SanitizationService. This method was
    entirely unused. Use the more specific methods such as sanitizeHtml() and
    sanitizeUrl() instead.

  • Generated ComponentFactory instances are no longer functionally const.
    This is to prevent issues where users attempt to use generated component
    factories in their own const contexts, which was known to cause problems
    in some build systems.

  • MultiToken<T> now extends OpaqueToken<List<T>>. This should have no real
    affect on most programs, unless you manually typed your MultiToken such as
    usPresidents = const MultiToken<List<String>>(). This will allow future
    features for the Injector interface:
    #555.

  • Using a suffix/unit for the [attr.name.*] syntax other than the newly
    introduced [attr.name.if] is now a compile-error. These binding suffixes
    were silently ignored (users were likely confused with [style.name.px],
    which is supported).

New features

  • ReflectiveInjector.resolveStaticAndCreate was added as an experimental
    API (subject to breaking change at any time). This is primarily for adopting
    runApp incrementally in existing large code-bases that use
    ReflectiveInjector. See #1426
    for details.

  • Support for the suffix .if for attribute bindings, both in a template and
    in a @HostBinding(). Accepts an expression of type bool, and adds an
    attribute if true, and removes it if false and closes
    #1058:

    <!-- These are identical -->
    <button [attr.disabled]="isDisabled ? '' : null"></button>
    <button [attr.disabled.if]="isDisabled"></button>

Bug fixes

  • The generated .template.dart code now properly subtypes AppView<C> where
    C is the annotated @Component class. This avoids implicit down-casts in
    the framework.

  • Fixed a bug where the compiler crashed if an injectable token contained the
    type void (directly or in some nested type like List<void>).

angular_compiler

0.4.0-alpha+16

  • Added support for void and Null types to appear in tokens.

angular_forms

2.0.0-beta

  • Maintanence release to bring into sync with angular 5.0.0-beta.

angular_router

2.0.0-alpha+15

Breaking changes

  • Removed component instance parameter from RouterHook.canNavigate().

angular_test

2.0.0-beta

  • NgZoneStabilizer waits for the longest pending timer during update().