How to use Angular components from different folder? - html

Seems like an obvious design decision for me but i can't seem to find any info on how to implement it.
I did the following:
created /pages folder and turned components in to modules for routing
created /components folder for components only
src/app/components/footer/footer.component.ts :
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
src/app/pages/home/home.component.ts :
import { Component, OnInit } from '#angular/core';
import { TranslateConfigService } from 'src/app/services/translate-config.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private translateConfigService: TranslateConfigService) { }
ngOnInit(): void {
}
}
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule } from '#angular/router';
import { HomeRoutes } from './home.routes';
import { TranslateModule } from '#ngx-translate/core';
import { HomeComponent } from './home.component';
import { FooterComponent } from 'src/app/components/footer/footer.component';
#NgModule({
declarations: [
HomeComponent,
FooterComponent,
],
exports: [HomeComponent],
imports: [
CommonModule,
RouterModule.forChild(HomeRoutes),
TranslateModule
]
})
export class HomeModule { }
I didn't import anything explicitly, but when i try to use from /components in some page's html - i get an error saying
Error: src/app/pages/terms/terms.component.html:391:1 - error NG8001: 'app-footer' is not a known element:
1. If 'app-footer' is an Angular component, then verify that it is part of this module.
2. If 'app-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component to suppress this message.

Related

Angular - Can't import a component from a library

I'm learning Angular and I decided to create separate generic elements in addition to the main project (in a library) and then import and use them according to my needs.
My problem is due to the fact that I can't import the generic components now... (I can import the Module from the library, but when I try to use my component's selector, Angular warns that the element is unknown to it and doesn't compile the server ).
Generic Component:
(.html)
<p>f-base-screen works!</p>
(.ts)
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'nx-flow-base-screen',
templateUrl: './f-base-screen.component.html',
styleUrls: ['./f-base-screen.component.scss'],
})
export class FBaseScreenComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}
Library Module:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FBaseScreenComponent } from './f-base-screen/f-base-screen.component';
#NgModule({
imports: [
CommonModule
],
declarations: [
FBaseScreenComponent
],
exports: [
FBaseScreenComponent
],
})
export class FLibrariesModule {}
f-libraries.ts (exports the module and its components):
export * from './f-libraries.module';
export * from './f-base-screen/f-base-screen.component';
My SharedModule (it's later imported into my app.module):
import { CommonModule } from "#angular/common";
import { NgModule } from "#angular/core";
import { FLibrariesModule } from "#nx-flow/f-libraries";
#NgModule({
imports: [CommonModule, FLibrariesModule],
exports: [CommonModule, FLibrariesModule],
providers: []
})
export class SharedModule {}
App.module.ts:
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FRestService } from './shared/utils/rest.service';
import { SharedModule } from './shared/shared.module';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, HttpClientModule, SharedModule],
exports: [],
providers: [FRestService],
bootstrap: [AppComponent],
})
export class AppModule {}
My Home.component.module.ts (which imports the SharedModule to use the nx-flow-base-screen component):
import { NgModule } from '#angular/core';
import { WelcomeService } from '../../shared/services/flow-services/welcome.service';
import { SharedModule } from '../../shared/shared.module';
import { FRestService } from '../../shared/utils/rest.service';
import { HomeComponent } from './home.component';
#NgModule({
declarations: [HomeComponent],
imports: [SharedModule],
providers: [WelcomeService, FRestService],
bootstrap: [HomeComponent],
})
export class HomeComponentModule {}
My Home.component.html (using the component, the error that appears in the image is the same as angular throws when I compile):
<div>
<span>Home Page</span>
</div>
<nx-flow-base-screen></nx-flow-base-screen>
I already researched and followed tutorials, none of them worked so far. Are there any changes I still need to make to be able to use my component, from the library, within my main project?
If any more files are needed to reach a conclusion, I'll post a print of it.
Error:
apps/flow/src/app/views/home/home.component.html:4:3 - error
NG8001: 'nx-flow-base-screen' is not a known element:
If 'nx-flow-base-screen' is an Angular component, then verify that it is part of this module.
If 'nx-flow-base-screen' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component
to suppress this message.

Angular 9: Cannot instantiate cyclic dependency

I am reusing a service for HTTP communication which worked fine under Angular 8, but throws the following error under Angular 9:
Error: Cannot instantiate cyclic dependency! HttpService
at throwCyclicDependencyError (core.js:8122)
at R3Injector.hydrate (core.js:17206)
at R3Injector.get (core.js:16960)
at NgModuleRef$1.get (core.js:36337)
at Object.get (core.js:33981)
at getOrCreateInjectable (core.js:5880)
at Module.ɵɵdirectiveInject (core.js:21115)
at NodeInjectorFactory.DashboardComponent_Factory [as factory] (dashboard.component.ts:9)
at getNodeInjectable (core.js:6025)
at instantiateRootComponent (core.js:12788)
at resolvePromise (zone-evergreen.js:798)
at resolvePromise (zone-evergreen.js:750)
at zone-evergreen.js:860
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Object.onInvokeTask (core.js:41640)
at ZoneDelegate.invokeTask (zone-evergreen.js:398)
at Zone.runTask (zone-evergreen.js:167)
at drainMicroTaskQueue (zone-evergreen.js:569)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:484)
at invokeTask (zone-evergreen.js:1621)
This is the code of the HTTP service:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable()
export class HttpService {
url: string = 'http://localhost:8000/';
constructor(private httpClient: HttpClient) { }
public getTestCall() {
return this.httpClient.get(this.url + 'test');
}
}
This is one of the components using HTTP service:
import { Component, OnInit } from '#angular/core';
import { HttpService } from 'src/app/services/http.service';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
constructor(private http: HttpService) { }
ngOnInit(): void { }
}
This is my app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpService } from './services/http.service';
import { environment } from 'src/environments/environment';
import { DashboardComponent } from './views/dashboard/dashboard.component';
import { MaterialsComponent } from './views/materials/materials.component';
import { OrdersComponent } from './views/orders/orders.component';
import { CustomersComponent } from './views/customers/customers.component';
import { ModelsComponent } from './views/models/models.component';
import { ProductsComponent } from './views/products/products.component';
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
DashboardComponent,
MaterialsComponent,
OrdersComponent,
CustomersComponent,
ModelsComponent,
ProductsComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [
HttpService,
{ provide: 'BACKEND_API_URL', useValue: environment.backendApiUrl }
],
bootstrap: [AppComponent]
})
export class AppModule { }
The components are referred within the app.component.html using the [routerLink] directive and app-routing.module.ts
Thanks in advance!
I prefer declaring the HTTP Services as:
#Injectable({
providedIn: 'root',
}) and not providing them in any module.
That way the Service is accessible on the whole app from the beginning and probably you won't have error like this.
It would be better If you include your apps modules in the question.
If you have more than one modules:
The problem could be, that the HttpService is provided in more than one of your modules.
In that case:
Solution can be to create a new module: HttpServiceModule:
#NgModule({
providers: [ HttpService ]
})
export class HttpServiceModule {}
After that, you have to delete in all other modules: providers: [ ...HttpService... ]

Trying to pass JSON data with angular/nativescript routing

I'm currently working on a nativescript/angular/typescript project and I'm basically trying to pass JSON data from one view (property) to another (propertyinfo).
First, I load up a JSON file in property.service.ts:
import { Injectable } from '#angular/core';
import { HttpClientModule, HttpClient } from '#angular/common/http';
#Injectable()
export class PropertyService {
public propertyData: any;
public selectedProperty: any;
constructor(private http: HttpClient) {
this.loadProperties();
}
loadProperties() {
this.http.get('/pages/property/property.json').subscribe(
(data) => {
this.propertyData = data;
}
)
}
}
This JSON data gets displayed in a view property.component.html:
<StackLayout *ngFor="let item of propertyData" class="list-group" xstyle="height: 300">
<GridLayout rows="110" columns="*, 40" (tap)="details(item)">
<StackLayout row="0" col="0">
<Label text="{{item.streetName}} {{item.houseNumber}}" class="text-primary p-l-30 p-t-5"></Label>
<Label text="{{item.etc}} {{item.etc}}" class="text-primary p-l-30 p-t-5"></Label>
</StackLayout>
<Label row="0" col="1" text="" class="fa arrow" verticalAlignment="middle"></Label>
</GridLayout>
<StackLayout class="hr-light"></StackLayout>
Here, the (tap)="details(item)" will call a function in property.component.ts:
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
import { PropertyService } from './property.service';
#Component({
selector: 'app-property',
templateUrl: 'pages/property/property.component.html',
providers: [PropertyService]
})
export class PropertyComponent implements OnInit {
public propertyData: any;
constructor(private router: Router, private propertyService: PropertyService) {}
ngOnInit() {
this.propertyData = this.propertyService.propertyData;
}
details(item: any) {
this.propertyService.selectedProperty = item;
this.router.navigate(["/propertyinfo"]);
}
}
Now, when I perform a console.log(JSON.stringify(this.propertyService.selectedProperty)); within my details function, the output is as follows:
JS: {"ID":4,"description":"Lorem ipsum dolor sit amet...", "streetName":"Somestreet","houseNumber":459,"etc":"etc"}
This is my propertyinfo.component.ts:
import { Component, OnInit } from '#angular/core';
import { PropertyService } from '../property/property.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-propertyinfo',
templateUrl: 'pages/propertyinfo/propertyinfo.component.html'
})
export class PropertyinfoComponent implements OnInit {
public selectedProperty: any;
constructor(private propertyService: PropertyService, private router: Router) {
this.selectedProperty = this.propertyService.selectedProperty;
}
ngOnInit() { }
}
Yet, when I perform a console.log(JSON.stringify(this.selectedProperty)); inside the constructor, the output is JS: undefined.
At the bottom of this post, I'll add the app.routing.ts and app.module.ts files so you can see all of my imports/directives etc. I'm really at a loss as to what I'm missing. I hope you can help me.
app.routing.ts:
import { NgModule } from "#angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "#angular/router";
import { PropertyComponent } from "./pages/property/property.component";
import { PropertyinfoComponent } from ".//pages/propertyinfo/propertyinfo.component";
const routes: Routes = [
{ path: "", component: PropertyComponent },
{ path: "propertyinfo", component: PropertyinfoComponent },
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }
app.module.ts:
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
import { HttpClientModule, HttpClient } from '#angular/common/http';
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";
import { PropertyService } from "./pages/property/property.service";
import { PropertyComponent } from "./pages/property/property.component";
import { PropertyinfoComponent } from "./pages/propertyinfo/propertyinfo.component";
#NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule,
NativeScriptRouterModule,
HttpClientModule,
NativeScriptHttpClientModule,
],
declarations: [
AppComponent,
PropertyComponent,
PropertyinfoComponent
],
providers: [
PropertyService
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
Thank you for any help in advance. If I need to clear things up/provide any more info, please let me know.
console.log(JSON.stringify(this.selectedProperty)) returns undefined in PropertyinfoComponent because the PropertyService service being injected is not the same instance in PropertyinfoComponent than it is in PropertyComponent
you did not post the full .html for both component so I can only assume that you have something like the PropertyComponent is a parent component and has a reference/include a PropertyinfoComponent in the html and because of the way angular work, it injected a new instance of the service instead of using the one from the parent component.
check Thierry Templier answer for more information about angular service injection for this type of issue : How do I create a singleton service in Angular 2?

Ionic 2 rootPage not showing

I'm new to Ionic and just started a new project. I picked the template with the 3 tabs at the bottom but now I want a new startpage.
I created a page called LoginPage but when I try to swap TabsPage for LoginPage it just shows an empty screen.
Here are the files
app.component.ts
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { LoginPage } from '../pages/login/login';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage = LoginPage;
constructor(platform: Platform) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
});
}
}
login.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
constructor(public navCtrl: NavController) {
}
}
app.module.ts
import { NgModule, ErrorHandler } from '#angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { SettingsPage } from '../pages/settings/settings';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import {LoginPage} from "../pages/login/login";
#NgModule({
declarations: [
MyApp,
SettingsPage,
ContactPage,
HomePage,
TabsPage,
LoginPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
SettingsPage,
ContactPage,
HomePage,
TabsPage,
LoginPage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
If there are other files you need to see, just say so and I will add them.
Thanks in adventage.
Try adding the login page using ionic CLI
$ ionic g page login
Then add the page in app.module.ts and edit app.component.ts like you mentioned
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { LoginPage } from '../pages/login/login';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage = LoginPage;
constructor(platform: Platform) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
});
}
}

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);
}
}