Need clarification for map and observable syntax in Angular - javascript

There is a certain syntax that is baffling me and i see it with the map function and also with the observable in typescript/Angular (Angular 5). I have two methods:
This one is in a component:
logout() {
this.authService.logout().subscribe(
result => {
this.router.navigate(['/login']);
}
);
}
And this is in the related service:
logout(): Observable<any> {
return this.http.post('/api/auth/logout', { }).map(
response => {
this._token = null;
//more unrelated code...
return true
}
);
}
The part that is confusing me in both of these cases is this:
thing => {
//code
}
What is this? The code above works. but I see that have both 'result' and 'response' for thing. Can 'thing' be anything at all or is it defined somewhere?
Also, I looked up the map function in javascript at w3schools (because I've never had a use for it) and it shows in the example that the first parameter is supposed to be a function which gets applied to each element of the array that it is associated with but "thing => {}" is not a function so this is super confusing.
Note, that I have worded my question in such a way as to get to the underlying misunderstanding rather than focusing on my specific problem, however solving my specific problem may help illustrate my misunderstanding.
The problem with the code above is that while it works it does not know what to do when the api endpoint returns a 500 error. I am trying to determine how to catch the error so that I can do something with that on the front end.

Thing can be whatever you want to name it. Result, data, response, etc. Doesn't matter. What you're basically doing is creating a variable for the result emitted from your subscription. The subscription takes in a function() and inside that function, you pass the variable name that you want to be used for the success result. And really, here, using result is meaningless, since nothing is ever done with it. If you aren't going to do anything with the response, its better to just say:
logout() {
this.authService.logout().subscribe(() => {
this.router.navigate(['/login']);
});
}
To catch errors, you only need to pass a comma after the last curly, like so:
logout() {
this.authService.logout().subscribe(() => {
this.router.navigate(['/login']);
}, err => {
// Do something with error here
});
}
As for map, here is an example
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
It basically takes every variable in the array and performs that map method, meaning it takes each value and does whatever the function says to do, in this case, multiply it by 2. Think of it as a sort of transformation. In that example, it's basically being used to manipulate the response before sending it back to the subscription.

Related

Call an object method once the chained methods are resolved

I would like to create a custom api service that will work similarly to the supabase-js library. Example:
const { data, error } = await supabase
.from('cities')
.select('name, countries(*)')
.eq('countries.name', 'Estonia')
I cannot figure out how it is possible that the last method doesn't have to be something like .get() (which would perform the fetch request)
Ideally, I would like the fetch to be called automatically after the chained methods are resolved - sth. like this:
const { data, pending, error } = await useProductsService()
.whereIn('id', [123, 12, 521, 521])
.whereLowerThan('price', 300)
note: I used supabase just as an example, I want to use this with a completely different API
I know how to do it with sth like a .get() method at the end, however, I'd like to do it without it, if possible.
It's not a big deal to have to call one more method but I see it as an opportunity to learn something new as well.
Is it possible to do something like this? Or did I understand something wrong?
As you correctly point out, it is necessary to have a function call at the very end, to let the chain know that you have finished building it and that it's time to execute the DB query.
However, when you do the destructuring and extract the data property, if there is a getter function for data, then that will act as the function which is called that signals that the building of the query is complete.
class Chain {
from(s) {
this.config = []; // 'from' is always the first in the chain, so reset the config
this.config.push({from: s}); return this;
}
select(s) { this.config.push({select: s}); return this; }
eq(s) { this.config.push({eq: s}); return this; }
get data() {
console.log(this.config);
// do the query here
return 'this is the result';
}
}
const api = new Chain()
const { data } = api
.from('cities')
.select('name, countries(*)')
.eq('countries.name', 'Estonia')
console.log(data)

Why is this destructuring not working?

I am creating an observable like so:
return new Observable(sub => {
const {next, complete, error} = sub;
this.AuthHttp.get(`http://192.168.1.100:3000/api/users/${id}`)
.subscribe(res => {
let user = res.json();
next(user);
complete();
}, e => {
error(e.json());
});
})
Yet it nothing is happening in my front end when next() is expected to be called. If I make a minor change to the code so that sub.next() is called instead, everything works as expected. This indicates the underlying code is not flawed, just the way I am making a reference to next.
I have seen this form of destructuring used with the Observer class before (in an example online), so what am I doing wrong here?
Because the next, error and complete methods are object methods that must be called on an object instance.
When you use destructuring to obtain the functions and later call those functions, the calls are without context.
You cannot do what you've attempted for the same reason that this will not work:
const { toString } = new Date();
console.log(toString());
For more information, see this issue.

Unsure how to convert method definition to ES6

I'm currently in the process of converting our Backbone application to ES6 syntax like e.g. this:
action: function(e){},
Becomes
action(e) {}
However, now I'm having this code:
throttleEvent: _.throttle(function(e) {
//do stuff
}, 500);
}
And I can't seem to find how to convert this to valid syntax.
I tried
throttleEvent _.throttle((e) => {
//do stuff
}, 500);
}
And
throttleEvent() {
return _.throttle((e) => {
//do stuff
}, 500);
}
But these all failed to work.
Help converting this to the valid syntax would be appreciated.
Well I'm not quite sure if the short syntax is applicable for your example.
Lets have a look at your start
action: function(e){},
you have an object, that object has a property called "action" and that property holds a function that later then can be called by obj.action().
Now to your example
throttleEvent: _.throttle(function(e) {}
Again you have an object, that has a property called throttleEvent. But the main difference is the value. The value is the return Value of the function _.throttle().
Taking from the documentation (https://lodash.com/docs/4.17.4#throttle)
Creates a throttled function that only invokes func at most once per every wait milliseconds
So your property actually holds the function that you got returned from the library. That explains why your second approach does not work. Because in this version every time you call the object property, you create a new throttle function.
(And to your first solution I think this is invalid syntax)
I think the best approach if you really want to use the short syntax is, assigning the throttle function to a variable before and then use it
For example something like this
const throttleFunction = _.throttle((event) => {
//do stuff
}, 500);
const obj = {
throttleEvent(event): any {
return throttleFunction(event);
},
};
But then it is to decide whether the ES6 syntax makes sense in this case or if you just stick with your original version
throttleEvent: _.throttle(function(e) {
//do stuff
}, 500)
Just because there is a different syntax available, does not mean you always have to use the new one. In some cases the "old one" makes actually more sense
try this syntax:
_.throttle(() => //Do stuff, 5000)

How do I return an array/value as a cursor am able to use in my template?

I have an helper function that returns an array instead of the conventional db.dbName.find() cursor. How do I code a return array so it reflects as a cursor similar to one generated by a db.dbName.find() that I can use in template?
Find below my helper function:
var arrayTest = Meteor.call('getUserCategoryArray', function(error, results){
if(error){
console.log(error.reason);
} else {
var results1 = results.toString();
var results2 = results1.split(",");
alert("Array content: " +results2);
alert(results2[0]);
alert(results2[1]);
alert(results2[2]);
return results2;
}
})
To explain part of the code: From the top down: The alerts successfully prints out:
Array content: shoes,clothes,watches
shoes
clothes
watches
The alert is just to confirm that results2 is a working array.
Now how do I code the return value/array so that I am able to use it in my template as if it was a cursor returned by a db.dbName.find() query?
Your help is appreciated.
your issue isn't about arrays, it's about synchronous vs asynchronous programming. as #mutdmour mentioned, spacebars can handle an array from a helper just fine.
helpers can get called several times as a template is rendered, so it shouldn't do anything async or have any side effects. your helper is making an async call, so that's one issue right off the bat.
the issue you're seeing is that such a call is async, and a helper needs to be sync. so you'll have trouble getting your helper to work as-is.
in many cases, helpers return the contents of, or a cursor to the contents of, a collection. i don't know your app, but is a publish/subscribe with collection contents a better choice here?
if not, and it has to be the results from a method call, then generally i will:
make the call in the onCreated()
write the results to a reactive var
return the reactive var from the helper
e.g.
Template.Foo.onCreated(function() {
let self = this;
self.clothing = new ReactiveVar();
Meteor.call('getUserCategoryArray', function(error, results) {
if (!error) {
// or whatever you need to do to get the results into an array
self.clothing.set(results);
}
});
});
Template.Foo.helpers({
clothing() {
return Template.instance().clothing.get();
}
});

Javascript Parents of Caller Function

I have functions in JavaScript that need to check that the function running it is, indeed, the correct function (ex, needs the function something.stuff.morestuff.coolFunction to have called it or it wont run).
I've tried getting Function.caller, but this only returns the function itself, and no way to determine which objects it is inside of.
Given the following setup:
function helloWorld(){
if(/* the exact path to the calling function */ === 'greetings.happy.classic.sayhello'){
console.log('Hello World');
}else{
console.log(/* the path from earlier */ + ' not allowed.');
}
}
greetings = {
happy: {
classic: {
sayHello: function(){ helloWorld(); }
sayBye: function(){ helloWorld(); }
}
},
angry: {
sayHello: function(){ helloWorld(); }
},
simple: [
function(){ helloWorld(); }
]
}
function sayWords(){
helloWorld();
}
What I'm trying to accomplish would look like this:
greetings.happy.classic.sayHello(); // => Hello World!
greetings.happy.classic.sayBye(); // => greetings.happy.classic.sayBye not allowed.
greetings.angry.sayHello(); // => greetings.angry.sayHello not allowed.
greetings.simple[0](); // => greetings.simple[0] not allowed.
sayWords(); // => sayWords not allowed.
helloWorld(); // => null not allowed.
// not sure what would come out of this, so i put null on that one
Here's the question in one neat little package:
How would I find the exact object path (i.e. greeting.happy.classic.sayHello) of the calling function? Function.caller.name just returns the name of the function, which is not enough. I need the full tree of the calling function's location.
This feels like a complex issue, so thank all for your help.
Well, you seem to be trying to find out parent's reference in the child object. This is not possible. Check out this post Javascript Object get parent
I think you could use new Error().stack to analyse where the call comes from.
Hopefully you're aware that any preprocessor/uglyfier/bundler is more than likely to break your approach ...

Categories

Resources