I am new to angular I have a class level variable in my angular component called moratoriumID. I call a method which calls a POST and then assigns a number to moratoriumID that is returned from the POST . I believe this works as intended, as I see the number show up in the chrome debugger console . Later on I try to access the variable and use it. It says its undefined. Why ? What am I not understanding ? How can I use the moratoriumID later in code ? Any explanation would be most appreciated. --Jason
export class AddMoratoriumsComponent implements OnInit {
moratoriumID: number;
//this gets called and assigns the moratoriumID from what I see
PostMoratorium(moratoriumtopost: Moratorium):void {
this.moratoriumService.PostMoratorium(moratoriumtopost)
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe((data) => (this.moratoriumID) = (data),
(error) => (console.log(error)),
() => console.log('Post moratorium is complete', this.moratoriumID),
);}
//...I call it
this.PostMoratorium(moratoriumtopost);
//Later I try to use moratoriumID but it says its undefined ...why ?
if (this.selectzipvalues.length>0){
const res = this.isoLocs.filter(i => this.selectzipvalues.includes(i.zipCode));
res.forEach(myFunction);
function myFunction(item) {
const moratoriumlocationstopost = {
county:item.county ,
city:item.city,
zip:item.zipCode,
moratoriumId:this.moratoriumID, //IT SAYS ITS UNDEFINED ..WHY ?
} as MoratoriumLocation;
}}
Answer seems to be be to use switchMap().
Related
const BasicFunctionalComponent = props => {
return (
<div>
{constantVariable}
</div>
)
}
export default BasicFunctionalComponent
const constantVariable = '**how I am initialized**?'
in example above I just create a basic functional component and after exporting it just initialized a constant variable set as a string. then I used it inside JSX above expected to go throw error 'Cannot access 'constantVariable' before initialization'. but all's good
Because BasicFunctionalComponent will get called much later. It's basically an asynchronous function from the perspective of this file you showed us. By the time that function is called, constantVariable will be defined.
Let's start with a much more clear example:
const fx = () => {
console.log(v)
}
// fx() // Call it here and it throws error
const v = 1
// fx() // Call it here and it's ok
console.log('Fin!')
The reason behind why it does not throw ReferenceError is basically because the component function is not called before the initialization of the constantVariable.
I have a function that I use to handle pagination in my Angular app. It was working as expected - I subscribe to the url params and then use the router to navigate according to those params while taking in the page number as a passed in value. One param is a boolean indicating whether the filter is currently active, and the second param is the value(s) itself for the filter.
This is the working version:
public paginate(page) {
this.route.params.subscribe(
(params: any) => {
this.pn_location_e = params['pn_location_e'];
this.pn_location_v = params['pn_location_v'];
}
);
this.router.navigate(
['/clients', {
page: page,
pn_location_e: this.pn_location_e,
pn_location_v: this.pn_location_v,
}]);
let fn = resRecordsData => {
this.records = resRecordsData;
let data = resRecordsData.data;
};
this.dataService.filterByInput(
page - 1, this.pagesize, this.location, fn);
}
Everything above was working as expected.
However, recently a colleague changed the filter syntax from using an "_" to using a ".". So it went from this:
this.pn_location_e = params['pn_location_e'];
to this:
this.pn_location.e = params['pn_location.e'];
The problem is, in my Angular component I can't initialize the variable with that syntax. When I try and initialize like this:
pn_location.e
... I get a syntax error. I also tried doing this pn_location['.e'], but that also won't work (also causes a syntax error).
Is there a way around this? Or do we just need to go back to using the underscore syntax for our filters params?
Surrounding the property names with quotes will allow the assignments:
public paginate(page) {
this.route.params.subscribe(
(params: any) => {
this.pn_location_e = params['pn_location.e'];
this.pn_location_v = params['pn_location.v'];
}
);
this.router.navigate(
['/clients', {
page: page,
'pn_location.e': this.pn_location_e,
'pn_location.v': this.pn_location_v,
}]);
}
I am learning Angular2, following the "Tour of Heroes" tutorial on Angular.io. Near the end of the tutorial, we set up routing to a detail page and pass a parameter indicating the hero to displace. This is handled using the params Observable in ActivatedRoute. We use switchMap to redirect from the params Observable to a Promise to return the data we actually want based on the parameter.
The syntax used in the tutorial is concise, so I tried to break it out into building blocks to get a better understanding of what is going on. Specifically, I have tried to replace right arrow notation with an actual function, that I think is identical. But my modification does not work.
Here is the code:
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => this.heroService.getHero(+params['id']))
//.switchMap(this.getHero)
.subscribe(hero => this.hero = hero);
}
getHero(params: Params) : Promise<Hero> {
return this.heroService.getHero(+params['id']);
}
What confuses me is why using the line that is currently commented out instead of the line above it, I get an error: "Cannot read property 'getHero' of undefined." The two versions of code look identical to me.
Fat-arrow function preserves the context of execution, allowing the this "variable" to be the same as in the parent scope. If you use .switchMap(this.getHero) then this will point to something else, not the component.
getHero(params: Params) : Promise<Hero> {
// "this" is not what you expect here
return this.heroService.getHero(+params['id']);
}
So this.heroService is undefined here.
You'd need to bind your getHero function.
.switchMap(this.getHero.bind(this))
Otherwise your change is identical. Using bind like this allows you to pass getHero as a standalone function to switchMap without losing what this means to it.
You can experiment with it:
'use strict';
const foo = {
bar: 'baz',
getBar: function() {
return this.bar;
}
};
foo.getBar();
// => 'baz'
const myGetBar = foo.getBar;
myGetBar();
// => TypeError: Cannot read property 'bar' of undefined
const boundGetBar = foo.getBar.bind(foo);
boundGetBar();
// => 'baz'
const otherObj = { bar: 'hi' };
const otherBoundGetBar = foo.getBar.bind(otherObj);
otherboundGetBar();
// => 'hi'
otherObj.getBar = myGetBar;
otherObj.getBar();
// => 'hi'
You cannot use this.getHero like in your snippet because
it's undefined (the service returns Observable that you have to subscribe before using its data)
it's not a property (doesn't have get modifyer).
I am try to make a logging service for my TypeScript / Angular 2 App. Unfortunately if i call console.log the line number is wrong. Even if i try to return console.log().
Here is my code:
LoggerService.ts
export class LoggerService {
log(message) {
// Server-side logging
// [...]
if (clientSideLogging) return console.log(message);
}
}
SomewhereElse.ts
this.logger.log('hello world');
-> Shows line number of LoggerService.ts instead of source
You could use the .bind() method to bind window.console to your custom log method and then return the function so that the code is executed within the original scope when it is called.
In doing so, the line number will be preserved when calling the logger service's log method:
class LoggerService {
public log = console.log.bind(window.console);
}
// ...or annotated:
class LoggerService {
public log: (message) => void = console.log.bind(window.console);
}
Then if you want to add in your conditional statement:
class LoggerService {
public log = clientSideLogging ? console.log.bind(window.console) : () => {};
}
Here is an example with the compiled TypeScript code.
Aside from the one-liner solutions mentioned above, if you want to implement additional logic inside of the log method, then you could utilize a getter which will return and call the console.log function that is bound to window.console.
class LoggerService {
public get log (): Function {
// Implemnt server-side logging
return console.log.bind(window.console);
}
}
As you can tell, it is important for the console.log function to be returned since it will not preserve the line numbers when it is called directly within another scope.
Then if you want to add in your conditional statement:
class LoggerService {
public get log (): Function {
const log = console.log.bind(window.console);
// Implemnt server-side logging
return clientSideLogging ? log : () => {};
}
}
Here is an example with the compiled TypeScript code.
You could use .trace() instead of .log().
this.logger.trace('hello world');
This will give you a stack trace to the original line number.
https://developer.mozilla.org/en-US/docs/Web/API/Console/trace
I am using angular2 with typescript and i have defined a class
export class Example{
//.../
const self: all = this;
functionToCall(){
//.. Do somerthing
}
mainFunctionCall(){
somepromise.then(x => self.functionToCall('url/'+ x.name ) )
}
}
But it keeps throwing error about functionToCall being undefined.
Im quite new to typescript/angular#
is there any rule that prevents this to be correct? Or what is the correct way to invoke method of class inside another method ?
No need for such a hack here, since lambda functions capture the this reference of the outer scope. You can just simply write:
const somepromise = Promise.resolve({name:"noone"});
class Example {
functionToCall(x : string) {
console.log(x);
}
mainFunctionCall() {
somepromise.then(x => this.functionToCall('url/'+ x.name ) )
}
}
(new Example()).mainFunctionCall();
Edit Code snippet updated to include all details. Can be run in the typescript playground.