NGXS State documentation - ngxs

I'm new to NGXS and I'm trying to fully understand the docs so I can start using it knowing what I'm doing.
There is one thing I don't understand in this code snippet from here.
export class ZooState {
constructor(private animalService: AnimalService) {}
#Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
return this.animalService.feed(action.animalsToFeed).pipe(tap((animalsToFeedResult) => {
const state = ctx.getState();
ctx.setState({
...state,
feedAnimals: [
...state.feedAnimals,
animalsToFeedResult,
]
});
}));
}
}
Just below this code, it says:
You might notice I returned the Observable and just did a tap. If we
return the Observable, the framework will automatically subscribe to
it for us, so we don't have to deal with that ourselves. Additionally,
if we want the stores dispatch function to be able to complete only
once the operation is completed, we need to return that so it knows
that.
The framework will subscribe to this.animalService.feed, but why?

The action, FeedAnimals, uses the injected service, AnimalService to feed the animals passed in the action's payload. Presumably the service is operates asynchronously and returns an Observable. The value of that Observable is accessed via the tap function and is used to update the ZooState state context based on completing successfully.
In order to use NGXS specifically and Angular in general, you really have to understand RxJS... here's my goto doc page for it

Related

How Subscribe works

I am learning the rxjs and playing with observable and subscribe. I have the following method in component.ts file which returns true/false from API
this.http.get(apiUrl+"/actionName")
.subscribe(result=>
{
if(result){
//step1
//1.show success message
//2.call the other method
//3.and after returned from here
}else{// not true
//1. show error message
//2. returned from here
}
});
});
//step2
// call another function
}
Whenever I subscribe to an observable it immediately jumps to the next line i.e. step 2 and another method gets called first. Which I don't want to do.
I want to run step1 first until it gets finished completely only then it should go to step2.
Thank you in advance.
You don't say so in your question, but I suspect your
//2.call the other method
line contains a nested subscription or a promise. If that's the case, of course your synchronous code will be run before your asynchronous code is run. JavaScript is a single-threaded environment, so you can never wait for other code to run.
Instead, use RxJS various operators to manage the order of your code for you. How you want to do that depends on what you're doing, though sadly call the other method isn't descriptive enough.
Assuming theOtherMethod and anotherFunction are actually strangely named observables, then you might do something like this:
this.http.get(apiUrl+"/actionName").pipe(
switchMap(result => {
if(result){
return theOtherMethod;
}
return of("There's no result")
}),
switchMap(otherMethodResult => anotherFunction)
).subscribe(anotherFunctionResult => {
/* Ignore result?*/
});

Intercept observables before subscription callback

I am using the following code to make get request:
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url) //code for making get request
return getReqObservable
}
The problem is sometimes my backend might return {error:true, message} with status code 200. (I know thats weird).In that case I want to intecept getReqObservable and not allow its subscription callback to run.
image.component.ts
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url)//code for making get request
return getReqObservable
.do((value)=>{
if(value.error){
//do not allow it to propagate further
})
})
You should propagate it further, but as an error rather than an event (i.e. do just like if your backend did the right thing and returned an error response):
makeGetReq$(url: string): Observable<Something> {
return this.httpClient.get<Something>(url).pipe(
mergeMap(value => value.error ? throwError(value) : of(value))
);
}
Otherwise, the calling method has no way to know that an error occurred, and thus can't execute the callbacks it might have registered for errors.
The easiest would probably be filter.
Filter items emitted by the source Observable by only emitting those that satisfy a specified predicate.
It would look like this:
return getReqObservable
.filter(value => !value.error)
It was pointed out, that you lose the notification completely if you just filter out the error case. There is of course the option to create a RxJS error notification with throwError, but it is also possible to just subscribe to the same source observable a second time with a different filter condition.
Be careful however to not call the backend twice, e.g. by using share.

Vuex error: "Do not mutate vuex store state outside mutation handlers."

I have a button on my website that performs the following action:
this.$store.commit('SET_THREAD_UPDATE', thread)
'thread' is an object consisting of multiple properties and objects and when the function is called there might be only a small change within an object of 'thread' or one of its properties.
'SET_THREAD_UPDATE' is a Vuex mutation and the only one of many that causes problems even though I am not doing anything differently.
const state = {
threadUpdate: {}
}
const mutations = {
SET_THREAD_UPDATE (state, userObj) {
state.threadUpdate = userObj
}
}
When the button that triggers the commit is pressed the first time, everything works like expected. But then, from the second time forward I get two errors and the commit doesn't do anything:
[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] Do not mutate vuex store state outside mutation handlers." (found in <Root>)
Error: "[vuex] Do not mutate vuex store state outside mutation handlers."
I can't figure out the error. It doesn't make sense because I am using a mutation to change the state. Ideas anyone? Thanks!
Solution to the problem was to use JSON instead of regular JS objects. Not sure why though.

ReduxObservable cancellation based on action type and its data

I have React app which uses redux-observable with typescript. In this scenario, FetchAttribute Action gets triggered with a id and then make an ajax call.
In certain case, I would want to cancel the ajax request if "FETCH_ATTRIBUTE_CANCEL" action was triggered with the same id as of "FetchAttributeAction" action.
action$.ofType(FETCH_ATTRIBUTE)
.switchMap((request: FetchAttributeAction) => {
return ajax.getJSON(`/api/fetch-attribute?id=${request.id}`)
.flatMap((fetchUrl) => {
// return new action
})
.takeUntil(action$.ofType(FETCH_ATTRIBUTE_CANCEL));
});
interface FetchAttributeAction{
id: number;
}
Problem:
How do we cancel the execution based on action type + action data?
In my case, it would FETCH_ATTRIBUTE_CANCEL and id.
The key is to filter actions in the takeUntil notifier to only those which match the ID you care about.
action$.ofType(FETCH_ATTRIBUTE_CANCEL).filter(action => action.id === request.id)
So here's what it might look like:
Demo: https://stackblitz.com/edit/redux-observable-playground-xztkoo?file=fetchAttribute.js
const fetchAttributeEpic = action$ =>
action$.ofType(FETCH_ATTRIBUTE)
.mergeMap(request =>
ajax.getJSON(`/api/fetch-attribute?id=${request.id}`)
.map(response => fetchAttributeFulfilled(response))
.takeUntil(
action$.ofType(FETCH_ATTRIBUTE_CANCEL).filter(action => action.id === request.id)
)
);
You can also take a look at previous questions:
Redux Observable: If the same action is dispatched multiple times, how do I cancel one of them?
Independent chain cancellation in redux-observable?
Dispatch an action in response to cancellation
The OP also pointed out that they were using switchMap (as did I originally when I copied their code) which would have meant that the epic only ever had one getJSON at a time since switchMap will unsubscribe from previous inner Observables. So that also needed to be chained. Good catch!
I think you should be able to make takeUntil selective for a certain action id with pluck and filter.
ex:
.takeUntil(action%.ofType(FETCH_ATTRIBUTE_CANCEL)
.pluck('id')
.filter((cancelActionID) => cancelActionID === fetchID))
The non-obvious part to me is how to get the current fetchID to run that comparison. I might consider try using do to store in a temporary variable

symfony2 my own event

I made the authorization and authentication via facebook like here:
http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
and it works
Now I want to make my own event, this event will do something when the user authenticates using facebook. For example-will redirect the user to the home page.
I did it like this
http://symfony.com/doc/current/components/event_dispatcher/introduction.html
So I have this class
http://pastebin.com/2FTndtL4
I do not know how to implement it, what am I supposed to pass as an argument to the constructor
It's really simple. Symfony 2 event system is powerful, and service tags will do the job.
Inject the dispatcher into the class where you want to fire the event. The service id is event_dispatcher;
Fire the event with $this->dispatcher->dispatch('facebook.post_auth', new FilterFacebookEvent($args)) when needed;
Make a service that implements EventSubscriberInterface, defining a static getSubscribedEvents() method. Of course you want to listen to facebook.post_auth event.
So your static method will look like:
static public function getSubscribedEvents()
{
return array(
'facebook.post_auth' => 'onPostAuthentication'
);
}
public function onPostAuthentication(FilterFacebookEvent $event)
{
// Do something, get the event args, etc
}
Finally register this service as a subscriber for the dispatcher: give it a tag (eg. facebook.event_subscriber), then make a RegisterFacebookEventsSubscribersPass (see this tutorial). You compiler pass should retrieve all tagged services and inside the loop should call:
$dispatcher = $container->getDefinition('event_dispatcher');
$subscribers = $container->findTaggedServiceIds('facebook.event_subscriber');
foreach($subscribers as $id => $attributes) {
$definition->addMethodCall('addSubscriber', array(new Reference($id)));
}
This way you can quick make a subscriber (for logging, for example) simply tagging your service.
Event object is just some kind of state/data storage. It keeps data that can be useful for dispatching some kind of events via Subscribers and/or Listeners. So, for example, if you wanna pass facebook id to your Listener(s) - Event is the right way of storing it. Also event is the return value of dispatcher. If you want to return some data from your Listener/Subscriber - you can also store it in Event object.

Resources