Skip to content
This repository has been archived by the owner on Sep 10, 2022. It is now read-only.

Where to call server api #1

Closed
mbinette opened this issue Feb 6, 2017 · 4 comments
Closed

Where to call server api #1

mbinette opened this issue Feb 6, 2017 · 4 comments

Comments

@mbinette
Copy link

mbinette commented Feb 6, 2017

I have a current solution based on optimizely/nuclear-js and heavily borrowed from home-assistant/home-assistant-js. It is similar in that there is a stateBehavior (the only behavior). Properties are defined with a bindState value that is a nuclear-js getter (function that returns the specified state). A simple example is

properties: {
  isAdmin: {
    type: Boolean,
    bindState: MyApp.authGetters.isAdmin,
  }
}

It is notified of changes and actions dispatched are used to update the state, just like uniflow. When saving a form we call an action which returns a promise. We can then wait for the response from the server and only leave the screen if successful, showing validation errors if necessary.

save: function() {
  if (this.$.form.validate()) {
    MyApp.userActions.saveUser(this.data).then(() => { 
        this.fire('user-save-clicked', this.user);
    });
  };
},

The MyApp.userActions.saveUser calls the backend server API to actually send the data and return any additional validation errors such as a non unique username error. It also updates other state such as the errorMessage to display on this screen. If the server returns an error, a Javascript error is thrown and the 'user-save-clicked' event is not fired. On success it is fired and an upstream component handles routing changes.

Where in uniflow should the calls to the server be put? I really like the ModelView validation method but where would it integrate with sending the data to the server and handling errors returned from the server? How would you wait to make sure it was successful before routing to a new screen?

I've reviewed the ToDoMVC app but of course it is only updating local state and not integrating with a server backend.

@militeev
Copy link
Contributor

militeev commented Feb 7, 2017

Good question, thank you. Calls to the server should only be put in action dispatchers, one [almost] never should make server calls from visual elements. Validation feature in model view is intended for client side validation. For persisting the data and server validation error I would recommend the following approach:

  • create action dispatcher for server calls. For example, SAVE_DATA is the action that would trigger validation and saving. Create [SAVE_DATA] method to make a server call. Program the method to emit DATA_SAVED action in case of success or INVALID_DATA in case of validation errors.
  • in your view action dispatcher create handlers for DATA_SAVED and INVALID_DATA actions. Then handler for DATA_SAVED may trigger routing to the new screen, whereas handler for INVALID_DATA would update status.validation property with error messages and invalid flags.

@mbinette
Copy link
Author

mbinette commented Feb 7, 2017

So the visual element calls the Model validation and if it passes, emits SAVE_USER. A <user-action-dispatcher> calls the backend API and handles the Promise. On success emits SAVE_USER_SUCCESS and failure SAVE_USER_FAILED. In a different action dispatcher we handle the SAVE_USER_SUCCESS and SAVE_USER_FAILED events.

This is a very similar workflow to what I am doing but I'm using the Polymer listeners to listen for the custom events fired. In one scenario the SAVE_USER functionality would be used from multiple pages. There might be a User Admin section to add and edit users and also a User Profile page that lets you modify yourself. Both use the same form and logic so both would call SAVE_USER.

I'm currently handling that using the Polymer listeners in a parent page that embeds the <myapp-user-edit> component which is the form and logic to call SAVE_USER. That way a success can redirect to the proper place depending on if it was used from the User Admin screen or from the User Profile screen.

I'm guessing that translates to putting a <user-admin-action-dispatcher> in the User Admin parent page and a <user-profile-action-dispatcher> in the User Profile parent page. Then each one can handle the SAVE_USER_SUCCESS differently. Does that sound about right?

@militeev
Copy link
Contributor

militeev commented Feb 7, 2017

All action dispatchers exist at the application level. It's up to the developer to logically associate action dispatchers with views, UniFlow doesn't prescribe one specific way. What we do in our project is setting extra options for actions; that gives you various options. Some action dispatchers may always process certain actions, some are conditional. For instance, in your scenario you may have view action property and make call as follows:
this.emitAction({ type: 'SAVE_USER', view: 'profilePage' }
Then user-profile-action-dispatcher will pick up the success action that has view set to "profilePage". You just need to make sure that your service action dispatcher passes through the options it receives to success/failure actions.
This is one of many ways to handle this scenario. Once again, there's no single preferred way.

@mbinette
Copy link
Author

mbinette commented Feb 9, 2017

Thanks. I just installed and am going to be testing out things today. Uni-flow is more straightforward and "Polymer-ish" than my existing method.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants