Unable to use a selector of a sub-component in Angular - javascript

I want to "insert" task.component's view into my main app.component.html (root template) as follows:
(app.module.ts)
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { TaskComponent } from './task/task.component';
#NgModule({
declarations: [
AppComponent,
TaskComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
(app.component.ts)
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'planner';
}
(task.component.ts)
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-task',
templateUrl: './task.component.html',
styleUrls: ['./task.component.css']
})
export class TaskComponent implements OnInit {
constructor() { }
ngOnInit() {
console.log("Task comonent initialized!");
}
}
(app.component.html)
<!--The content below is only a placeholder and can be replaced.-->
<app-task></app-task>
<div style="text-align:center">
<h1>
Welcome to {{ title + 1 }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
So despite the fact that I have linked the task.component to the module I do not have access to its selector. Did I forget some import/export statements. Is that in fact a misunderstanding of angular's architecture/principle of structure?
The file task.component.html only consists of
<p>
task works!
</p>
Edit:
I also received the following error from the client's console:
[

What exactly shows in the place of the selector <app-task></app-task> that you added in app.component.html ?? What error in the console. This selector should work and be rendered to TaskComponent html view !!!!

To add a New Component to the Module that you're working on (which in your case is the AppModule), you first create a component(just use AngularCLI to do this by running the command ng g c task), and Angular CLI automatically adds it to your AppModule's declarations array. Then you can simply add the selector tag to your app.component.html to load that up
Just add <app-task></app-task> to your app.component.html
UPDATE
In some cases, even when you do everything properly, Angular doesn't recognise the Component that was added recently. Try breaking your local service by Ctrl + C on Windows or Cmd + C on Mac. And then run ng serve to serve up the App again. This generally happens when a Component is Added while the Server is running.
Here's a Sample StackBlitz for your ref just to cross check if you missed something.

I don't know what did you mean for linking components?
Following the structure that you shared it's working if you want see something, you must create the task-component.html because doesn't exist.
And the idea a component is that each component must has its logical indipendent to work.
And ways to share resources is using EventEmitters or binding properties.
This is the sceenshot that I saw and I can see the component created.

In fact restarting the server with ng serve did not solve the problem and therefore was not responsible for the missing interpolation of the component's template.
Rebuilding the app was the only (and ugliest) option for me which caused additionally work of course.
Delete all files of your project (all files in the layer in which amongst others node_modules is placed)
Setting up the project with ng new (...)
Building clean components with terminal commands (ng g c (...) / ng generate component (...))

Try re-running ng serve after stopping it. Hope you added component using Angular-Cli command -
ng generate component task

Related

Angular4/5 dependency injection docs not working

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

Angular 2: Rendering angular html components from webservice

I am looking for how to add html which is a return of the web service, in angular. The problem is that the angular directives do not rendered. here is my source code
//tohtml.directive.ts
import { Directive, ElementRef, OnInit } from '#angular/core';
#Directive({
selector: '[appToHtml]'
})
export class ToHtmlDirective {
constructor( private el: ElementRef) {}
tohtml() {
//it is assumed that this is the return of the webservice
this.el.nativeElement.innerHTML = '<a
[routerLink]="/link/to/page">helpful!
</a>';
}
}
Code for component.html
<div id="wrapper">
<h1 appToHtml>
Hello World!
</h1>
</div>
the code works, but the rendering of the [routerLink] does not work, pleaseee hellppp !!!
By setting innerHTML prop in your directive you only set DOM and attributes. But this content need to be compile by angular to allow angular-like behavior (binding directives, instanciating components etc..) .
Angular dont have compiler ready to use like angularJS ( which has $compile ). You need to use 3rd party libraries like
https://www.npmjs.com/package/p3x-angular-compile
or
https://www.npmjs.com/package/ngx-dynamic-template
Those lib comes with handy examples. You should easily understand how to use them.
Be aware that you cant use AOT with such a rendering system.
Edition for ngx-dynamic-template usage :
if your dynamic templates need some directive of component, you have to configure ngx-dynamic-template to import the corresponding modules.
You can create a dynamic module like that in your case
#NgModule({
imports: [
RouterModule
],
exports: [
RouterModule
]
})
export class DynamicModule {}
and then when importing ngx in your appModule or SharedModule
#NgModule({
imports: [
...
NgxDynamicTemplateModule.forRoot({extraModules: [DynamicModule]})
...
],
Then you will be able to use routerLink without problem (i just tested)
in cmpt :
htmlTemplate = `<a [routerLink]="['dress-options']">link to user component</a>`;
in template :
<div dynamic-template [template]="htmlTemplate"></div>
With the latest angular version for me only this module works fine: https://www.npmjs.com/package/ngx-dynamic-template
v2.1.24 for angular4, v.2.3.0 is for angular5

The selector "relative-path" did not match any elements

I am following the component-relative paths angular documentation.
Per the instructions, I am keeping my component ts and component html in the same directory. For the purpose of this question, that directory is /app/components/first
My component ts contains the following code, and is named First.component.ts
import {Component, Injectable} from '#angular/core';
import {MyService} from "../../service/MyService";
import {ValueObj} from "../../value/ValueObj";
#Component({
moduleId: module.id,
selector: 'relative-path',
templateUrl: 'First.component.html',
providers: [MyService]
})
#Injectable()
export class FirstComponent {
public valueObjs: ValueObj[];
constructor(private _myService: MyService) {}
getAllItems(): void {
this._myService.getAllValueObjs().subscribe(
data => this.valueObjs= data, error=> console.log(error),
() => console.log("getting complete"));
}
}
My First.component.html contains the following code:
<form (ngSubmit)="getAllItems()">
<label>Value Objects</label>
<button type="submit">Search</button>
</form>
<hr>
<p style="color:red">{{error}}</p>
<h1>All Objects</h1>
<div *ngFor="let valueObj of valueObjs">{{valueObj.name}}</div>
I have looked at this solution, The selector "my-app" did not match any elements , however, I do not find it applicable. My main.ts file only contains this:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
// start the application
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
and has no reference to BrowserModule. I also looked at why getting the error "The selector did not match any elements"? , however, I have no boot.ts file to compare my values.
Lastly, I have looked at Angular2 CLI build EXCEPTION : The selector "app-root" did not match any elements , however, I have no reference to angular-universal in my packaging.json.
Any idea as to what I am doing wrong?
I just had the same issue, the example is a bit confusing. The line:
selector: 'relative-path',
is just an example name of your component, it is not a command to use relative paths.
Simply adding the moduleId line will make relative paths work, so you can leave your selector as "first-component" or whatever you had before.
The error message is actually trying to say that the saying that the selector you have now ("relative-path") does not match what is in the index.html file. This only happens when you change the component that is in the bootstrap entry in app.module. If you had the same issue with a non-bootstrap module, you get a much clearer error message.

Angular 2, share an object between two components that have no direct relationship

I have an app that is structured like this.
<app>
<header>
<component-a></component-a>
</header>
<div>
<router-outlet></router-outlet>
<component-b></component-b> <!-- loaded through router -->
</div>
</app>
In component-b some data is retrieved and later set to a new object. For example, something like this..
{
infoThatComponentANeeds : true,
someMoreInfoAddedFromCompB : []
}
This info is needed for the template in component-a. At first I tried to pass the info up to component-a via #Outuput and eventEmitter using a custom event. But I was unable to get it to bubble up. I suspect that has to do with it being loaded through the router. So now I am trying to share the data between the two components using a shared service.
My Service So Far:
import {Injectable} from 'angular2/core';
#Injectable()
export class SharedService
{
public spec:Spec= null;
public getSpec()
{
return this.spec;
}
public setSpec(spec:Spec)
{
this.spec = spec;
}
}
This is how I am trying to use it in component-a:
ngDoCheck()
{
if(this._sharedService.spec)
{
this.spec= this._sharedService.getSpec();
}
}
The Problem:
After the spec is set in component-b and ngDoCheck from component-a checks to see if the spec has been set. It comes back as undefined so the getSpec() function does not run, and no spec is returned. So I am not sure what I am missing, or why it would still be undefined in my SharedService after it has been set. Should the shared service keep a reference to what was set? Or am I completely misunderstanding this concept?
I have also explored ways of sharing this data via promises/observables. However I have not had any luck with that either. And the majority of the examples I have found use HTTP, which I really do not need at this point.
Update:
Here is some more info.
Boot.ts
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {
ROUTER_PROVIDERS,
APP_BASE_HREF,
Location,
LocationStrategy,
HashLocationStrategy,
PathLocationStrategy
} from 'angular2/router';
import {AppComponent} from './components/app.component';
import {SharedService} from './services/shared.service';
bootstrap(<any>AppComponent, [
ROUTER_PROVIDERS,
SharedService,
provide(LocationStrategy, {useClass: PathLocationStrategy})
]);
AppComponent.ts
import {AfterViewInit, Component, OnInit} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {ComponentA} from './componentA';
#Component({
selector : 'body',
directives : [ComponentA, ROUTER_DIRECTIVES],
template : `
<app>
<header>
<component-a></component-a>
</header>
<div>
<router-outlet></router-outlet>
</div>
</app>
`
})
#RouteConfig([
{path: '/:appName/', name: 'ComponentB', component: ComponentB}
])
export class AppComponent
{
constructor(){}
}
Update 2:
Here is a plunker I created to try to isolate the issue. I removed the router stuff and simplified the whole thing. I am still seeing the same result..
https://plnkr.co/edit/kx6FWWGS1i04bH5J9DXM?p=preview
Watch the console.log()
Fixed:
This was the key.
Be sure to remove configurations in the providers attribute of your
two components.
Perhaps your service isn't actually shared. I mean you could have two instances according to the way you configured providers.
To be sure, just add the service when bootstrapping your application:
bootstrap(AppComponent, [ SharedService ]);
Be sure to remove configurations in the providers attribute of your two components.
If you're interested in hierarchical injectors of Angular2 (the concept behind this), you could have a look at this question:
What's the best way to inject one service into another in angular 2 (Beta)?

angular 2 beta ngFor not working in javascript [duplicate]

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.

Categories