How do functions defined with => get called in Angular? - javascript

From here: https://angular.io/tutorial/toh-pt4 - hero.component.ts
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes);
}
I have understood that this heroes => this.heroes = heroes translates to as follows:
f( heroes )
{
return this.heroes = heroes;
}
Is return implied here?
I want to understand where from does this inner function get called. Who's calling it?

In the example code you provided,to return a list of heros, we have to write it like
getHeroes(): Hero[] {
this.heroService.getHeroes()
.subscribe(heroes => ({heroes : heroes}));
}
Above arrow function will translate to
f( heroes )
{
return this.heroes = heroes;
}
Otherwise, the code you provided, its just making an assignment to this.heros variable, so return statement does not apply, and the arrow function translate to
f( heroes )
{
this.heroes = heroes;
}
Further explanation of Arrow function
Arrow functions, like function expressions, can be used to return an object literal expression. The only caveat is that the body needs to be wrapped in parentheses, in order to distinguish between a block and an object (both of which use curly brackets).
Example
//ES5
var setNameIdsEs5 = function setNameIds(id, name) {
return {
id: id,
name: name
};
};
// ES6
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });
console.log(setNameIdsEs6 (4, "Kyle")); // Object {id: 4, name: "Kyle"}
For a regular function, if the ‘this’ keyword were inside an object’s method (a function that belongs to an object), it would refer to the object. While in an arrow function, ‘this’, always references the owner of the function it is in. Adding a console.log(this) before the return in the arrow function returns a Window object.
Example
// ES5
const brunch = {
food: 'Dim sum',
beverage: 'Jasmine tea',
order: function() {
return `I'll have the ${this.food} with ${this.beverage} please.`
}
}
brunch.order(); //"I'll have the Dim sum with Jasmine tea please."
// ES6
const brunch = {
food: 'Dim sum',
beverage: 'Jasmine tea',
order: () => {
return `I'll have the ${this.food} with ${this.beverage} please.`
}
}
brunch.order(); //"I'll have the undefined with undefined please."

In the following arrow function heroes => this.heroes = heroes
Yes, return is implied, this may or may not be a problem depending on the rest of your code. I'm assuming in your case, you're not looking to return the assignment, you just want the assignment to happen.
So all you have to do is wrap the result in braces like so heroes => {this.heroes = heroes}, now nothing is returned.
As for your second question, who calls the inner arrow function: From the looks of your code, this.heroService.getHeroes() returns an observable. In your code you have "subscribed" to the observable. The easy way to think about is that the observable is telling your subscription to run the arrow function.
Basically, you are observing the observable. The observable needs time to think about it's response which is why you need to subscribe to it. When it is ready it will tell you it's response, and your arrow function inside the subscription is your response to the observable response. This is a very non-technical description to give you some intuition.
You should research observables/async functions to get a clear understanding.

this.heroService.getHeroes() returns a subscription object. In order to subscribe to it we should use .subscribe(heroes => this.heroes = heroes);.
subscribe maps the subscription object and extracts the data from the object and puts it in this.heroes, the first param inside the subscribe.
Then with the => operator we start writing actions like affectation, displaying, or anything to do, you can do anything after =>
in order to write more than one action you should use the braces like this:
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => { console.log('ur data from the observable',heroes);
this.heroes = heroes
});
}

Related

Is it possible to provide default parameters with rest operator

I was learning from an ES6 essential course and trying default parameters and rest operator for functions.
I have defined a function sayHi as below with default parameters and then rest operator which does not gives the desired output.
const sayHi = (greetings, ...names) => {
names.forEach(item => {
console.log(`${greetings} ${item}`);
});
}
sayHi('Hi', 'Ahsan', 'Awais', 'Haseeb');
The above snippet works as desired. but when I tried to set a default parameter value for greetings variable it works but gives unwanted result i.e. value 'Ahsan' is taken by the greetings variable.
const sayHi = (greetings = ' Hi', ...names) => {
names.forEach(item => {
console.log(`${greetings} ${item}`);
});
}
sayHi('Ahsan', 'Awais', 'Haseeb');
Is there a way I can set default parameters in function like above before rest operator?
You can't, no. The rest parameter only picks up the "rest" of the parameters not consumed by any previous formal parameters, so greeting will always receive the first argument's value.
Separately, since both the names and the greeting have the same type, you can't provide a default at all if you want to accept the names that way.
A couple of options for you:
A curried function
You could have a function that accepts the greeting and returns a function that uses it with whatever you pass it:
const greet = (greeting = "Hi") => (...names) => {
for (const name of names) {
console.log(`${greeting} ${name}`);
}
};
greet()("Ahsan", "Awais", "Haseeb");
greet("Hello")("Ahsan", "Awais", "Haseeb");
Note how we called that:
greet()("Ahsan", "Awais", "Haseeb");
greet() creates the function using the default greeting. Then we call that function by using ("Ahsan", "Awais", "Haseeb") on it. greet("Hello") creates a function that uses the greeting "Hello" (and then we call it).
(I also took the liberty of using for..of rather than forEach, but it's a matter of style.)
Take names as an array
Another option is to accept the names as an array. That way, we can tell inside the function whether we got a greeting or not:
const greet = (greeting, names) => {
if (Array.isArray(greeting)) {
names = greeting;
greeting = "Hi";
}
for (const name of names) {
console.log(`${greeting} ${name}`);
}
};
greet(["Ahsan", "Awais", "Haseeb"]);
greet("Hello", ["Ahsan", "Awais", "Haseeb"]);
you just have to pass undefined in the 1st parameter to skip optional arg
think of it like this greetings = typeof greetings != 'undefined' ? greetings : "hi" which means that check the value of greetings and if it's undefined (not provided) use the default value
edit: here is the code snippet
const sayHi = (greetings = ' Hi', ...names) => {
names.forEach(item => {
console.log(`${greetings} ${item}`);
});
}
sayHi(undefined, 'Ahsan', 'Awais', 'Haseeb');

If a function is only used in another function should I keep it inside or outside it?

Like in the subject. I have a function like below and I have quite a bit of helping functions declared within a function (twice as much than in the example) because it's the only one using them.
My question is: should I extract those helping functions outside the function to maintain rule "Function should do one job and do it well" or it should be within? I also read about that higher level functions should be higher for better readability, but it somehow doesn't work (shouldn't hoisting make it work?).
const queryThings = async (body = defaultBody) => {
try {
(...)
// helping functions
const isNonTestDeal = obj => (...)
const isNonEmpty = obj => (...)
const replaceHTMLEntity = obj => (...)
const extractCountries = o => (...)
const queried = await query(...) // that one is outside this function
const cases = queriedCases
.filter(isNonTestDeal)
.map(obj => {
let countries = [(...)]
.filter(isNonEmpty)
.map(replaceHTMLEntity)
.map(extractCountries)
let data = {
(...)
}
return data
})
.filter(obj => (...))
.sort((a,b) => a.d - b.d)
.slice(0, 45) // node has problem with sending data of more than 8KB
return cases
} catch (error) {
console.log(error)
}
}
If you declare the function outside, and only use it in one function, then you cause namespace pollution. (What is namespace pollution?) Thus, I would recommend keeping it inside. Also, if you do so, it is easier to read as well, since it will be closer to the code where it is used.
To address your question about hoisting, it only works if you declare your function without assigning it to a variable.
i think when you write function in other function the memory use is better than write out of function
but you can't use in another function it is local function and it isn't public function

How would I programmatically call an object method? Like MyObject.XVariable(//some function)

I have an object, that takes input from an API call to fill it up.
let MyDog = {
Name: 'Dog',
}
let arrayFunctions;
fetchDogsFunctions(dogAPIUrl).then(res => {
//results is an array that has a list of functions the dog has, like //getStats(), or walkDog()
arrayFunctions = res;
})
Now I want to map through the array results and call the function on my dog like...
arrayFunctions.map(item => {
await MyDog.item(//Params)
})
How can I do this??
Where MyDog is set up from a file, and then depending on the array functions, for each function it programmatically fills in the call to the new function like MyDog.item where item is a variable in an array called "Walk()"
I assumed how your data might have structured. Pls take a look below and you might get the idea of how to call functions dynamically using "await"
const MyDog = {
funA(a) { return Promise.resolve('Function A called with parameter ' + a) }
, funB(b) { return Promise.resolve('Function B called with parameter ' + b) }
}
const arrayFunctions = ['funA', 'funB']
Promise.all(arrayFunctions.map(async (item, i) =>
await MyDog[item](++i))
)
.then(console.log)
I can't see any property name "item" in your MyDog Object
The answer is to do :
MyDog[item]()
within the loop.
I was asking the correct syntax to perform this operation

Why would you ever call .call() on Observable functions?

I am a relative beginner in Angular, and I am struggling to understand some source I am reading from the ng-bootstrap project. The source code can be found here.
I am very confused by the code in ngOnInit:
ngOnInit(): void {
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
const results$ = letProto.call(inputValues$, this.ngbTypeahead);
const processedResults$ = _do.call(results$, () => {
if (!this.editable) {
this._onChange(undefined);
}
});
const userInput$ = switchMap.call(this._resubscribeTypeahead, () => processedResults$);
this._subscription = this._subscribeToUserInput(userInput$);
}
What is the point of calling .call(...) on these Observable functions? What kind of behaviour is this trying to achieve? Is this a normal pattern?
I've done a lot of reading/watching about Observables (no pun intended) as part of my Angular education but I have never come across anything like this. Any explanation would be appreciated
My personal opinion is that they were using this for RxJS prior 5.5 which introduced lettable operators. The same style is used internally by Angular. For example: https://github.com/angular/angular/blob/master/packages/router/src/router_preloader.ts#L91.
The reason for this is that by default they would have to patch the Observable class with rxjs/add/operators/XXX. The disadvantage of this is that some 3rd party library is modifying a global object that might unexpectedly cause problems somewhere else in your app. See https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#why.
You can see at the beginning of the file that they import each operator separately https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts#L22-L25.
So by using .call() they can use any operator and still avoid patching the Observable class.
To understand it, first you can have a look at the predefined JavaScript function method "call":
var person = {
firstName:"John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var myObject = {
firstName:"Mary",
lastName: "Doe",
}
person.fullName.call(myObject); // Will return "Mary Doe"
The reason of calling "call" is to invoke a function in object "person" and pass the context to it "myObject".
Similarly, the reason of this calling "call" below:
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is providing the context "this._valueChanges", but also provide the function to be called base on that context, that is the second parameter, the anonymous function
value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
}
In the example that you're using:
this._valueChanges is the Input Event Observerable
The _do.call is for doing some side affects whenever the event input happens, then it returns a mirrored Observable of the source Observable (the event observable)
UPDATED
Example code: https://plnkr.co/edit/dJNRNI?p=preview
About the do calling:
You can call it on an Observable like this:
const source = Rx.Observable.of(1,2,3,4,5);
const example = source
.do(val => console.log(`BEFORE MAP: ${val}`))
.map(val => val + 10)
.do(val => console.log(`AFTER MAP: ${val}`));
const subscribe = example.subscribe(val => console.log(val));
In this case you don't have to pass the first parameter as the context "Observable".
But when you call it from its own place like you said, you need to pass the first parameter as the "Observable" that you want to call on. That's the different.
as #Fan Cheung mentioned, if you don't want to call it from its own place, you can do it like:
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
I suppose
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is equivalent to
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
In my opinion it's not an usual pattern(I think it is the same pattern but written in different fashion) for working with observable. _do() in the code is being used as standalone function take a callback as argument and required to be binded to the scope of the source Observable
https://github.com/ReactiveX/rxjs/blob/master/src/operator/do.ts

Using switchMap with Promises

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).

Categories