I've started learning to use Angular and so far it seems fairly straight forward. I opted to convert one of my existing website themes over to familiarize myself with the process but ran into a question regarding proper usage.
My understanding thus far is that each page is a component. I have my index content in app.component.html, and then each sub page is a separate component as well. I would however like to separate the header/footer HTML and include it as I have in the past with PHP.
My question is, should the header/footer be individual components or should they just be singular HTML files, included using ng-include? I realize either would work but can't figure out which is the traditional implementation with Angular developers.
I am trying the following approach but the header/footer component's don't seem to load. They work fine from app.component.html but not from index.html.
index.html
<body>
<app-header></app-header>
<app-root></app-root>
<app-footer></app-footer>
</body>
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { ProductComponent } from './product/product.component';
import { ProductsComponent } from './products/products.component';
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
FooterComponent,
ProductComponent,
ProductsComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
You should create Header and footer components and use it in AppComponent.
This is helpful if you want to use i18n tools like translate or if you want to change the header or footer if user is logged in.
The app Structure should be something like this.
AppComponent
|
|----> HeaderComponent
|----> Router-Outlet ---> Page content should be in the container.
|----> FooterComponent
This is how you need to have the files. You cannot have the components in index.html as the angular bootstraps for app not for other components.
Related
I have one feature module that I created via CLI, so it imports the common module.
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { HomeComponent } from './home/home.component';
#NgModule({
declarations: [HomeComponent],
imports: [
CommonModule
]
})
export class HomeModule { }
But when I do this normal paragraph appears but paragraph with *ngFor part doesn't work, it does not display anything.
<p> Some normal paragraph </p>
<p *ngFor = "let i of [1,2,3]" >home works!</p>
I also tried to create a shared module, import and export the common module there, and import that shared module in my feature module but it didn't work.
What could cause the problem?
I have also faced that problem. after looking at my app.module.ts I found that shared my custom module is not imported there. After importing it in app module my problem has been solved
I built a project using angular-elements and managed to successfully embed a component into another application. What I would like to do now is be able to debug the original component from the application it is included in.
All the logic for the component is in one file, which is a concatenation of 4 files created by Angular during build - runtime.js, polyfills.js, scripts.js, main.js.
The js.map files for those 4 files are also created during build and I can successfully place & hit a breakpoint in the original main.ts file (after including the jsmaps in the directory with the output file for the element). However, I have been unable to find a way to debug the actual component.ts file from the application that is using it. The js.map for that component is also included in the bundle and I can view the component.ts file through Chrome DevTools, but if I put any breakpoints they will never be hit.
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, Injector } from '#angular/core';
import { createCustomElement } from '#angular/elements';
import { FormsModule } from "#angular/forms";
import { FirstWebElementComponent } from './first-web-element/first-web-element.component';
import { AppComponent } from './app.component';
import { HttpModule } from '#angular/http';
import { HttpClientModule } from '#angular/common/http';
import { ScenarioSelectorComponent } from './scenario-selector/scenario-selector.component';
#NgModule({
declarations: [
AppComponent,
ScenarioSelectorComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
HttpClientModule
],
providers: [],
entryComponents: [ScenarioSelectorComponent]
})
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const scenarioSelector = createCustomElement(ScenarioSelectorComponent, {injector: this.injector});
customElements.define('scenario-selector', scenarioSelector);
}
}
main.ts
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
To the best of my understanding, the component.ts file logic is included in main.js file during build, but there doesn't seem to be a map created describing
the connection between the two.
For reference, here is the stuff I read / watched.
Building Custom Elements / Web Components with Angular 6
Angular Elements – A Practical Introduction To Web Components With Angular 6
Angular CLI doesn't support inline source maps anymore. Your best bet is to replace ng build with ngx build plus - https://github.com/manfredsteyer/ngx-build-plus
Then add a build plugin to replace the devtool with inline-source-map which will inline the sourcemaps into your bundle file enabling you to debug.
See: https://stackoverflow.com/a/54548171/1829251
https://angular.io/guide/architecture#services
I'm following the docs on angular.io to inject dependencies like services, etc. I did everything they said and when I try to run it, the console keeps telling me:
Uncaught ReferenceError: LedgerService is not defined
I am doing nothing crazy except creating a simple component with a service where both constructors have console.log commands (constructors in both the component and service). I've done everything Angular says to do in their 2 paragraphs that details this feature of Angular.
The component itself is being injected into the main app module (with the service being injected into the component) and both the component and service were created with the Angular CLI. So there isn't much I've even done at all minus trying to inject the service. So I'm not sure where it is going wrong but it is definitely not working and just shows a blank page (when it previously had basic content by default).
I created both units, tried to specify providers in both the app.module and the component.ts file and neither works and yields the same error--when Angular claims either could work. I've also specified it as a private service within the constructor of the component.ts file.
Everything I've seen relating to this is always for Angular 1 or 2. Neither of which are even remotely similar to Angular 4/5.
If you really want to see this code, fine but it's literally just framework and nothing else:
bookkeeper.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-bookkeeper',
templateUrl: './bookkeeper.component.html',
styleUrls: ['./bookkeeper.component.css'],
providers: [LedgerServiceService]
})
export class BookkeeperComponent implements OnInit {
constructor(private service: LedgerServiceService) { }
ngOnInit() {
console.log("Ledger component works!");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { InterfaceComponent } from './interface/interface.component';
import { BookkeeperComponent } from './bookkeeper/bookkeeper.component';
#NgModule({
declarations: [
AppComponent,
InterfaceComponent,
BookkeeperComponent
],
imports: [
BrowserModule
],
providers: [
LedgerServiceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
ledger-service.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LedgerServiceService {
constructor() {
console.log("wtf");
}
}
LedgerService is actually called LedgerServiceService because I initially created LedgerService manually and then tried to use the AngularCLI to generate a service and named it LedgerService and it created a service called LedgerServiceService. Naming is not what is wrong. I only initially called it simply LedgerService because I figured it would be confusing.
Your examples are missing the import.
Anywhere we use a custom type, we also need to import that type.
For that reason, in both the module and component you will need to add:
import { LedgerServiceService } from './your-path-here'
You can see this in the examples they give on https://angular.io/guide/dependency-injection
In the below code from ../src/app/app.module.ts,
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
Component consists:
view(../src/app/app.component.html)
logic(../src/app/app.component.ts)
style(../src/app/app.component.css)
Angular application is a tree of components. Good components have high cohesion, i.e. each component contains only elements with related functionality. They are also well encapsulated and loosely coupled.
How modules are different from components?
A component is just a class with the #Component() annotation. Note that .html and .css files might be referenced by the component, certainly not mandatory. The component template might very well be 'inlined' directly in the component configuration, or there simply might not be any html template at all for a given component.
A module is a structural element of an Angular application (and maybe other classes and interfaces). It is also "just a class" with the #NgModule() annotation.
It acts as a logical 'container' for your components, directives, services, pipes, etc... to help you structure your overall source code better.
You can have a look at this existing question : What's the difference between an Angular component and module
A module is something that has components. It wraps them up so you can import and manage them.
Notice when you make a component you can put anything that's decorated as #Injectable in your constructor:
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
}
}
And magically you will have a myService to use. This is dependency injection, which is built into Angular - but it's managed on a Module level. In your module you import what other modules you want to be able to use:
imports: [
BrowserModule,
FormsModule
],
define what your module includes:
declarations: [
AppComponent,
HeroesComponent,
MyService
],
export any components (so other modules can import them)
exports: [
HeroesComponent
],
They help organize an application into blocks of functionality. Components are things that tell angular how to render something. Modules compose Components, Pipes, Services etc into 'blocks' that can be compiled by angular or imported and used by others.
Edit to address comment
Taking your specific question about HttpClient. The HttpClient is the service you are using to perform the actions. The HttpClientModule is the module you import into your module, so you can use the service it contains.
You import the module:
#NgModule({
imports: [
BrowserModule,
// Include it under 'imports' in your application module
// after BrowserModule.
HttpClientModule,
],
})
And use the service:
#Component(...)
export class MyComponent implements OnInit {
// Inject HttpClient into your component or service.
constructor(private http: HttpClient) {}
...
}
The HttpClientModule contains within it all you need for the HttpClient to work, and packages it up so you can use it in your own projects.
This particular module only wraps up that one service, but the module could contain a bunch of related services, components, pipes or directives. For example, the RouterModule allows you to use the RouterOutlet and RouterLink directives.
Module in angular is set of Components, Services, Filters, or some another smaller modules too, or we can say where you import all these in order to use later in the app for future use. in a single app there can be one or more than one module may exist.
Whereas, A component controls a patch of screen called a view.
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
Refer this guide for more details:
https://angular.io/guide/architecture
This question already has answers here:
Can't bind to 'ngForOf' since it isn't a known property of 'tr' (final release)
(38 answers)
Closed 3 years ago.
I am trying to follow the basic Angular 2 tutorial here:
https://angular.io/docs/js/latest/guide/displaying-data.html
I can get the angular app to load and display my name with this code:
import { Component, View, bootstrap } from 'angular2/angular2';
#Component({
selector: "my-app"
})
class AppComponent {
myName: string;
names: Array<string>;
constructor() {
this.myName = "Neil";
}
}
bootstrap(AppComponent);
However when I try to add an array of strings and try to display them with an ng-for, it is throwing the following error:
Can't bind to 'ng-forOf' since it isn't a known native property ("
<p>Friends:</p>
<ul>
<li [ERROR ->]*ng-for="#name of names">
{{ name }}
</li>
"): AppComponent#4:16
Property binding ng-forOf not used by any directive on an embedded template ("
<p>Friends:</p>
<ul>
[ERROR ->]<li *ng-for="#name of names">
{{ name }}
</li>
"): AppComponent#4:12
Here is the code:
import { Component, View, bootstrap } from 'angular2/angular2';
#Component({
selector: "my-app"
})
#View({
template: `
<p>My name: {{ myName }}</p>
<p>Friends:</p>
<ul>
<li *ng-for="#name of names">
{{ name }}
</li>
</ul>
`,
directives: [ NgFor ]
})
class AppComponent {
myName: string;
names: Array<string>;
constructor() {
this.myName = "Neil";
this.names = ["Tom", "Dick", "Harry"];
}
}
bootstrap(AppComponent);
What am I missing?
If you use alpha 52, check out the CHANGELOG.md in the GitHub repo. They changed the template to case-sensitive which is ngFor instead of ng-for (similar for all other directives)
Element names like <router-outlet> weren't changed though to stay compatible with custom elements spec which requires a dash in the tag name of custom elements.
In >= RC.5 (and final) ngFor and similar directives are not ambient by default. They need to be provided explicitly like
#NgModule({
imports: [CommonModule],
or if you don't mind the module being locked to be browser-only
#NgModule({
imports: [BrowserModule],
The BrowserModule exports CommonModule like also WorkerAppModule does.
Update
The BrowserModule should be imported in the app module, in other modules CommonModule should be imported instead.
With Angular 2.1.0+
It seems this is the same except you should import the BrowserModule in your app module and import CommonModule in others (you can't import BrowserModule twice with routes lazy-loading).
With Angular 2 rc5 :
This version introduced NgModules, you need to import BrowserModule in your module(s) in order to use ngFor, and ngIf:
BrowserModule registers critical application service providers. It also includes common directives like NgIf and NgFor which become immediately visible and usable in any of this modules component templates.
example:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
#NgModule({
imports: [BrowserModule],
providers: [],
exports: [],
declarations: []
})
export class MyModule { }
In Angular2 beta ng-for isn't correct. it should be *ngFor.
ngIf and ngFor are declared in CommonModule from #angular/common.
CommonModule contributes many of the common directives that applications need including ngIf and ngFor.
BrowserModule imports CommonModule and re-exports it. The net effect is that an importer of BrowserModule gets CommonModule directives automatically.
update your code as follow
import { CommonModule } from '#angular/common';
#NgModule({
imports: [CommonModule]
})
// In HTML
<li *ngFor="let customer of customers">{{customer.name}}</tr>
for more information Angular Module
The syntax for the ngFor directive is
<tr *ngFor="let name of names">{{name}}</tr>
Notice that is no longer #name of names as it was but let name of names and the ngFor requires the * and is case sensitive.
Behind the other answers, another possible cause is that you use some html formatter-repacker which converts all of your HTML - including the component templates - into lowercase.
The Angular template substitution is case sensitive for the ngFor and ngIf tags, at least today, but I can't say anything for sure for the next week.
Particularly webpack plugins, for example htmljs or html-minify work badly as their convert everything to lowercase on their default setting. Doublecheck the HTML code in the compiled text, it may be with all lowercase (like *ngif=...), which won't be accepted, even if in your original source is it correct!
Of course it breaks the HTML5 standard.
It happens because our most wonderful angular2 development thinks "they wish to follow html5 more closely", but there are always some surprising exceptions, making the work with angular2 always better and better.
It also might be caused by a typo. I just faced this problem I had
<div class="row" *ngFor="let order or orders">
As you see there is let order or orders instead of let order of orders
Be careful of the typo:
it's
*ngFor
not ng-for
not ngfor
not ng-For
Angular 8 Solution
Source Link
How to resolve this issue?
To resolve this issue we need to import BrowserModule in the application's main module i.e app.module.ts file and also import CommonModule in the child module.
So after imports, our files will look like these:
app.module.ts
// app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
...
...
#NgModule({
imports: [
BrowserModule,
....
....
child.module.ts
// child.module.ts
...
...
import { CommonModule } from '#angular/common';
#NgModule({
imports: [
CommonModule
...
...
Given that it has had so much success on the other issue marked as a duplicate of this one, here is a response of mine that has received a lot of upvotes:
Just for anyone who is missing it, I also had an issue where I typed ngif rather than ngIf (notice the capitol 'I').
My problem was caused by a missing export of the component containing the *ngFor. This component (MyComponentWithNgFor) was already imported and declared inside my SharedModule. The SharedModule also imported Angular's CommonModule, so everything looked fine.
However, I was using my component with the *ngFor in another module - let's call it ModuleB - which was importing SharedModule, so that I could use MyComponentWithNgFor.
My solution was simply to add my component containing the *ngFor to my SharedModule's exports array, like so:
#NgModule({
imports: [ CommonModule ],
declarations: [ MyComponentWithNgFor ],
exports: [ MyComponentWithNgFor ]
})
export class SharedModule { }
This made it possible for my ModuleB (which imports SharedModule) to use MyComponentWithNgFor.