I am using Ionic 3 and angular 5. I have one feature module 'Settings':
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { SettingsPage } from './test';
#NgModule({
declarations: [
SettingsPage,
],
imports: [
IonicPageModule.forChild(SettingsPage),
],
})
export class SettingsPageModule {}
Under Settings module I want to add 5 more pages.
I checked a lot of post and cannot found out how to do that. Is it even possible ?
The Ionic3 standard way, if you use lazy loading, is: one module per page.
If you use the CLI, ionic generate page command will do the job for you and create a folder with 4 files whenever you create a new page.
If you don't want pages to live each in a separate directory, one way could be to create the new page-related files in the same directory.
But, if you want multiple pages in one module, it's not going to work, at least in my experience - e.g. if you try to place two pages in the same directory and load them from the same module, you'll get this error message:
Error: /.../src/pages/pagegroup/pageX.ts has a #IonicPage decorator, but it does not have a corresponding "NgModule" at /.../src/pages/pagegroup/pageX.module.ts
Below I'm explaining a working solution to have multiple pages, each with its own module, in a single directory.
Let's assume you start from this:
src
settings
settings.html
settings.module.ts
settings.scss
settings.ts
...and you want to add a page named "CustomSettingsPage".
Depending on how complex this page is, you must add the following 2 to 4 files, in the same directory (src/settings) - the optional ones are between square braces:
[custom-settings.html]
custom-settings.module.ts
[custom-settings.scss]
custom-settings.ts
The module and page .ts files will have a similar structure:
custom-settings.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { CustomSettingsPage } from './custom-settings';
#NgModule({
declarations: [
CustomSettingsPage,
],
imports: [
IonicPageModule.forChild(CustomSettingsPage),
],
exports: [
CustomSettingsPage
]
})
export class CustomSettingsPageModule {}
custom-settings.ts
import { Component } from '#angular/core';
import { IonicPage } from 'ionic-angular';
#IonicPage()
#Component({
selector: 'page-custom-settings',
template: `<your html template here>`
})
export class CustomSettingsPage {
// your page code here
};
Instead of template: you could use templateURL: 'custom-settings.html' - in that case, you should create the corresponding custom-settings.html template file in the same directory.
If you want to add the CSS rules for this page, you can create an optional custom-settings.scss file like:
.page-custom-settings {
/* your rules here */
}
or, you can add those CSS rules to the existing settings.scss file: this is really up to you.
I believe what you want is "modals"
https://ionicframework.com/docs/components/#modals
You can add individual pages under your settings.
I'm late to this question but just in case someone needs it in the future!
I'm not sure if you are referring to this but you can have several pages into one module having a folder tree like, for example:
pages
settings
childPage 1
child1.page.(html|scss|ts)
childPage 1
child1.page.(html|scss|ts)
settings.module.ts
settings.page.(html|scss|ts)
then in your Setting Routing Module you do like
import ...
const routes: Routes = [{
path: '',
redirectTo: 'pathtoRedirect', // if you need it
pathMatch: 'full'
}, {
path: '',
component: SettingsPage
}, {
path: 'child-page-1',
component: ChildPage1
}, {
path: 'child-page-2',
component: ChildPage2
}]
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SettingsPageModule {}
Then in your App Routing Module you can do something like:
import ...
const routes: Routes = [{
...
}, {
path: 'settings',
loadChildren: () => import('./pages/settings/settings.module').then(m => m.SettingsPageModule),
}, {
...
}]
#NgModule({
...
})
export class AppRoutingModule{}
This should work. What a component needs is for it to be in ANY module. It's true "module per page strategy" is included as best practice, however, sometimes I simply don't want to have many files that actually can be deleted and managed under the same module.
From this point, you can have a different folder tree if you feel like it, or even create a deeper nested route like
/settings
/settings/children/:id
/settings/children/otherchildren/childrenpage
Now it would be up to you and your project needs!
Hope this is useful for somebody!
Related
In our Angular 8 project, we have a container component for user registration (user.registartion). Also, we have a reusable component for updating the user information (user.component). Both components has to show a 'user policy' pop-up which is also a reusable component (policy.component). The following picture shows my project structure.
But I can't show the Policy popup in both components. It showing the following error on the user registration page.
How can I access the 'Policy' Component from both the User registration and the User Information component?
You need to create a Shared Module to share components across many modules (and everything you want shared, like pipes, directives etc). There is an example in the docs how to use one:
// ...
#NgModule({
imports: [ CommonModule ],
declarations: [ ... your components etc... ],
exports: [ ... your components etc... ]
})
export class SharedModule { }
Remember to import CommonModule to the imports array in your shared module, and export your components. Then import the shared module to your other modules.
You need to import SharedModule on UserRegistrationModule... something like this:
#NgModule({
// ...
imports: [
CommonModule,
SharedModukle, // <---
],
// ...
})
export class UserRegistrationModule {}
I am currently transforming an old Angular app to a new version (Angular 10) and there is a file in app folder called app.server.module.ts. However, asa far as I see, it seemsto be related to old versions (maybe AngularJS), but I am not sure how to remove this file (which changes should I made in app.module.ts, app.routing.module.ts, etc. Here is that file below:
app.server.module.ts
import { NgModule } from '#angular/core';
import { ServerModule } from '#angular/platform-server';
import { ModuleMapLoaderModule } from '#nguniversal/module-map-ngfactory-loader';
import { AppComponent } from './app.component';
import { AppModule } from './app.module';
#NgModule({
imports: [AppModule, ServerModule, ModuleMapLoaderModule],
bootstrap: [AppComponent]
})
export class AppServerModule { }
Will it be a problem to remove completely?
Update:
Here is the only file using this module in the entire frontend project:
tsconfig.server.json.ts:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"target": "es2016"
},
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule"
}
,
"files": [
"main.ts"
],
"include": [
"src/**/*.d.ts"
]
}
It's not related to AngularJS but to Angular.
If you want to remove this file (without knowing the whole context of your application), you would at least need to make two changes :
Add the bootstrap metadata into another module (AppModule ?) as it defines the root component of your app being bootstrapped from your index.html
bootstrap: [AppComponent]
Check your main.ts file as it might be the module used to bootstrap your application :
platformBrowserDynamic()
.bootstrapModule(AppServerModule)
.catch((err) => console.error(err));
If removing this module in benefit of your AppModule, you would as well need to add the imports ServerModule and ModuleMapLoaderModule into its medatdata.
A button is displayed on the page. When the user selects the button the child component will appear, however, the following error appears - Error: Uncaught (in promise): Error: No component factory found for ModalComponent. Did you add it to #NgModule.entryComponents?
The structure I have set up is as follows and this is in conjunction with Ionic 3 -
app (folder)
- app.module
- app.component
components (folder)
- modal-component.ts
pages (folder)
- pageOne (folder)
- pageOne.module
- pageOne.ts
I put the modal component in the pageOne.module
pageOne.module
#NgModule({
declarations: [
pageOne,
modalComponent
],
entryComponents: [
modalComponent
],
imports: [
IonicPageModule.forChild(pageOne),
],
exports: [
pageOne,
]
})
export class pageOneModule {}
pageOne.ts
#IonicPage()
#Component({
selector: 'pageOne',
templateUrl: 'pageOne.html',
})
export class pageOne {}
Are you bootstrapping your module?
put this somewhere where it will load
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { pageOneModule } from './pages/pageOne/pageOne.module';
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(pageOneModule)
.catch(err => console.log(err));
});
I would also suggest using the angular cli, It does this kind of stuff for you.
Your Page module isn't setup right for lazy loading. I'm not sure exactly what's causing the exact error but when you lazy load you don't export or declare the entry components. Change your page module to:
#NgModule({
declarations: [
pageOne,
modalComponent ],
imports: [ IonicPageModule.forChild(pageOne) ]
})
export class pageOneModule {}
Now, you didn't post your modal component code so I'm not sure if it's something you made or not. If it's something like the Material2 Modals, those need to be in entryComponents. Also, your Nav stacks should use the string name of the page now, not a import to make sure you are loading the same object vs cloning it.
I am pretty new in Angular 2. I am studying how to create modules into an Angular app and I have the following doubt related a tutorial that I am following.
My doubt is related to the routing.
So in my example there is defined this AuthModule module:
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { SigninComponent } from './signin/signin.component';
import { SignupComponent } from './signup/signup.component';
import { AuthRoutingModule } from './auth-routing.module';
#NgModule({
// Components and directives used by the module:
declarations: [
SigninComponent,
SignupComponent
],
// Import modules used by this features module:
imports: [
FormsModule,
AuthRoutingModule
]
})
export class AuthModule {}
and I have the related rotues configuration class defined:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
const appRoutes: Routes = [
{ path: '', redirectTo: '/recipes', pathMatch: 'full' },
{ path: 'shopping-list', component: ShoppingListComponent }
];
#NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
So I think that the export keyword means that the content related to this class can be exported and used somewhere else (in this case I think into the imports array of the AuthModule class).
Is it? Or am I missing something? What it the exact meaning of the export statment?
I am not understanding if it is something related to Angular or more generally to TypeScript (because here I found https://www.typescriptlang.org/docs/handbook/modules.html). So it seems to me that this module concept is not directly bounded to Angular 2 framework but is a TypeScript concept to subdivide our code in a smart way (then Angular 2 can use this kind of feature of the language).
Is it or am I missing something?
Angular imports/exports and TypeScript imports/exports are two different concepts.
TypeScript imports/exports work at language level to make it clear what
a used identifier references exactly. This is entirely unrelated to Angular.
So, if you use FormsModule there can't be any ambiguity, what FormsModule is meant. If there is more than one FormsModule in your code or any of your dependencies, then you need to make it clear with imports which one is meant. You can't import 2 FormsModule from different locations without disambiguation (for example using as foo in the import and then reference it using foo.FormsModule).
This way you can use code from arbitrary 3rd-party libraries and avoid name collisions.
Angular imports/exports are used to make the content of one module available to be used in another module.
Your:
imports: [
FormsModule,
AuthRoutingModule
]
Allows you to use the directives from FormsModule and AuthRoutingModule in AuthModule and registers the services provided by these modules in the AppModule scope or the closed lazy-loaded root scope.
If you reference any of Angulars directives or services in TypeScript code, you also need to add TypeScript imports. Above FormsModule and AuthRoutingModule need to be imported with TypeScript imports, to make the Angular imports: [...] work.
For example like
<form #f="ngForm">
<input type="text">
</form>
works only if FormsModule is listed in imports: [ ... ] of your current module.
There is no TypeScript import required, because there is no TypeScript code.
Yes you are right by using export keyword before your typescript class you can use that class somewhere else .. in your project
I have an Angular2 component, which contains a tab control from #angular/material.
I'm trying to test my component (see simplified code below - I get that there's no point in testing a component that's this simple), and am getting the following error:
Error: Error in ./MdTabHeader class MdTabHeader - inline template:0:0 caused by: No provider for ViewportRuler!
Error: No provider for ViewportRuler!
My assumption was to try and include ViewportRuler (https://github.com/angular/material2/blob/master/src/lib/core/overlay/position/viewport-ruler.ts) as a provider. When I do this (see commented out lines below), karma returns:
Uncaught SyntaxError: Unexpected token import
at http://localhost:9876/context.html:10
Which, from a bit of Googling, suggests that it's serving the .ts file to the browser, rather than the compiled .js. It's possible I'm referencing it from the wrong place.
My question is: how do I make my tests compile?
My code is:
my.component.ts:
#Component({
selector: 'test',
template: require('./test.component.html')
})
export class TestComponent {
items: any[];
constructor() {
this.items = [{ title: 'test 1', description: 'description 1' }, { title: 'test 2', description: 'description 2' }];
}
}
my.component.html:
<md-tab-group>
<md-tab *ngFor="let link of items">
<template md-tab-label>
<h4>{{link.title}}</h4>
</template>
{{link.description}}
</md-tab>
</md-tab-group>
my.component.spec.ts:
import { TestBed } from '#angular/core/testing';
import { Component} from '#angular/core';
import { MaterialModule } from '#angular/material';
import { ViewportRuler} from '#angular/material/core/overlay/position/viewport-ruler'
import { TestComponent } from './test.component';
describe("TestComponent",
() => {
let fixture, component;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [MaterialModule],
declarations: [TestComponent],
providers: [
//{ provide: ViewportRuler }
]
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
});
it('true = true', () => {
expect(true).toBe(true);
});
});
I've tried to include as much info as possible, but I'm new to the whole Angular world, so let me know if there's anything else I can provide.
Many thanks.
2.0.0-beta.3
MaterialModule is deprecated. Developers can either consume individual component modules and their dependencies as needed (e.g. MdButtonModule) or create their own custom module.
MaterialModule
MaterialModule (and MaterialRootModule) have been marked as
deprecated.
We've found that, with the current state of tree-shaking
in the world, that using an aggregate NgModule like MaterialModule
leads to tools not being able to eliminate code for components that
aren't used.
In order to ensure that users end up with the smallest code size
possible, we're deprecating MaterialModule, to be removed in the a
subsequent release.
To replace MaterialModule, users can create their own "Material" modul
within their application (e.g., GmailMaterialModule) that imports only
the set of components actually used in the application.
https://github.com/angular/material2/releases/tag/2.0.0-beta.3
2.0.0-beta.2
Material team removed .forRoot() making this a non-issue.
The use of Module forRoot has been deprecated and will be removed in the next release. Instead, just simply import MaterialModule directly:
#NgModule({
imports: [
...
MaterialModule,
...
]
...
});
https://github.com/angular/material2/releases/tag/2.0.0-beta.2
MaterialModule.forRoot() sets up the providers, which you'll need in a testing module. This should resolve errors like yours and similar ones like No provider for MdIconRegistry!.