5

The problem is that in routing i have to click twice to trigger ngOnInit code.

The weird thing is, if I have two routes: A and B, and I clicked on A first, it will trigger the constructor only, and if I clicked on B after it, it will trigger A's onInit before calling B's constructor.

using angular 2.0.0-rc.4 and routes 3.0.0-beta.2

error displayed on page load:

vendors.js:2291 Unhandled promise rejection Error: Cannot match any routes: ''
at Observable._subscribe (http://localhost:54037/js/app.js:19280:28)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:60)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MergeMapOperator.call (http://localhost:54037/js/app.js:26178:21)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:36)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MergeMapOperator.call (http://localhost:54037/js/app.js:26178:21)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:36)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MapOperator.call (http://localhost:54037/js/app.js:56831:21)

gulp file

/// <binding Clean='default, clean, resources' />
/*
This file in the main entry point for defining Gulp tasks and using Gulp     plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
*/

var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var typescript = require('gulp-typescript');
var systemjsBuilder = require('systemjs-builder');
const del = require("del");

// Compile TypeScript app to JS
gulp.task('compile:ts', function () {
return gulp
  .src([
      "appTS/**/*.ts",
      "typings/*.d.ts"
  ])
  .pipe(sourcemaps.init())
  .pipe(typescript({
      "module": "system",
      "moduleResolution": "node",
      "outDir": "app",
      "target": "ES5"
  }))
  .pipe(sourcemaps.write('.'))
  .pipe(gulp.dest('app'));
});

// Generate systemjs-based bundle (app/app.js)
gulp.task('bundle:app', function () {
var builder = new systemjsBuilder('./', './system.config.js');
return builder.buildStatic('app', 'wwwroot/js/app.js');
});

// Copy and bundle dependencies into one file (vendor/vendors.js)
// system.config.js can also bundled for convenience
gulp.task('bundle:vendor', function () {
return gulp.src([
    'node_modules/core-js/client/shim.min.js',
    'node_modules/systemjs/dist/system-polyfills.js',
    'node_modules/reflect-metadata/Reflect.js',
    'node_modules/zone.js/dist/zone.js',
    'node_modules/systemjs/dist/system.js',
    'system.config.js'
])
    .pipe(concat('vendors.js'))
    .pipe(gulp.dest('build'));
});

// Copy dependencies loaded through SystemJS into dir from node_modules
gulp.task('copy:vendor', function () {
return gulp.src([
    'node_modules/rxjs/bundles/Rx.js',
    'node_modules/@angular/**/*'
])
.pipe(gulp.dest('build'));
});

gulp.task('vendor', ['bundle:vendor', 'copy:vendor']);
gulp.task('app', ['compile:ts', 'bundle:app']);

// Bundle dependencies and app into one file (app.bundle.js)
gulp.task('bundle', ['vendor', 'app'], function () {
return gulp.src([
    'build/app.js',
    'build/vendors.js'
])
.pipe(concat('app.bundle.js'))

.pipe(gulp.dest('wwwroot/js/app'));
});

/**
 * Copy all resources that are not TypeScript files into build directory.
 */
gulp.task("resources", () => {
return gulp.src(["Scripts/app/**/*", "!**/*.ts"])
    .pipe(gulp.dest("wwwroot/app"));
});

/**
 * Remove build directory.
 */
gulp.task('clean', (cb) => {
return del(["build"], cb);
});

gulp.task('default', ['bundle']);

app.routes

import { provideRouter, RouterConfig } from '@angular/router';
import { MediaItemFormComponent }  from './media-item-form.component';
import { MediaItemListComponent }    from './media-item-list.component';


export const routes: RouterConfig = [
{ path: 'list', component: MediaItemListComponent },
{ path: 'add', component: MediaItemFormComponent }
];

export const APP_ROUTER_PROVIDERS = [
provideRouter(routes)
];

list component

import {Component, Inject, OnInit } from '@angular/core';
import 'rxjs/Rx'; 
import {MediaItemComponent} from './media-item.component';
import {CategoryListPipe} from './category-list.pipe';
import {MediaItemService} from './media-item.service';

@Component({
selector: 'media-item-list',
directives: [MediaItemComponent],
pipes: [CategoryListPipe],
providers: [MediaItemService],
templateUrl: 'app/media-item-list.component.html',
styleUrls: ['app/media-item-list.component.css']
})
export class MediaItemListComponent implements OnInit {
mediaItems; 

constructor(private mediaItemService: MediaItemService) {
    console.log("constructor MediaItemList");
}

ngOnInit() {
    console.log("ngOnInit MediaItemList");
    this.getMediaItem();

}

onMediaItemDeleted(mediaItem) {

    this.mediaItemService.delete(mediaItem)
        .subscribe(() => {
            this.getMediaItem();

        });
}

getMediaItem() {

    this.mediaItemService.get().subscribe(mediaitems => {
        this.mediaItems = mediaitems;
    },
        function (error) { console.log("Error happened" + error) },
        function () {
        }
    );
}
}

system.js

// map tells the System loader where to look for things
var map = {
'app': 'Scripts/app',
'rxjs': 'node_modules/rxjs',
'@angular': 'node_modules/@angular'
};

// packages tells the System loader how to load when no filename and/or no         extension
var packages = {
'app': { main: 'main', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
};

var packageNames = [
  '@angular/common',
  '@angular/compiler',
  '@angular/core',
  '@angular/forms',
  '@angular/http',
  '@angular/platform-browser',
  '@angular/platform-browser-dynamic',
  '@angular/router',
  '@angular/testing',
  '@angular/upgrade',
];

// add package entries for angular packages in the form '@angular/common': {         main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function (pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});

System.config({
map: map,
packages: packages
});

index.html

<html>
<head>
<title>MeWL</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/" />
<link href="resets.css" rel="stylesheet">
<script src="js/vendors.js"></script>
<script src="js/app.js"></script>
<style>
    body {
        margin: 0px;
        padding: 0px;
        background-color: #32435b;
    }
</style>
</head>

<body>
<media-tracker-app>Loading...</media-tracker-app>
</body>

</html>

Update:

I'll include html of list and the component nested inside if it helps

    <media-item
    *ngFor="let mediaItem of mediaItems"
    [mediaItemToWatch] ="mediaItem"
    (deleted)="onMediaItemDeleted($event)"
    [ngClass]="{'medium-movies': mediaItem.medium === 'Movies', 'medium-    series' :  mediaItem.medium === 'Series'}"        ></media-item>

MediaItem html:

    <h2>{{mediaItem.name }}</h2>

    <div>{{mediaItem.category}}</div>
    <div>{{mediaItem.year}}</div>
    <div class="tools">
    <a class="delete" (click)="onDelete()">
    remove
    </a>
    <a class="details">
    watch
    </a>
    </div>

Media Item ts:

import {Component, Input, Output, EventEmitter} from '@angular/core';
import {FavoriteDirective} from './favorite.directive';



@Component({
selector: 'media-item',
directives: [FavoriteDirective],
templateUrl: 'app/media-item.component.html',
styleUrls: ['app/media-item.component.css']
})
export class MediaItemComponent {

@Input('mediaItemToWatch') mediaItem;
@Output('deleted') delete = new EventEmitter();
onDelete() {
    this.delete.emit(this.mediaItem);
}
}
14
  • What about updating to router beta.2? Commented Jul 5, 2016 at 13:19
  • I've upgraded to rc4 and beta.2 and still same issue :/ Commented Jul 5, 2016 at 13:44
  • What browsers have you tested? Commented Jul 5, 2016 at 13:48
  • 1
    This might be related github.com/angular/angular/issues/9818 Commented Jul 5, 2016 at 13:52
  • 1
    It might be caused by the error you get on reload. Can you please try to add the route { path: '', redirectTo: '/list', pathMatch: 'full' }, and try again? Commented Jul 5, 2016 at 14:25

2 Answers 2

2

It seems

vendors.js:2291 Unhandled promise rejection Error: Cannot match any routes: ''

causes change detection to not run

To avoid this error add a route for the '' path like

{ path: '', redirectTo: '/list', pathMatch: 'full' }

or

{ path: '', component: DummyComponent, pathMatch: 'full' }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so muchhh this has fixed the problem :D you're a legend!
I am still experiencing this issue in Angular 6.0.3 without any error in the console - I have to click the route link twice to load any data from an outside service
-1

I think better answer is to add "onSameUrlNavigation" option on

RouterModule.forRoot(
  appRoutes,
  {
    useHash: false,
    anchorScrolling: "enabled",
    onSameUrlNavigation: "reload",
    enableTracing: true,
    scrollPositionRestoration: "enabled"
  })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.