I want to perform an action based to the result of an asynchronous NGXS action.
In a Angular frontend app I'm using NGXS for state management. Some of the actions involve talking to a backend via REST calls. Those actions are implemented as asynchronous actions, with the reducer functions in my state classes returning an Observable.
What I'm looking for is a way to get hands on the result of the backend call, to be able to perform some action.
One use case I'm trying to implement is navigation to just created objects: Business objects are created in the frontend (Angular) app with a couple of domain properties. They get persisted in the backend, and as a result an ID for this object is created and returned to the frontend, and incorporated into the NGXS store. As a direct response to this, I'd like to navigate to a detail view for the new object. To do so, I need
(a) the information that the call has been returned successful, and
(b) the answer from the backend (the ID in this case).
Another slightly more complicated use case is the assignment of a number of tags to an business object. The tags are entities by themselfes, and have an ID each. In the UI, the user can either pick existing or add new tags. Either way, multiple tags can be added in a single step in the UI, which means I have to
call the backend for each new tag to create the ID
after all missing tags are created, update the business object with the list of tag IDs
In general, there are use cases in the frontend that depend on the result of a backend call, and there is no clean way to find this result in the store (although it's in there)
I know I can subscribe to the Observable returned from the store's dispatch method (as shown in asynchronous actions).
I also know about action handlers. In both cases I can attach code to the event of an action finished, but neither option enables me to get the result of the backend call. In the fist case, the Observable carries the whole store, while in the latter case I get the original Action, which is unfortunately missing the essential information (the ID).
The part you're missing here are selectors. Dispatching actions is not supposed to give you back a result. The only purpose of the Observable returned by store.dispatch() is to tell you when the action's handlers are done.
To get to the data returned by your calls to the backend, you have to patch the state inside your action handler. And then, outside of your state, you can access the data using store.select() or store.selectSnapshot() depending on what you need. Your state class should look somewhat like this (untested):
#State()
export class SampleState {
#Selector(SampleState)
sampleSelector(state) {
return state.sampleObject;
}
#Action(SampleAction)
sampleAction(ctx: StateContext<any>, action: sampleAction) {
return sampleBackendCall(/* ... */).pipe(
tap((result) => {
ctx.patchState({ sampleObject: result });
})
);
}
}
Now you can access this result where ever you need using the Store. For the use case of navigating to an element after its creation, you can combine a subscription to store.dispatch() with a store.selectSnapshot() like this:
store.dispatch(new SampleAction()).subscribe(() => {
navigateTo(store.selectSnapshot(SampleState.sampleSelector));
});
Note that in this easy case a selectSnapshot is perfectly fine, as we only want to get the value we just finished writing into the state. In most cases though, you will want to use store.select() or the #Select() decorator because they return Observables which enable you to also correctly display changes in your state.
That said, I'd like to add that if saving data inside the state is not necessary for you at all, then probably NGXS is the wrong library for you in the first place and you could as well just use an ordinary angular service directly returning the result of the backend call, like suggested in the comments.
Related
Apologies if I've just managed to miss it in the docs, but I can't find a way to do this in Apollo Client.
I've read about query batching, but this in fact the opposite of what I want to do. I want my queries sent as separate isolated queries.
Happy to expand on details if needed, but I think the title says it all.
so, my solution has been to create a new component that
returns null (i.e. renders nothing)
runs a useQuery and puts the result into an array (who's setter is passed in from the parent)
This new component sits inside a loop that iterates all my different variable sets that I want to fire the query with.
I am so confused about how to implement and how to follow SRP (single responsibility principle ) in a Laravel controller.
Suppose we have a controller which we have to do these things:
e.g
public function StorePost() {
// check user login()
//check number of current user Post count =>which must be less than 10
//store post
//send an email to user which your post has saved
//return =>api:json /web : redirect
}
I know that I can implement some DB queries in the repository but I don't know how to implement others of my logic code to achieve SRP
Also, I know there is a Heyman package to achieve these but I want to implement it by myself.
SRP in this context basically means each class and method should only be responsible for a single behaviour/feature. A rule of thumb is a class or method should change for one reason only, if it changes for multiple reasons, it needs to be broken down into smaller parts.
Your storePost method should not bother with checking the user login, that should be handled elsewhere before invoking storePost. storePost shouldnt change if the auth mechanism changes like switching from api token to json web token or something else. Laravel does this in the middleware level with the auth middleware.
Checking the users post count, this can be checked in the validation stage. storePost shouldn't change if we add more validation logic. In Laravel you can use FormValidation for this
For storing the post, the controller doesn't need to know how to call the DB, you can use the active record style using the model class or maybe create a service or repository class if your use case requires that. storePost shouldn't change if we decide to change DB vendor like going NoSQL.
For sending email, again the controller doesnt need to know how to send the email like what the subject/body recipients are. storePost shouldnt change if we need to change the email layout. Laravel has Notification for that
For serialising the response to json, the controller doesnt need to know how to format the response. if we decide to update how our json looks, storePost shouldnt change. Laravel has API Resources for that
So, ultimately in this example, the responsibility of the controller method is basically to glue all these together. It basically does what you wrote down, it only responsible for maintaining the step by step behavior, everything else is delegated to someone else. if the behavior change, like adding new behavior e.g notify all follower, storePost will change.
I'm writing a restful redux/react app.
My desired output is such.
INPUT_CHANGE-->
(state = {valid: false})->REDUCER->(state = {valid: true})-->
AJAX CALL
From the redux documentation, async javacript is supposed to be called from the action creator, but I don't understand how to get to the action creator once the state changes from valid:false to valid:true.
Since this is a react app, I could change a hidden input called valid, which has an onChange action creator attached to it, but this seems like an unneccessary extra step. Any ideas?
My general preference is to have the action creators handle all async operations. So the validation operation in this question is comparable to the shouldFetchPosts function in http://rackt.org/redux/docs/advanced/AsyncActions.html
The action creator would then be something like inputChangeAndSubmitIfValid which corresponds to that file's fetchIfNeeded action creator.
On very rare occasions I implement an observer for catching store changes, but I always try to find a better action oriented way first.
I have read a lot of answers relating to how to dynamically add forms to an model formset in Django and can successfully implement that. However, I would now like to submit the formset with AJAX. This is mostly working now but I have an issue that I can't find a solution to in any other answer:
If you dynamically add a form to the formset, you give it a new form id number that is one larger than the maximum the form currently has and you also increment the management TOTAL_FORMS count by one. The newly added form then saves successfully as a new object.
I am trying to submit by AJAX so the user can continue editing without having the page refresh. The formset saves fine but any dynamically added forms are now existing objects. To account for this I need to increment the INITIAL_FORMS count on the management form when the save is successful. Easy enough. However, I've also realised I need to give the newly created objects an ID since they now exist in the database.
How can I get my view to tell me the ID of the new objects in its response to the AJAX call? Or is there a better way of looking at this?
Django forms and formsets are intended for classic browser-based posting of data. Though they can definitely be made to work with Javascript, the more you want to part from the normal behavior, the more complex it gets.
Depending on your requirements, you might start thinking about dropping it and switch to Javascript + REST endpoint. Of course, if you need progressive enhancements and you are required to have it work without javascript, that's not an option.
In any case, you want to have a customized view for posting from JS, so that you can get the result back and parse it easily in your AJAX handler. Probably some JSON.
There are several approaches you could take.
Have your AJAX send data to a different URL. This is pertinent if you have an API or are planning to build one at some point. So your form, when submitted normally, will do its old-style processing but your AJAX will talk to the API endpoint instead.
For instance, your form send to https://example.com/myform, but your Javascript code talks to REST api at https://example.com/api/v1/mymodel/ (sending PUT, POST and DELETE requests as appropriate).
Or if you don't have an API and building one seems overkill, you may just alter your view so it formats its output differently depending on whether the data is being submitted in the regular way or using AJAX.
You'd go about it like this:
class MyFormView(.....):
def render_to_response(self, context, **kwargs):
if self.request.is_ajax():
return self.render_to_json(context, **kwargs)
return super().render_to_response(context, **kwargs)
def render_to_json(context, **kwargs):
data = {
# see below!
}
return HttpResponse(
content=json.dumps(data).encode('ascii'),
content_type='application/json',
)
This is just an outline. You need to ensure is_ajax will detect it properly (see django doc). And you need to properly build data from context: extract the things you want to send back to your JS code and put them in the dict.
You will find it's manageable if you just do this for one, maybe two views in your project, but very quickly you'll want to have a small API instead, especially given how easy it is to build one with packages such as Django REST framework.
In your view, where you save the object, AFTER the save, the object.id will contain the new id for the object, which you can return via json or however you want in your ajax response, and then yes you will need to fill that into the formset row so that it will be submitted the next time.
One thing you have to watch out for is that django expects all existing rows to be at the top of the formset, and any new rows to be at the bottom. Otherwise, the formset save will complain about missing id's. So if you're doing any kind of sorting in your javascript, you can't do that.. unless you do quite a bit of fixing of all the field names etc in the formset. The formset code uses the numbers in the management form to determine which rows to insert and which rows to update, it does not do it on the basis of whether or not an id is present. Unfortunately...
In Parse there is something called:
Parse.Cloud.beforeSave
I wonder if there is something to play the role of a:
Parse.Cloud.beforeRead
I need a way to control what is going to be returned to the user when a request is made to the DB.
In particular in certain circomstances, depending on information on the server, I want to force blank fields in the result of the DB request made by the user. Any standard way to do this?
There is no Parse.Cloud.beforeRead kind of function supported by Parse.
Instead, you can define a custom cloud function using
Parse.Cloud.define('readObjects', function(request, response) {...} );
that returns array of objects. This function will act as a wrapper over the Parse query.
Then, your client apps should be calling this cloud function to fetch objects rather than direct Parse.Query requests.