Angular2 App doesn't see Service - json

I am building up an Angular2 app and trying to get data from local json file.
The problem is that the service I created is ignored by the app. There are no errors, warnings or whatever either in console or Terminal.
index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>My app</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="app/assets/flex.css">
<link rel="stylesheet" href="app/assets/styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>OLOLOading...</my-app>
</body>
</html>
releases.component.ts
import { Component, OnInit } from '#angular/core';
import { ReleasesService } from './releases/releases.service';
#Component({
selector: 'releases',
templateUrl: 'app/releases/releases.component.html',
providers: [ReleasesService]
})
export class ReleasesComponent implements OnInit {
constructor(private releasesService: ReleasesService) {
this.releases = releasesService.getReleases();
}
ngOnInit() {
this.releasesService.getReleases().subscribe(
releases => {
this.releases = releases;
}
);
}
}
releases.component.html
<div class="releases-component">
<div *ngFor="let release of releases | async">
<h3>Name: {{releases.name}}</h3>
<h4>Name: {{releases.instrument}}</h4>
</div>
</div>
releases.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, Jsonp, Headers, Response, RequestsOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/catch';
#Injectable()
export class ReleasesService {
constructor (private http: Http){ }
getReleases = (): Observable<Response> => {
console.log(this.releases);
return this.http.get('app/releases/releases.json')
.map(res => res.json());
}
}
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule, JsonpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ReleasesComponent } from './releases/releases.component';
import { DistroComponent } from './distro/distro.component';
import { ContactsComponent } from './contacts/contacts.component';
import { routing } from './app.routes';
#NgModule({
imports:[
BrowserModule,
FormsModule,
HttpModule,
JsonpModule,
routing
],
declarations: [
AppComponent,
HomeComponent,
ReleasesComponent,
DistroComponent,
ContactsComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
What has been done wrong?

If you use the async pipe you don't need to use explicit subscribe() because async auto-subscribes to the observable. Try this:
export class ReleasesComponent implements OnInit {
releases: Observable<Array<string>>;
constructor(private releasesService: ReleasesService) {
}
ngOnInit() {
this.releases = this.releasesService.getReleases();
}
}

Related

Add dynamic loading messages with APP_INITIALIZER

I have an app which do some backend calls before initializing. I have a loading screen for this, which tells the user that something is currently loading. The problem is that I also want to show what is currently loading. If one of the backend calls fails, it should specifically displayed what went wrong. To illustrate the problem, I have programmed a small sample app.
app.module.ts
import { APP_INITIALIZER, NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { MatButtonModule } from '#angular/material/button';
import { MatMenuModule } from '#angular/material/menu';
import { MatTreeModule } from '#angular/material/tree';
import { MatIconModule } from '#angular/material/icon';
import { MatInputModule } from '#angular/material/input';
import { TreeNodeComponent } from './tree-node/tree-node.component';
import { ListElementComponent } from './list-element/list-element.component';
import { HttpClient } from '#angular/common/http';
import { forkJoin, switchMap, tap } from 'rxjs';
import { UserService } from './user.service';
import { ProudctService } from './proudct.service';
#NgModule({
declarations: [
AppComponent,
TreeNodeComponent,
ListElementComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
MatMenuModule,
MatTreeModule,
MatIconModule,
MatInputModule
],
providers: [{
provide: APP_INITIALIZER,
multi: true,
deps: [UserService, ProudctService],
useFactory: getUserConfig
}],
bootstrap: [AppComponent]
})
export class AppModule { }
export function getUserConfig(userService: UserService, productService: ProudctService) {
return function () {
switchMap(() => {
const user$ = userService.getUsers();
const product$ = productService.getAllProducts();
return forkJoin([user$, product$]);
})
}
}
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>FocusManagerPlayground</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght#300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-typography">
<app-root>
<div class="splash">Loading User... </div><div *ngIf="loading">Succesfull</div><div *ngIf="!loading">failed</div>
<div class="splash">Loading Product...</div>
</app-root>
<app-loading></app-loading>
</body>
</html>
and here a screenshot how it should looks like:
If the first backend call was successful, on the right of the loading message should be a success icon anf if it fails, there should be a fail icon. As the same by loading the products.
Not sure if your example is what your doing or just meant to illustrate but is there a reason your not having the loading messages in the component? I would put your messages in a component and then separate the calls into a service that is kicked off on initialization. The component can reference the service and then you can use something like flags to update the template.
app.module.ts
export const userFactory = (provider: UserService): (() => Promise<void>) => () => provider.load();
#NgModule({
providers: [
UserService,
{ provide: APP_INITIALIZER, useFactory: userFactory, deps: [UserService], multi: true },
Example Service -- just doing the UserService as an example
#Injectable()
export class UserService {
usersLoading: boolean
usersLoadError: boolean
user: any;
load(): void {
this.usersLoading = true;
this.getData();
}
getData() {
setTimeout(() => {
this.user = { id: 1, name: 'hi' };
this.usersLoading = false;
this.usersLoadError = false;
}, 5000);
}
}
Template -- I don't really like flags but just using here to make a point you could also just check that the user property is truthy.
#Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>
{{userService.usersLoading ? 'Loading' : 'loaded' }}`,
styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent {
#Input() name: string;
constructor(public userService: UserService) {}
}
Please find a working example here:https://stackblitz.com/edit/angular-tj57g2?file=src/app/user.service.ts

Angular - Scrolling bar error "TypeError: tView is null"

I would like to make a scroll widget for my array in html file but I get an error:
"ERROR ERROR: Not Caught (in promise): Error type: tView is null". I don't know why it doesn't work. To make scrollbar i use CdkScrollableModule, ScrollDispatcher services.
app.module.ts:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {RouterModule, Routes, Scroll} from "#angular/router";
import {NewPlanComponent} from "../new-plan/new-plan.component";
import {ManagementComponent} from "../management/management.component";
import {TeachersComponent} from "../management/teachers/teachers.component";
import {RoomsComponent} from "../management/rooms/rooms.component";
import {SubjectsComponent} from "../management/subjects/subjects.component";
import {GroupsApiService, RoomsApiService, SubjectsApiService, TeachersApiService} from "../api.services";
import {HttpClient, HttpClientModule} from "#angular/common/http";
import {enableProdMode} from '#angular/core';
import { TeacherComponent } from '../management/teachers/teacher/teacher.component';
import {FormsModule, ReactiveFormsModule} from '#angular/forms';
import { RoomComponent } from '../management/rooms/room/room.component';
import { SubjectComponent } from '../management/subjects/subject/subject.component';
import { GroupsComponent } from '../management/groups/groups.component';
import { GroupComponent } from '../management/groups/group/group.component';
import { NewTimetableComponent } from '../new-plan/new-timetable/new-timetable.component';
import {focusCellDirective} from '../shared/focus-cell.directive';
import {focusCellSubjectDirective} from "../shared/focus-cell-subject.directive";
import {ScrollDispatcher} from "#angular/cdk/overlay";
import {CdkScrollableModule, ScrollingModule} from "#angular/cdk/scrolling";
import {CdkVirtualScrollAppendOnlyExample} from "../scroll-bar/scroll-bar.component";
import {BrowserAnimationsModule} from "#angular/platform-browser/animations";
import {MatNativeDateModule} from '#angular/material/core';
export const router: Routes = [
{ path: 'newplan', component:NewPlanComponent},
{ path: 'management', component:ManagementComponent},
{ path: 'management/teachers', component:TeachersComponent},
{ path: 'management/rooms', component:RoomsComponent},
{ path: 'management/subjects', component:SubjectsComponent},
{ path: 'management/teachers/teacher', component:TeacherComponent},
{ path: 'management/rooms/room', component:RoomComponent},
{ path: 'management/subjects/subject', component:SubjectComponent},
{ path: 'management/groups', component:GroupsComponent},
{ path: 'management/groups/group', component:GroupComponent},
{ path: 'newplan/newtimetable', component:NewTimetableComponent},
{ path: 'newplan/scrollbar', component:CdkVirtualScrollAppendOnlyExample},
];
#NgModule({
declarations: [
AppComponent,
ManagementComponent,
NewPlanComponent,
TeachersComponent,
TeacherComponent,
RoomsComponent,
RoomComponent,
SubjectComponent,
SubjectsComponent,
GroupsComponent,
GroupComponent,
NewTimetableComponent,
focusCellDirective,
focusCellSubjectDirective,
CdkVirtualScrollAppendOnlyExample,
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
RouterModule.forRoot(router),
FormsModule,
ReactiveFormsModule,
ScrollingModule,
CdkScrollableModule,
BrowserAnimationsModule,
MatNativeDateModule,
],
providers: [TeachersApiService,HttpClient,HttpClientModule,RoomsApiService,SubjectsApiService,GroupsApiService,ScrollDispatcher],
bootstrap: [AppComponent]
})
export class AppModule { }
new-timetable.component.html :
<html>
<body>
<cdk-virtual-scroll-viewport appendOnly class="example-viewport"y>
<div *cdkVirtualFor="let item of arr">
{{item}}
</div>
</cdk-virtual-scroll-viewport>
</body>
</html>
new-timetable.component.ts :
import { Component, OnInit } from '#angular/core';
import {GroupsApiService} from "../../api.services";
import {Groups} from "../../models/groups.model";
import {SubDb} from "../../models/subDb.mobels";
#Component({
selector: 'app-new-timetable',
templateUrl: './new-timetable.component.html',
styleUrls: ['./new-timetable.component.css']
})
export class NewTimetableComponent implements OnInit {
constructor() { }
arr=['fafsa','fsfafs','gsgad','fafsa','fsfafs','gsgad','fafsa','fsfafs','gsgad','fafsa','fsfafs','gsgad','fafsa','fsfafs','gsgad']
ngOnInit(): void {
}
}

Add context path Angular 2

I want to run my app instead of http://localhost:4200 at http://localhost:4200/pilot/.
I'm trying to change the base href at index.html but I get Uncaught SyntaxError: Unexpected token <
This is my index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>PrimengQuickstartCli</title>
<base href="pilot/"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
And my app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { MessagesModule } from 'primeng/primeng';
import { InputTextModule } from 'primeng/primeng';
import { PasswordModule } from 'primeng/primeng';
import { ButtonModule } from 'primeng/primeng';
import { DataTableModule, SharedModule } from 'primeng/primeng';
import { DialogModule } from 'primeng/primeng';
import { CarService } from './service/carservice';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
ButtonModule,
MessagesModule,
InputTextModule,
PasswordModule,
ReactiveFormsModule,
DataTableModule,
SharedModule,
DialogModule
],
providers: [CarService],
bootstrap: [AppComponent]
})
export class AppModule { }
Should I change the folder structure?
I appreciate any help.
At the end with this was enough in my index.html:
<base href="/pilot/">
you cam make use of routing module in angular 2 and redirect the user to /pilot when no path is set in the url
SO you will have code like this in app.routing.ts
{path: '',redirectTo: '/pilot',pathMatch: 'full'},
still need to see if this can be done without routing.

Can't I use a component defined in a file other than app.component.ts in HTML directly?

I am facing difficulty in using a component defined in a file named navigation.component.ts directly on HTML Page.
The same component works fine if I use it under template of a component defined on app.component.ts.
Contents of app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { NavigationComponent} from './shared/navigation.component';
#NgModule({
imports: [BrowserModule],
declarations: [AppComponent, NavigationComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Contents of navigation.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'navigation',
templateUrl: '/views/shared/navigation.html'
})
export class NavigationComponent {
userName: string = 'Anonymous';
}
Contents of app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'main-app',
template: '<navigation></navigation><h1>{{pageTitle}}</h1>'
})
export class AppComponent {
pageTitle: string = 'Portal 2.0';
}
Contents of index.html
<body>
<main-app></main-app>
</body>
The above works and renders menus on top but when I try to use <navigation> directly (given below) it doesn't render it, doesn't show any errors either.
<body>
<navigation></navigation>
</body>
Am I doing something wrong?
And the bigger question is how I go debugging issues like this?
Yes you can use web components. Add all the components that you want to load to entrycomponents.
Using createCustomElement you can create elements and use their selector anywhere.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, Injector } from '#angular/core';
import { createCustomElement } from '#angular/elements';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
entryComponents: [AppComponent]
})
export class AppModule {
constructor(private injector: Injector) {
console.log('Elements is loaded: Activation');
this.registerComponent('metro-activation-loader', AppComponent);
}
public ngDoBootstrap(): void {
console.log('Elements is loaded: Activation ngDoBootstrap');
}
// tslint:disable-next-line:no-any
private registerComponent(name: string, component: any): void {
const injector = this.injector;
const customElement = createCustomElement(component, { injector });
customElements.define(name, customElement);
}
}

Angular2 rc5 and Electron Error - Cannot resolve component using

I learning how to use angular2 with electron.Currently i am using the the latest angular rc5 and the latest version of electron.I decided to use the official angular tutorial (Tour of heroes). I had no major problems till i got to routing.I had to make some little changes for routing to work eg in index.html instead of using for support with electron i had to use .I am also using webpack and angular2-materialize.
My problem is when i click one of the heroes it shows the error stated in the title, here is a picture :
error image
here is the code for this particular component (dashboard.component)
html (dashboard.component.html): `
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1- 4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</div>
</div>
`
typescript(dashboard.component.ts):
import {Component, OnInit} from '#angular/core';
import {Hero} from './hero';
import {HeroService} from './hero.service';
import {Router} from '#angular/router';
#Component({
selector: 'my-dashboard',
templateUrl: './dashboard.component.html'
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private router: Router,private heroService: HeroService){}
ngOnInit(): void {
this.heroService.getHeroes().then(heroes => this.heroes = heroes.slice(1,5));
}
gotoDetail (hero: Hero): void
{
let link = ['/detail',hero.id];
this.router.navigate(link);
}
}
app.module.ts :
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import {MaterializeDirective} from "angular2-materialize";
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service';
import {HeroesComponent} from './heroes.component';
import {routing} from './app.routing';
import {DashboardComponent} from './dashboard.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
routing,
],
declarations: [
AppComponent,HeroDetailComponent,MaterializeDirective,HeroesComponent,DashboardComponent
],
providers: [HeroService],
bootstrap: [ AppComponent ],
})
export class AppModule { }
index.html:
<html>
<head>
<base href="">
<title>First App</title>
<!--<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">-->
<link href="../icons/icon.css" rel="stylesheet">
<link href="../node_modules/materialize-css/dist/css/materialize.css" rel="stylesheet" />
<link href="../css/styles.css" rel="stylesheet">
</head>
<body>
<myapp></myapp>
<script src="../build/common.js"></script>
<script src="../build/angular2.js"></script>
<script src="../build/app.js"></script>
</body>
main.ts:
import {platformBrowserDynamic} from '#angular/platform-browser-dynamic';
import {AppModule} from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
app.routing.ts:
import {ModuleWithProviders} from '#angular/core';
import {Routes, RouterModule} from '#angular/router';
import {HeroesComponent} from './heroes.component';
import {DashboardComponent} from './dashboard.component';
import {HeroDetailComponent} from './hero-detail.component';
const appRoutes: Routes = [
{
path: 'heroes',
component: HeroesComponent
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: '',
redirectTo: '/dashboard',
pathMatch: 'full'
},
{
path: 'detail/:id',
component:'HeroDetailComponent'
}
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
app.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'myapp',
template: `
<nav>
<div class="nav-wrapper">
{{title}}
<ul id="nav-mobile" class="left">
<li><a routerLink="/heroes">Heroes</a></li>
<li><a routerLink="/dashboard">Dashboard</a></li>
</ul>
</div>
</nav>
<router-outlet></router-outlet>
`
})
export class AppComponent {
title = 'Tour of Heroes';
}
hero-detail.component.ts :
import {Component, Input, OnInit} from '#angular/core';
import {ActivatedRoute, Params} from '#angular/router';
import {HeroService} from './hero.service';
import {Hero} from './hero';
#Component({
selector: 'my-hero-detail',
templateUrl: './hero-detail.component.html'
})
export class HeroDetailComponent implements OnInit {
#Input()
hero: Hero;
constructor(private heroService: HeroService, private route: ActivatedRoute)
{
}
ngOnInit(): void
{
this.route.params.forEach((params: Params) => {
let id = +params['id'];
this.heroService.getHero(id)
.then(hero => this.hero = hero);
});
}
goBack(): void {
window.history.back();
}
}
hero-detail.component.html
<div *ngIf="hero">
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name"/>
</div>
<button (click)="goBack()">Back</button>
</div>
Thank You
You should be have your component name without '(single quote) in component option of route. As you already have imported HeroDetailComponent there in app.routing.ts(rotue configuration).
{
path: 'detail/:id',
component: HeroDetailComponent //<-- removed quote from here
}
I observed that you are having file protocol while asking for template, it means you haven't hosted your application on server.
Please host your application on server(lite server would also work), so that template would ask
over http protocol instead of file.