I'm using angular w/ rxjs to observe user events on the interface. However, I'm having this really simple problem with passing arguments to a method in an arrow function. Here is the problem:
This is not working: searchterm is not being passed to this.searchFacilities
ngOnInit() {
this.searchTerm$.subscribe(searchterm => this.searchFacilities);/**Not working here**/
}
searchFacilities(term: string){
console.log(term);
this.facilityservice.searchFacilities(term)
.subscribe(results => this.facilityList = results);
}
But this works:
this.searchTerm$.subscribe(searchterm => { this.searchFacilities(searchterm); })
Clearly, I have other solutions that are pretty painless, but I really want to understand why my first approach is not working. Thanks!
Because the parameter is not passed directly to your function.
Example from the doc:
Rx.Observable.range(0, 3).subscribe(function (x) { console.log(x) });
The same example with an arrow function:
Rx.Observable.range(0, 3).subscribe(x => console.log(x));
Small clarification. The doc says you need to pass a callback to subscribe() and that this callback will receive the value(s) emitted by the observable.
We could write it like this:
const myCallBack = (val) => console.log(val);
Observable.range(0, 3).subscribe(myCallBack);
In your case you already have a callback, this.searchFacilities.
This means you can simply write:
this.searchTerm$.subscribe(this.searchFacilities);
Just like you can rewrite my original example to:
// Now `console.log` is the callback!
Observable.range(0, 3).subscribe(console.log);
In other words, the problem is not "Why arrow function is not passing arguments". The problem is that you created an arrow function whose body IS your callback, instead of just using your callback directly.
The expanded version of your code would look like this:
const myCallBack = (searchterm) => {
return this.searchFacilities;
}
As you can see, searchFacilities is neither invoked nor does it receive the searchterm param.
You could have run into the same problem with a NON-ARROW function by writing the following code (although the syntax of arrow functions does make the mistake more likely and insidious):
const myCallBack = function(searchterm) {
return this.searchFacilities;
}
Because you're getting a reference to the searchTerm but you're not doing anything with it. You could just do this.searchTerm$.subscribe(this.searchFacilities) and the term will be passed into the function.
You searchFacilities function is declared in global scope, and then is called inside of ngOnInit as a callback and its context is not anymore global scope, now this points to ngOnInit element Object. In order to work inside ngOnInit object you need to bind it and then searchFacilities be method of ngOnInit and in this way its going to work.
Related
I have question about the fundamentals of JS.
So, in JS we all agree that a function is an object. So lets suppose this:
const mainFunction = () => { //Do stuff };
mainFunction.nested = () => { //Do other stuff };
So I have two functions:
a main function which I can call like this: mainFunction()
and a nested function I can call like this: mainFunction.nested()
I quite understand that I can access to the nested function, because she is inside an object and I'm accessing it with . like JS syntax wants to.
But I'm wondering how can JS understand which code to run when I just call mainFunction() ?
Let me know if I'm clear enough, Its kind of a silly question...
Thanks
and a nested function I can call like this: mainFunction.nested()
It's not a nested function. This is a nested function:
function example() {
function nested() {
}
}
It's just a function assigned to a property.
But I'm wondering how can JS understand which code to run when I just call mainFunction() ?
Because there's no ambiguity, you're referring to mainFunction. If you wanted to use the other function, you'd refer to it itself (the way you showed, mainFunction.nested()). It's exactly how there's no ambiguity between obj and obj.prop; the former refers to the object, the latter refers to the object's property.
Sorry for the ambiguous title, I just didn't know what else to put. Im learning JS and in the video the person does this.
When he calls the addListAfterKeyPress method at the bottom, why does the function call work? I thought he would have to put in a argument for the addListAfterKeyPress to take in since it has an event parameter. But in the end the code works perfectly. And also, when can i call a function that takes a parameter without explicitly passing one like how he did it in the picture?
This is a so called callback.
addListAfterKeypress at line 30 is not a call to this function, it is just saying, whenever the event keypress is raised on this input element, call this function.
Who is calling the function is the DOM library, indeed. You just have to pass a pointer to the function to be called.
Even more, the addListAfterKeypress function expects an event parameter, which will be provided to the function by the DOM library.
I think it is a bit more understanding by looking at an annonymous function there.
input.addEventListener('keypress', event => {
// This will be run whenever the input raises an event of type 'keypress'
// Here, the DOM library provides me an event parameter
});
Edit on demand:
Be aware, I am using ES6 just for comfort.
Suppose having this function
const callback = () => {
console.log(`My callback function is being executed`);
};
I will be using setTimeout to mock the HTML events. setTimeout is a function that expects a callback to execute after n milliseconds.The first parameter is the callback itself, the second is the amount of milliseconds, n.
See https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(callback, 500); // After 500ms, function callback will be fired
Here, I am just passing a pointer to the setTimeout function. This pointer must point to a function that will be called by setTimeout.
Let's write our own function that takes a callback as a parameter.
const callback2 = (number) => {
console.log('I received this parameter', number);
};
const callbackWrap = (callback, n) => {
// Here, callback parameter is a function that I can invoke, actually
console.log('The wrapper will execute the function passed as parameter');
callback(n);
};
Now, we can call the wrapper pointing to the new callback (callback2).
callbackWrap(callback2, 3);
callbackWrap(callback2, 4);
Or, we can define our function directly on the parameter list.
That is, we are passing an annonymous function
// p is the parameter of the callback function
callbackWrap(p => {
// Since callbackWrap will call the function parameter
// by passing a single parameter,
// the function I am declaring, expects that parameter
console.log(`Received ${p} inside the annonymous function`);
}, 'Parameter');
So, to summerize a bit, just the same way you can declare a variable (let's say, of type number) and then pass it to a function as a parameter, you can declare a function to pass it the same way.
const normalParameter = 30;
const functionParameter = p => console.log('Another callback', p);
callbackWrap(functionParameter, normalParameter);
// Or maybe passing more complex parameters
const anotherParameter = [1, '2', {3: 4}];
callbackWrap(functionParameter, anotherParameter );
Hope it clarifies a bit.
In a tutorial related to React, which I am watching on YouTube:
https://www.youtube.com/watch?v=h3KeJRKYpj8
there was a piece of code that had the following (minute 13:40 in the video)
const setCounterWithValue = (value) => {
setCounter(value)
}
this function gets called from a button component in the following code:
<button onClick={() => setCounterWithValue(counter -1)}
The video tutorial suggested a way to shorten this function call and make it simpler.
So what he did was modifying the code to be as follows (minute 14:30 in the video):
const setCounterWithValue = value => () => {
setCounter(value)
}
which meant the button component became as follows:
<button onClick={setCounterWithValue(counter -1)}
So my problem here is that I was expecting the setCounterWithValue to be structured as the following:
const setCounterWithValue = () => (value) => {
setCounter(value)
}
so empty () then pass value which triggers the setCounter.
I would like to have some deep explanation and some resources (like articles and videos) that explain this in further details.
I disagree that its simpler... What they are doing is called currying. Its a shorthand way to create a function that returns a function. So a longhand form would look like this:
const setCounterWithValue = (value) => {
return function () {
setCounter(value)
}
}
Its probably easier to understand why the parameters go where they do when written in this form. When you call it inline you're calling the outer function <button onClick={setCounterWithValue(counter -1)} />. It then returns the a function that should be called when the button is clicked.
What they're doing there is called currying. In other words, it's a function that returns another function. Instead of firing it outright, they're taking the value of the first function's argument and utilizing it in the second function that is fired from the the click event. In this particular case I don't see it being any simpler as you're getting the same exact outcome but in this case your original function is just fired in the second function body. Nevertheless, more info on currying can be found here.
Calling the "simpler" function with setCounterWithValue(counter - 1) will return a function that, when executed, will pass through the counter value provided. The concept for this is called currying through the use of a closure. The function you "expected" wouldn't make much sense because you'd be calling it with a value, but that value never gets captured, so the function it returns is expecting a value parameter, which is not passed, it gets lost.
Here's the two examples:
Example 1:
const setCounterWithValue = value => () => {
setCounter(value)
}
When called with setCounterWithValue(42), it will return the following:
() => { setCounter(42) }
Example 2:
As opposed to what you said you expected, which would end up like the following:
const setCounterWithValue = () => (value) => {
setCounter(value)
}
Called with setCounterWithValue(42) would return the following:
(value) => { setCounter(value) }
Notice how the function being returned still expects a value to be provided. This is the difference between the two examples and why Example 1 would work, while this one wouldn't.
This is an example of currying, which you can use as an introduction to Higher Order Functions which are very common in the React ecosystem.
To break down what happens in this case and why your assumption on how the function should look is wrong, you first have to understand what JavaScript closures are.
Let's say we have this piece of code:
function foo() {
var bar = 5;
return function baz() {
console.log(bar);
}
}
foo(); // Returns a function. Nothing happens
foo()(); // The returned function is executed. Prints 5
Here we take advantage of a closure that is created on line 3. The function baz that we return from foo captures the context of its definition site (definition site = where the function is defined = in this case the foo function). So baz can be called from anywhere and still have access to the place in memory that bar points to.
The first invocation does nothing since the returned function is not called.
The second invocation calls the returned function therefore printing the number 5 to the console.
In order to understand your example snippet you can be more explicit in the function definition:
This:
const setCounterWithValue = value => () => {
setCounter(value)
}
can be rewritten like this:
function setCounterWithValue(value) {
return function() {
setCounter(value)
}
}
The instructor in the video just takes advantage of the implicit return feature of arrow functions
The code snippet just above will have the same result when used with your code. Hopefully, written like this, it makes more sense to you why there is no need for the anonymous function to have a value argument. It can access it via a closure.
As to why currying and high order functions are preferred by some JavaScript developers, the answer is way too long and opinionated, so I suggest you study the subject a bit more. A very interesting article can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
A bit harder to read but with a bunch of useful theory: https://eloquentjavascript.net/05_higher_order.html
It is easier to understand using function declaration instead of arrow functions. The tutorial suggests you refactor the function into a function factory:
function setCounterWithValue (value) {
return function () {
setCounter(value);
}
}
This means that calling the function above will return a function that requires no arguments:
let f = setCounterWithValue(1);
f(); // this sets counter to 1
Your suggested function instead returns a function that requires an argument:
function setCounterWithValue () {
return function (value) {
setCounter(value);
}
}
This means to set the value you will have to pass an argument:
let f = setCounterWithValue();
f(1); // set value to 1
The problem the refactor is trying to solve is that onclick functions are always called with an event object as the argument. When the button is clicked, the browser will call your function as:
setCounterWithValue(event);
You have no control over this. It is impossible to force the browser to call it any other way. Thus, ideally you want to pass into the onclick handler a function that ignores the event argument:
function setCounterWithValue (value) {
return function () {
setCounter(value);
}
}
let f = setCounterWithValue(counter -1); // this returns a function
// that ignores arguments
return <button onClick={f} />
most people would avoid using a temporary variable so:
<button onClick={setCounterWithValue(counter -1)} />
On the other hand, if you use your suggestion you would need to do:
{/* wrap in an anonymous function to ignore the event */}
<button onClick={() => setCounterWithValue(counter -1)} />
I'm working with the setState method from REACT, and almost every setState call in my code looks something like the following:
this.setState({..some_stuff...}, ()=> some_standard_method(this.state));
And so that naturally suggests that if i had a method of the form
customSetState(args) {
this.setState(args, () => some_standard_method(this.state));
}
Then I can make my code a lot less verbose by replacing each of my setState calls above with the following below
customSetState(...some_stuff...).bind(this)
But I'm not sure how to write this method. What I mean by that, is that the setState method doesn't take a single variable exactly, but an arbitrary object with arbitrary parameters specified. So in the line:
customSetState(args) { ...
Do i need to make any changes to the input variable "args" to indicate that i'm accepting arbitary defined objects?
Here's a simple example of how to achieve that using the spread operator and a rest parameter:
function setStateSimulation(...args) {
console.log(`My three parameters are ${args[0]}, ${args[1]} and ${args[2]}`);
const callback = args[args.length - 1];
callback();
}
function myCustomSetStateSimulation(...args) {
setStateSimulation(...args, () => {
console.log('My custom callback');
});
}
myCustomSetStateSimulation("a", "B", "c");
I'm trying to build a middleware in redux to handle api requests.
While looking for inspiration I found this code:
redux api middleware
export default store => next => action => {
const callAsync = action[CALL_API];
if(typeof callAsync === 'undefined') {
return next(action);
}
.
.
.
function actionWith(data) {
const finalAction = assign({}, action, data);
delete finalAction[CALL_API];
return finalAction;
}
next(actionWith({ type: types.REQUEST }));
.
.
.
}
My question is: Why is the function actionWith decalared inside of the main function? Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
What is the benefit here?
Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
You are correct: you could have take actionWith outside of the outer function as long as you supplied action as an argument (actionWith(data, action)).
The functionality would be the same. However, the primary concern I have is maintainability: if you needed to modify the inner function to do something that required yet another variable from the outer function , you'd need to add another argument. If the duty of the function is closely tied to the internals of the outer function, leaving it in gives you ready access to the outer function's variables when you need to modify the code.
I would balance this concern of extra arguments (which generally favors keeping the function internal) against the usefulness of having the function available to other part of the code (which would favor taking it outside, for increased visibility). For example, if I had many outer functions that each had their own internal copies of actionWith, it would be better to have them to share a single version of actionWith.
That is, if I had
function outer1(action) {
function actionWith(data) { ... }
actionWith(thing);
}
function outer2(action) {
function actionWith(data) { ... }
actionWith(thing);
}
From a maintainability perspective, I would rather have
function actionWith(action, data) { ... }
function outer1(action) {
actionWith(action, thing);
}
function outer2(action) {
actionWith(action, thing);
}