Angular programmatic navigation - Why router does not in providers array - javascript

In Angular Dependency Injector when ever we injecting a Type , we will includes them in providers array (May be in #NgModule decorator or #Component decorator. But in the following instance when we navigate programmatically we inject Router instance to constructor, But we don't provide in providers array as normally we do in Angular Dependency Injector.
What is the different here than Angular Dependency Injector ? for your reference I will attach both code
Programmatic Navigation - Code
import { Router } from '#angular/router';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private router:Router) { }
ngOnInit() {
}
onLoadServer(){
this.router.navigate(['servers']);
}
}
Angular Dependency Injector way - Code
import { Component,Input} from '#angular/core';
import { LoggingService } from '../logging.service';
#Component({
selector: 'app-account',
templateUrl: './account.component.html',
styleUrls: ['./account.component.css'],
providers:[LoggingService]
})
export class AccountComponent {
#Input() account: {name: string, status: string};
#Input() id: number;
constructor(private logginService:LoggingService){
}
onSetTo(status: string) {
this.logginService.loggingStatusChange(status);
}
}

RouterModule.forRoot already injects Router in root injector, thats why you don't have to include it in providers array any where. you can read about it here :-
https://angular.io/api/router/RouterModule#forroot

Related

Angular - trying to use child component function in parent view but I'm gettting an error

When I use #ViewChild I get the error that the component is not defined.
When I use #ViewChildren I get the error that the function from that component is not a function.
I am new to using child components in Angular so I'm not sure why it's doing this when I do have the child component defined in the parent component and when it's clearly a function in the child component.
I don't want to have to define every function from the child in the parent or else what's even the point of using a separate component.
Child Component
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-mood',
templateUrl: './mood.component.html',
styleUrls: ['./mood.component.css']
})
export class MoodComponent implements OnInit {
moodColors = ['red', 'orange', 'grey', 'yellow', 'green'];
constructor() { }
ngOnInit(): void {
}
chooseMood() {
alert(this.moodColors);
}
}
Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood is undefined")
import { Component, OnInit, ViewChild, ViewChildren } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { MoodComponent } from '../mood/mood.component';
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css'],
encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {
#ViewChild('mood') mood: MoodComponent = new MoodComponent;
Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood.chooseMood is not a function")
import { Component, OnInit, ViewChild, ViewChildren } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { MoodComponent } from '../mood/mood.component';
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css'],
encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {
#ViewChildren('mood') mood: MoodComponent = new MoodComponent;
Parent View
<h2 (click)="mood.chooseMood()"></h2>
You don't explicitly initialize view children via new.
Just use:
#ViewChild('mood') mood : MoodComponent;
If that doesn't work post a Stackblitz example which I can edit to resolve the issue.
Also, using ViewChild is more of an exception in Angular, and your use of it points to a probable design issue. More likely you child component should emit via an Output to the parent.
Regarding outputs, you can do something like this - though it is hard to give a precise answer without deeper knowledge of what you are trying to achieve:
export class MoodComponent implements OnInit {
#Input() moodId: string;
#Output() chooseMood = new EventEmitter<string>();
moodClicked(){
this.chooseMood.emit(moodId);
}
}
export class CalendarComponent implements OnInit {
moodChosen(string: moodId){
console.log(moodId);
}
}
// Calendar template:
<app-mood
moodId="happy"
(chooseMood)="moodChosen($event)"
></app-mood>
1 - you have to use this code
#ViewChild('mood') mood : MoodComponent;
when you are using #ViewChildren it will return list of items with the 'mood' name then you have to use this code
mood.first.chooseMood() ;
its better use ViewChildren when there is ngIf in your element
2- no need new keyword for initialize mood variable
it would be fill after ngOnInit life cycle fires

Problem calling one Angular component from another component

At work, I have run into a problem using Angular. I have this kind of Angular component:
#Component({
selector: 'foo',
templateUrl: 'foo.html'
})
export class FooComponent {
#Input() data: string;
content: string;
ngOnInit() {
this.content = this.data;
}
setValue(data) {
this.content = data;
}
}
This is initialized from my main Angular component in a code block such as this:
this.components = [FooComponent, BarComponent, BazComponent, QuuxComponent];
Now this works so far. But if I try to call the setValue() function with this.components[0].setValue("Hello world!"); I get an error "this.components[0].setValue is not a function."
What is the reason for this and how can I fix it?
This seems like a very very weird way to work with components in angular.
You really don't want to break encapsulation by calling methods inside one component from another component.
I personally haven't seen this kind of component referencing anywhere (and have doubts it is a correct approach).
There is no reason to duplicate the data property in the content.
You can pass values in the template. Or use a service if you don't have direct access to the template.
Here is a very basic example on how to modify data from the parent using a template and #Input.
app.component.ts
import { Component } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
message = "I am a message from the parent";
}
app.component.html
<app-child [content]='message'></app-child>
child.component.ts
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-child",
templateUrl: "./child.component.html",
styleUrls: ["./child.component.css"]
})
export class ChildComponent implements OnInit {
#Input("content") public content: string;
constructor() {}
ngOnInit() {}
}
child.component.html
<p>{{content}}</p>

Angular app is compiling successfully but giving errors property does not exist in 'ng build --prod'

Angular app is compiling successfully but giving the following errors in 'ng build --prod'
ERROR in src\app\header\header.component.html(31,124): : Property 'searchText' does not exist on type 'HeaderComponent'.
src\app\dashboard\dashboard.component.html(3,72): : Property 'newsService' is private and only accessible within class 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(3,72): : Property 'p' does not exist on type 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(29,46): : Property 'p' does not exist on type 'DashboardComponent'.
I have used these properties in my html file as below:
header.component.htmlfile
<input type="text" class="form-control mr-2 align-self-center" required placeholder="Search" name="searchText" [ngModel]="searchText" value="">
dashboard.component.htmlfile
<pagination-controls class="text-center" (pageChange)="p = $event"></pagination-controls>
my header.component.html file
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation } from '#angular/core';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
filterText : string;
#Output() search = new EventEmitter();
#Output() filterButton = new EventEmitter();
constructor() { }
ngOnInit() {
}
onSubmit(form : NgForm)
{
console.log(form);
this.search.emit(form);
}
filterClicked($event)
{
this.filterText = $event.target.text;
this.filterButton.emit(this.filterText);
}
}
my dashboard.component.html file
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { NewsService } from '../shared/news.service';
import { NewsModel } from '../shared/news.model';
import { Form } from '#angular/forms';
import { Pipe, PipeTransform } from '#angular/core';
import { element } from 'protractor';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
articles : any;
temp : NewsModel = new NewsModel;
constructor(private newsService : NewsService) { }
ngOnInit() {
this.FetchHeadlines();
}
FetchHeadlines()
{
this.newsService.GetAllGaurdian()
.subscribe((result) =>
{
this.articles = result;
this.articles.response.results.forEach(element => {
this.newsService.newsArticles.push(this.newsService.CusotomMapper(element));
});
})
}
}
can't able to figure out where is the error exactly!
I think the error descriptions are as accurate as it can be. each of them tells you that something wrong with your component, lets examine each of them
ERROR:
ERROR in src\app\header\header.component.html(31,124): : Property 'searchText' does not exist on type 'HeaderComponent'.
you have searchText in HeaderComponent HTML, but not in the Component itself
SOLUTION: add searchText variable to the Component
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
searchText:string
...
}
ERROR :
src\app\dashboard\dashboard.component.html(3,72): : Property 'newsService' is private and only accessible within class 'DashboardComponent'.
all the fields you are using inside the template, must be the public field inside component itself, otherwise it will not compile
SOLUTION: change private modifier to public at newService
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor(public newsService : NewsService) { }
...
}
ERRORS :
src\app\dashboard\dashboard.component.html(3,72): : Property 'p' does not exist on type 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(29,46): : Property 'p' does not exist on type 'DashboardComponent'.
same as HeaderComponent. you are using p field but it's not defined in DashboardComponent
SOLUTION : add p field to the dashboard component
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
p:any
...
}
You are trying to access from the template, variables that aren't defined in the corresponding components.
In header.component.html you are setting [ngModel]="searchText" and variable searchText isn't defined on header.component.ts. Could it be filterText variable instead?
In dashboard.component.html you are setting p = $event and variable p isn't defined on dashboard.component.ts. You also have an error about newsService being private. If you are gonna use it in the template it must be declared public when you inyect it on the constructor. I hope this helps. If you need more help is better if you provide a Stackblitz with minimum code.

Angular9: Import of service not found in component

I've created a service that I use in 2 separate components from the same module.
The service has a few imports and is somewhat normal.
import { CdkPortal } from "#angular/cdk/portal";
import { ElementRef, Injectable } from "#angular/core";
import { Subject, Subscription } from "rxjs";
#Injectable()
export class TestService {...}
I've added the service into the module into the providers array as well as both components where the service is needed.
The first component uses the service with no issue.
import { FlyoutService } from "../flyout.service";
#Component({
selector: "test-uno",
templateUrl: "./test-uno.component.html",
styleUrls: ["./test-uno.component.scss"],
})
export class TestUnoComponent implements OnInit, OnDestroy, AfterViewInit {
constructor(private flyoutService: FlyoutService) {...}
}
The second component, that uses the service in what I think is the same way, fails.
import { FlyoutService } from "./../flyout.service";
#Component({
selector: "test-dos",
templateUrl: "./test-dos.component.html",
styleUrls: ["./test-dos.component.scss"],
animations: [...],
})
export class TestDosComponent implements OnInit, OnChanges, OnDestroy {
constructor(private flyoutService: FlyoutService) { }
}
The second component fails in the browser with the error:
Export of name 'CdkPortal' not found.
This only happens when buildOptimizer is set to true on the build. Any idea what's going on?

Angular 4+ send service from child to parent via interface

I was searching for answer several hours..
Is possible in angular to send from child to parent service via interface?
parent component
child component (extends parent)
interface for service
service (e.g. locationService) (implementing iface above)
Child extends from Parent
constructor(public locationService: LocationService) {
super(locationService); //parent
}
And parent looks like:
constructor(generalService?: IService) {
this.myService = generalService;
}
and than I want to do something like: this.myService.doLogic();
I got runtime error: Error: Uncaught (in promise): Error: Can't resolve all parameters for ParentComponent: (?).
Thanks for any hint or help..
The best way to design component inheritance in Angular framework is passing Injector instance to base component and injecting dependencies in the base component.
Base component class implementation:
export class BaseComponent {
protected locationService: LocationService;
constructor(injector: Injector) {
this.locationService = this.injector.get(LocationService);
}
}
Child component:
import { Component, Inject, Injector } from "#angular/core"; // Import injector from #angular/core
#Component({
selector: "child-component",
templateUrl: "child-component-template.html",
styleUrls: [
"./child-component-styles.scss"
]
})
export class ChildComponent extends BaseComponent{
constructor(
#Inject(Injector) private injector: Injector
) {
// Pass injector instance to base class implementation
super(injector);
}
}
Now in the child component you can use LocationService by calling this.locationService.doSomethind();
You should not have to extend Component, By extending component it brings only class property. So change parent from Component to simple class.
interface IService {
doLogic();
}
#Injectable()
export class LocationService implements IService {
doLogic() {
console.log('service goes here...');
}
}
export class ParentComponent {
constructor(public locationService?: IService) {
}
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent extends ParentComponent {
constructor(locationService: LocationService) {
super(locationService);
this.locationService!.doLogic();
}
}

Categories

Resources