Search code examples
javascriptvalidationbackbone.jsbackbone-views

Backbone model state when tied to a form


I'm building a form with Backbone and looking to have it validate its fields on the "blur" event.

Hooking into the event is easy enough, but what I'm curious about is whether or not the model should be updated on blur or only when the form is submitted?

Updating model on blur

  • model.set({...}, {validate:true});
  • if your model has multiple attributes, validation will be run for all of them, every time
  • when creating a new item, the model state isn't as important because it's probably not shared with any other modules yet
  • when editing an item, the model is in this weird outdated/updated state, depending on where the person is in the form. What if the model is being shared between multiple modules?

Updating model on submit

  • can't use model.set() for validation, so the model needs to expose some validation methods (eg MyModel.validZip())
  • on submit, even though all fields have been validated, set() needs to be called to update the model, which will cause validation to happen one more time (not entirely sure this is bad though)

I've read through a couple of relevant Backbone github issues (1, 2, 3) and Backbone devs seem to draw a line between a model and a form.

Additionally, the Backbone.Form plugin appears to keep an internal fields property to track the form fields and when done, call .commit() to update the model.

So it seems like updating the model on submit is the better approach. Is that the experience you've had?


Solution

  • Proper UX in forms is tricky. I have tried both of your approaches in the past. In my opinion, there is a third option: always keep a model in-sync with your view's state.

    This short video highlights some of my reasoning: http://screencast.com/t/qukIe6XW5.

    In this video, I am typing into a form. The form auto-updates to show how many characters I have typed and how many are allowed. It's good UX to to provide instantaneous feedback rather than making the user remove focus from the form, find out they have validation errors, and then come back to the form. In order to achieve this, you'll need to be able to know the state of your view at all times.

    But I don't want my model's state to be updated automatically! The user needs to press submit first!

    It sounds like introducing another class of models would make your life a lot easier. Consider creating a viewmodel which keeps a reference to the instance of your model. With the introduction of a viewmodel you will be able to record the changes to your view without affecting the state of your model. This helps mitigate the risk of bad things happening and, if anything does go awry, your server will be able to catch the changes and fail with server-side validation.

    Here are some links to my source for doing in-place editing:

    You'll see that I give EditPlaylistPromptView an EditPlaylistPrompt model which stores a reference to the playlist being edited. However, it doesn't directly modify that playlist while the user is working on the view. It just updates the playlist once it passes validation. Note that I'm not going through the model for validation, but I could be, just slacking on that aspect of it.

    Here's a picture of how I like to visualize things. It is completely true that a model should be concerned about a view to enforce separation of concerns. However, that's only when you're working with 3 layers of objects. Be more flexible, introduce a new, intermediary layer called a ViewModel and your life gets simpler:

    enter image description here