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.
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 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().
I am writing an ESLint rule for a plugin. I have the following test code:
const test = require('./test');
module.exports.foo = class Foo {}
module.exports.test = class Test {}
I have the following rule:
module.exports = {
create: (context) => ({
CallExpression: (node) => {
// The callee must be `require`.
if (node.callee.name !== 'require') {
return;
}
// Must be part of a VariableDeclarator.
if (node.parent.type !== 'VariableDeclarator') {
return;
}
const variable = node.parent.id;
if (variable.type !== 'Identifier') {
return;
}
// Now that we have the variable part of the expression `const name =
// require('name');`, find any identifiers in the code where the
// uppercased version of the `variable` is used.
}
})
}
So as you can see, in the CallExpression, I find the require('./test'); to get the test variable name. What I then want to do, as indicated by the final comment in the above code, is to find the class called Test. I don't know how to do this. I tried the following, but it doesn't work:
const scope = context.getScope();
const capitalizedName = variable.name.charAt(0).toUpperCase() + variable.name.slice(1);
// `undefined` is returned. Why? Shouldn't it find the `Test` class, even if it's exported?
const classVariable = scope.variables.find(variable => variable.name === capitalizedName)
if (!classVariable) {
return;
}
const foundClassVariable = classVariable.references.find(({ identifier }) =>
['ClassDeclaration', 'ClassExpression'].includes(identifier.parent.type),
);
Yet it works for the following test code (when the class isn't exported):
const test = require('./test');
class Test {}
Anyone know how I can get this to work? Is it possible the problem is with the scope I'm using, and if so, how can I get all the identifiers defined at the document root, to search all of them?
Here's what I basically ended up doing:
const scope = context.getScope();
const capitalizedName = variable.name.charAt(0).toUpperCase() + variable.name.slice(1);
const hasFoundClassVariable = scope.childScopes.some(childScope => childScope.type === 'class' && childScope.variables[0].name === capitalizedName)
The guide here did help, as you would imagine, since it's the official docs.
You have a class expression there, Test is just the name of the class that can be used inside the class to reference it, it is not associated to a variable like a class declaration is. So in other words: There is no easy way to get that class, you have to manually search through all nodes of the AST and find a class expression that has the name Test.
create: (context) => {
// initialize local variables, e.g. the class names to look for
return {
CallExpression: (node) => {
// register class names
},
ClassDeclaration(node) {
// check class declaration
},
ClassExpression(node) {
// check class expression
},
};
},
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'm using jQuery for some things in my angular2 projects. But I can't manage to use variables I've declared in angular2 to use in jQuery. I have something like this:
export class AddExerciseComponent implements OnInit {
parameters:Array<string> = ["FU"];
constructor() { }
ngOnInit() {
$('.chips').on('chip.add', function(e, chip){
this.parameters.push(chip.data);
console.log(this.selectedValue);
});
}
This would get me an error that parameters is not defined. I guess it's because I use this. What else can I do?
You need to use an arrow function expression (() => {}) to keep this in scope. Try:
export class AddExerciseComponent implements OnInit {
parameters:Array<string> = ["FU"];
constructor() { }
ngOnInit() {
// removed function keyword and added () => {} syntax
$('.chips').on('chip.add', (e, chip) => {
this.parameters.push(chip.data);
console.log(this.selectedValue);
});
}
When you passed your callback as a regular old function, JavaScript doesn't consider your callback to be within the scope of the calling function, leaving this unusable for calling data from the scope you thought you were in. By using an Arrow function, the scope is saved and this is usable for accessing data as expected.
If you are looking to use angular variables in jquery animate ON-Complete function call back,that's how you do it:
$('#myDiv').animate({top: 70+"%"},{
queue: false,
duration: 1000,
complete: () => {
//this is you angular variable of the class
this.angularVar = 0;
$("#myDiv").hide();
//this is you angular variable of the class
this.showAnimation = false;
//this is you angular class function
this.angularFunction();
console.log("animation complete");
}
});
Assign angular's this(instance) to Jquery's this(instance) to use the angular variable inside JQuery
let jQueryInstance = this; // This line will assign all the angular instances to jQueryInstance variable.
$('.chips').on('chip.add', (e, chip) => {
/* this.parameters.push(chip.data); */
// Instead of the above line we have to use like below
jQueryInstance.parameters.push(chip.data); // instead of "this", "jQueryInstance" is used
// console.log(this.selectedValue);
console.log(jQueryInstance.selectedValue);
});