Angular 6 AOT issue - can't pass function as argument - angular6

I'm unable to pass a function as an argument to a base class from a child class when trying to build using ng build --prod. The build works fine without the --prod flag, which looks to indicate an issue with AOT. The error I get is:
ERROR in : Can't resolve all parameters for AppGridComponent in
/src/app/components/core/shared/app-grid.component.ts: (?, [object
Object])
I found this SO thread which has several different answers for solutions, but I haven't been able to get any to work. It appears that AOT wants to inject this argument as a service and can't resolve (which I don't need since I am passing the function as a value from the child).
Base Class - app-grid.component.ts
import { Component, OnDestroy, OnInit } from '#angular/core';
import { GlobalsService } from '../../../services/globals.service';
#Component({})
export class AppGridComponent implements OnInit, OnDestroy {
constructor(protected loadDataCallBack: any, protected globalsService: GlobalsService) {
}
ngOnInit() {
this.init();
}
// get api data
public init() {
this.loadDataCallBack()
.subscribe(result => result);
}
Child class - rules.component.ts
const loadApiData = function() {
return this.productRuleService.get();
};
#Component({
selector: 'app-rules',
template: `<div class="grid-wrapper">Data here...</div>`
})
export class RulesComponent extends AppGridComponent implements OnInit, OnDestroy {
constructor(protected globalsService: GlobalsService, protected productRuleService: ProductRelationshipRuleService) {
super(loadApiData, globalsService);
}
Any suggestions on how to get this to build would be appreciated.

I was able to get this to work by creating a class that extends Function and then using this class as the provider in the component.
// Base Class - app-grid.component.ts
export class LoadDataCallBack extends Function {
}
#Component({
template: '',
providers: [{provide: LoadDataCallBack, useValue: () => {}}]
})
This ultimately satisfied the compiler and it is able to identify the type to inject into the first argument: loadDataCallBack.

Related

How to pass a function from a parent to a deep nested child and use an #input value into the passed function in Angular 8?

I have 3 components in this situation:
-OuterComponent
--MiddleComponent
---InnerComponent
I need to pass a function from OuterComponent to InnerComponent through MiddleComponent.
It is important to mention that the function I need to pass does take an input: DoSomething(node)
I don't know if it is relevant but I am already passing a NodeTree from the OuterComponent to the MiddleComponent and then I am unpacking the NodeTree into a Node and passing it InnerComponent. This Node is what I need to use as an input for the function being passed.
So, I need to be able to use an #Input as the input for the function being passed to the InnerCompoenent, which I assume will need to be an #output.
Method 1:
You can call the parent component function(OuterComponent) from the child component(InnerComponent) using #Output.
OuterComponent HTML:
<MiddleComponent (updateOuterComponent)="parentFunction($event)" />
OuterComponent TS:
export class OuterComponent implements OnInit {
constructor() {}
ngOnInit() {}
parentFunction(para) {
console.log(para);
// operations you want to do in parent component
}
}
MiddleWare HTML:
<InnerComponent (updateMiddleComponent)="middleFunction($event)" />
MiddleComponent TS:
export class MiddleComponent implements OnInit {
#Output() updateOuterComponent = new EventEmitter();
constructor() {}
ngOnInit() {}
middleFunction(para) {
this.updateOuterComponent.emit(para);
}
}
InnerComponent HTML:
It can be whatever you want to write
InnerComponent TS:
export class InnerComponent implements OnInit {
#Output() updateMiddleComponent = new EventEmitter();
constructor() {}
ngOnInit() {}
updateMiddleAndParent(para) {
this.updateMiddleComponent.emit(para);
}
}
Once you call updateMiddleAndParent function form Inner component using emitter, that will trigger middleFunction in the MiddleComponent. After triggering middleFunction, Similarly middleFunction will trigger parentFunction with the help of emitter.
Method 2:
You need to create a service and use it to call the parent function:
DataService:
import {BehaviorSubject} from "rxjs/BehaviorSubject"
export class DataService {
private state$ = new BehaviorSubject<any>('initialState');
changeState(myChange) {
this.state$.next(myChange);
}
getState() {
return this.state$.asObservable();
}
}
call DataService in both InnerComponent and OuterComponent:
In the OuterComponent call DataService and call getState(), this will return an observable whenever the value changes you can any function using data passed in observable response.
In the InnerComponent call DataService and use the changeState() to change the value.
once the value is changed in DataService, then in parent Component the value will be change as you are subscribed to the observable, You will get the updated data from there you can call any function in parent.

Property getter calling function can't be binded?

I have a model class with a property that returns a value by calling a method, but when i try to bind that property, there is result on the page, but also no error occuring.
export class TestClass {
testProperty: string = this.getString();
getString() {
return 'hello';
}
}
in html:
{{model.testProperty}}
Does Typescript / Angular not support this? What is the common way to do it?
This is a simple enough class. What you could do is initialize testProperty as null or by a default value and in ngOnInit() assign the returned value from the function.
import { Component, OnInit } from '#angular/core';
export class TestClass implements OnInit {
testProperty: string = null;
ngOnInut() {
this.testProperty = this.getString();
}
getString() {
return 'hello';
}
}
The ngOnInit() is a lifecycle hooks and runs when the component is initialized.
public get testProperty(): string {
return 'hello'
}
If you use the 'get' after the public, it allow the function to be called as it would be a normal variable. I think you shouldnt even need the 'model.'

Call static TypeScript function out of HTML

I want to call a static class method/function from out of my HTML in Angular 7. This function is not in the component.ts but in a separate general class file message.ts.
An error is displayed on the console :
TypeError: Cannot read property 'msg1' of undefined.
Template:
<div>
{{ Message.msg1({ 'x': 'abc', 'y': 'def' }) }}
</div>
message.ts:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class Message {
constructor() { }
public static msg1 (items: []): string {
// some code
}
}
Is what I want possible ? If yes, how can I get the message file (and so the Message class) in scope of the HTML?
Static methods are accessible on the class, not the instance injected by DI. If you want that template code to work, you'd have to do e.g.
import { Message } from ".../message";
#Component(...)
class Whatever {
Message = Message;
...
}
to make the class available as Message in the template scope.
That said, it's unclear why that method is static, or what the point of an injectable service with only a static method is.

null parameters from angular

I am trying to send parameters from my angular app using httpRequest.
I am getting back Null to my backend server.
I have checked with Postman and Fiddler both work with a json Object.
I have tried changing from Post to Get.
I am using Java RestAPI for the backend with apache Tomcat as the server.
This is my Service for login:
#Injectable({
providedIn: 'root'
})
export class LoginService {
private loginURL='http://localhost:8080/CouponSystemWeb/rest/loginpage/login'
constructor(private http:HttpClient) { }
public login(loginDetailes:LoginDetailes):Observable<LoginDetailes>{
return this.http.post<LoginDetailes>(this.loginURL,loginDetailes,{withCredentials:true})
}
}
This is my Login Component:
import { Component, OnInit } from '#angular/core';
import { LoginDetailes } from 'src/app/Entities/LoginDetailes';
import { LoginService } from 'src/app/services/login.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public loggedin:boolean;
public loggedClient:string;
public errormessage:string;
public loginDetailes = new LoginDetailes();
constructor(private loginservice:LoginService,private router:Router) { }
ngOnInit() {
this.loggedin=false;
}
public onLogin():void{
const observable=this.loginservice.login(this.loginDetailes);
observable.subscribe((returnedLoginDetailes:LoginDetailes)=>{
alert("Login Aquired");
this.loggedin=true;
if(this.loginDetailes.clientType=="ADMIN"){
this.router.navigate(['/crtComp']);
}
else if(this.loginDetailes.clientType=="COMPANY"){
this.router.navigate(['/login']);
}
else if(this.loginDetailes.clientType=="CUSTOMER"){
this.router.navigate(['/login']);
}else{
alert("Wrong Login Detailes");
}
}, err => {
this.errormessage=err.console.error("Wrong Detailes please Check Again!");
alert(this.errormessage);
}
)}}
This is the login Entity :
export class LoginDetailes{
public name:string
public password:string
public clientType:string
constructor(){
}
}
I have tried ngModel but that didn't fix the problem.
I have tried changing my backend from Post to Get.
The problem happends only in the angular App. I can send parameters with fiddler and Postman without problem.
Ok the answer was not in the component or the service.
the problem was in the HTML i was missing the ngModel two way data binding so my App was sending null's.

Angular View binding not updating with simple boolean

Goodday, This is probably a nooby question but I can't get it to work.
I have a simple service which toggles an boolean, if the boolean is true the class active should appear on my div and if false no class.. Simple as that. But the boolean gets updated, but my view doesn't react to it. Do I somehow have to notify my view that something has changed ?
Service:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class ClassToggleService {
public menuActive = false;
toggleMenu() {
this.menuActive = !this.menuActive;
}
}
View (left menu component):
<div id="mainContainerRightTop" [class.active]="classToggleService.menuActive == true">
Toggle point (top menu component):
<a id="hamburgerIcon" (click)="classToggleService.toggleMenu()">
This because you are changing a value on a service not on the component, so Angular don't need to update the component, because it did not change. If you want to update the view of your component when a service element is modified, you have to use an Observables and Subjects, and subscribe to them. In this way when the element is changed, it automatically notify all the subscribed components.
#Injectable({
providedIn: 'root'
})
export class ClassToggleService {
public menuSubject: Subject<boolean> = new BehaviorSubject<boolean>(false);
public menuActive = this.menuSubject.asObservable();
toggleMenu(val : boolean) {
this.menuSubject.next(val);
}
}
And in your component just implement OnInit interface and subcribe to the observable in the your service:
public localBool = false;
ngOnInit() {
this._myService.menuActive.subscribe(value => this.localBool = value);
}
ComponentToggleMenu() {
this._myService.toggleMenu(!this.localBool);
}
Then your html:
<div id="mainContainerRightTop" [class.active]="localBool">
<a id="hamburgerIcon" (click)="ComponentToggleMenu()">
Why we need service, this should be integrated with component class. As a general rule, you are not supposed to call service method in template file.
export class TestComponent implements OnInit{
public menuActive = false;
toggleMenu() {
this.menuActive = !this.menuActive;
}
}
Template:
<div id="mainContainerRightTop" [class.active]="menuActive">