Success gets called in a successful factory response in the then callback:
This doesn't work, it cannot find response:
this.storeFactory.getSafes().then(success(response), failure());
How to I pass the response to the success function correctly?
var success = (response: any): void => {
scope.safes = response.data.safes;
localStorage.setItem('safeCount', scope.safes.length);
this.$http.get('/app/dashboard/safes/safes.html', { cache: this.$templateCache }).success((tplContent): void => {
element.replaceWith(this.$compile(tplContent)(scope));
});
}
The long hand version works fine, but I feel like it is very messy.
this.storeFactory.getSafes().then((response: any): void => {
scope.safes = response.data.safes;
localStorage.setItem('safeCount', scope.safes.length);
this.$http.get('/app/dashboard/safes/safes.html', { cache: this.$templateCache }).success((tplContent): void => {
element.replaceWith(this.$compile(tplContent)(scope));
});
}
How to I pass the response to the success function correctly?
You don't. You pass the success function to the then method, then the promise will pass the result value to your success function. That's how callbacks work.
All you need to do is declare response as a paramter of your function. You must not call the function yourself - you only should pass it as a callback:
this.storeFactory.getSafes().then(success, failure);
Also you will need to define the functions before you pass them to then. If you only declare them, and pass undefined values to then, they will be ignored. Use
var success = (response: any): void => {
scope.safes = response.data.safes;
localStorage.setItem('safeCount', scope.safes.length);
this.$http.get('/app/dashboard/safes/safes.html', { cache: this.$templateCache }).success((tplContent): void => {
element.replaceWith(this.$compile(tplContent)(scope));
});
};
var failure = (): void => {
this.$http.get('/app/shared/mocks/tableError.html', { cache: this.$templateCache }).success((tplContent): void => {
element.replaceWith(this.$compile(tplContent)(scope));
});
}
this.storeFactory.getSafes().then(success, failure);
However, arrow functions are actually supposed to be defined inline, without assigning them to a specific variable. (You called this the "long hand version" in your question, even if it's actually shorter). Just use that and you won't face these problems.
In general, I would recommend to avoid defining functions in variable assignments completely. If you need a variable, just use a declaration instead (Typescript syntax should not vary much).
I can't speak to the ES2015 syntax or Typescript, however the way you're passing back your success callback looks suspect.
instead of
this.storeFactory.getSafes().then(success(response), failure());
you should use
this.storeFactory.getSafes().then(success, failure);
The callback of your AJAX call also needs to use arrow functions:
this.$http.get('/app/dashboard/safes/safes.html', { cache: this.$templateCache }).success((tplContent) => {
element.replaceWith(this.$compile(tplContent)(scope));
});
Related
I am really new to Angular and Typescript.
I have this function right now
createTranscriptionJob(fileToUpload: File, language: string): Observable<void> {
this.getSasUrl(fileToUpload.name, language, ldapUserName)
.subscribe(response => {
const test = this.upload(response.sasUrl, fileToUpload);
console.log(test);
});
return of();
}
First problem currently is that the createTranscriptionJob function is returning basically nothing.
Second problem is that the createTranscriptionJob function is returning before the completion of the inner upload function call.
Question
I would need the createTranscriptionJob function to return the result of the upload function. How to achieve that?
Something like that, but it's complaining:
You'll need to chain your observables with an operator like switchMap.
Doing so, you will need the called to do the subscribe.
createTranscriptionJob(fileToUpload: File, language: string): Observable<void> {
return this.getSasUrl(fileToUpload.name, language, ldapUserName)
.pipe(
switchMap(() => this.upload(response.sasUrl, fileToUpload)
)
);
}
You can use alse the async/await pattern:
async createTranscriptionJob(fileToUpload: File, language: string) {
var response = await this.getSasUrl(fileToUpload.name, language, ldapUserName).toPromise();
// this line depends on the reponse type of upload method (toPromise() must be added if is an observable)
const test = await this.upload(response.sasUrl, fileToUpload);
console.log(test);
return test;
}
I need to type handleFoo with MyType['foo'].
type MyType {
foo: () => void
}
const Comp: React.FunctionComponent<{}> = () => {
function handleFoo() {}
return ...
}
I don't want to use Anonymous function like const handleFoo: MyType['foo'] = () => {}
I also tried <MyType['foo']>function handleFoo() {} like recommended here but it's not working in tsx (Operator '>' cannot be applied to types 'string[]')
Whatever your reason for avoiding the anonymous function, you can still type a function by assigning it to a variable, even if it isn't anonymous:
const handleFoo: MyType["foo"] = function () {}
Edit: as #jonrsharpe pointed out, there are some utility classes you could use here, but the results, uh, leave something to be desired:
function handleFoo(...args: Parameters<MyType["foo"]>): ReturnType<MyType["foo"]> {}
const handler: ProxyHandler<any> = {
get: (target: Promise<any>, prop: string, receiver: any) => {
return target.then((o) => {
return o[prop].apply(o);
});
},
};
return new Proxy(obj, handler);
So I have this code that I copied from a gist on the internet, and it seems to work. I understand how the trap works, but I don't get how the proxy makes a return of a promise act like a synchronous value. My colleague is afraid this code has a race condition. Are there any race conditions? what's actually happening under the hood? do I need to improve this code any to make it safe?
code is written in typescript and running on nodejs 10.
It doesn't look like this code makes access synchronous at all. It looks like it serves to make any methods on the promise payload available on the promise, but they will still have deferred execution when invoked.
For example, given the following API:
interface Bird {
speak(): void;
}
function getBird(): Promise<Bird> {
return new Promise((resolve) => {
setTimeout(() => resolve({ speak() { console.log('CAW'); } }, 1000);
});
}
function proxyPromise<T>(promise: Promise<T>) {
// Your promise proxying code here
}
The proxyPromise code would allow you to call methods on the proxied object, and defer them until the promise is resolved:
const proxiedBird = proxyPromise(getBird());
console.log("Fetching Bird")
proxiedBird.speak;
console.log("Told it to speak");
This code would execute fine, but it won't make the speak() operation run synchronously--it will still wait for the getBird() promise to resolve. So in output you would see:
Fetching Bird
Told it to Speak
CAW
The code snippet you have would do nothing to support fields or methods with parameters on the proxied object.
You could describe its safe behavior with some typescript typing:
type MethodProxy<T> = {
[idx in keyof T]: T[idx] extends () => infer U ? Promise<U> : never;
}
function proxyPromise<T>(promise: Promise<T>): MethodProxy<T> {
const handler: ProxyHandler<any> = {
get: (target: Promise<any>, prop: string, receiver: any) => {
return target.then((o) => {
return o[prop].apply(o);
});
},
};
return new Proxy(promise, handler);
}
Tricky question #xenoterracide. But answering you, actually, this doesn't work synchronously at all, basically, you turned every obj property to be accessed only asynchronously, and if the property is not a function, it throws an error.
Under the hood, you are only trapping a promise get properties, and in the trap, waiting for the promise to resolve and execute the property (function) in this value resolved by the promise.
I simulate it in this playground:
const handler: ProxyHandler<any> = {
get: (target: Promise<any>, prop: string, receiver: any) => {
return target.then((o) => {
return o[prop].apply(o);
});
},
};
const obj = {
a() {
return 'Hi'
},
b: 5
}
const proxy = new Proxy(Promise.resolve(obj), handler);
//both prints promises
console.log(proxy.a) // after resolved, return 'Hi'
console.log(proxy.b) // error
This proxy approach could be useful if you don't want to resolve the promise itself. But you would need to await every property, and take care of not function ones.
Under my Angular 6 app , i have this service ; where i'm declaring a varibale called permittedPefs , this variable is setted asychronsouly within a httpClient.get call.
#Injectable()
export class myService implements OnInit {
permittedPefs = [];
constructor(){}
ngOnInit() {
// STEP 1
this.loadUserPefsService.getUserRolePefs(roleId).subscribe(
(returnedListPefs) => {
this.permittedPefs = returnedListPefs;
},
error => {
console.log(error);
});
}
// STEP 2
this.myMethod(1);
After that , i ve a call of this method which is using my -supposed setted - var
myMethod(pefId): boolean {
return this.permittedPefs.includes(pefId);
}
the problem is it seems that permittedPefs , haven't got its value yet , and the call of myMethod() point to a wrong value of "permittedPefs"
So what's the simpliest way to make it wait to the just after the http response , without calling if from the http Response callback (as i 'm using it in several places)
Sugesstions??
Asynchronous Hell ! the best choice here is to get an Observable instead of a value
in your service :
getValue (): Observable<any>{
return this.loadUserPefsService.getUserRolePefs(roleId);
}
in your method :
myMethod(pefId): boolean {
this.yourservice.getValue().subscribe(
data => {
if(data){
return data.includes(pefId);
}
});
}
This happens because your method is called when you have not received the result yet. so just move the function call in subscribe function
Call the method this.myMethod(1); from subscription block, so that you wait for asynchronous call to be completed, which will then set the value of permittedPefs.
ngOnInit() {
// STEP 1
this.loadUserPefsService.getUserRolePefs(roleId).subscribe(
(returnedListPefs) => {
this.permittedPefs = returnedListPefs;
// STEP 2
this.myMethod(1); // check this line
},
error => {
console.log(error);
});
}
I have a method which makes a call to Angular's $resource. I am trying to test the return value of this method. This method should be simple enough to test.
Method Code
getCountries(): returnTypeObject {
var countries = this.$resource(
this.apiEndpoint.baseUrl,
{
'get': {
method: 'GET', isArray: false
}
});
return countries;
}
Unit Test
describe('module', (): void => {
beforeEach((): void => {
angular.mock.module('ngResource');
});
describe('getCountries...', (): void => {
it("should...", inject(
['Builder', (Builder: IBuilder): void => {
Builder.getCountries().get(
(value: any) => {
console.log(value);
}, (error: any) => {
console.log(error);
});
}]));
});
});
Now in the above code when I run my test the none of the callbacks ever get called. Neither "value" nor "error" ever get printed. I've been looking for a solution for quite a while now but haven't been able to find anything.
Keep in mind that I do not want to mock $resource, instead I want to test what is returned by getCountries().get() and then I want to use the callbacks to test the return value.