Search code examples
backbone.jsmarionette

Marionette js 3+: whose responsibility to handle the situation when the validation failed?


There is view of registration form. When some one put data and click registration button: created model and after model.save() starting a validation.

The idea: when validation failed, mark form inputs as has-error

My code: view

class App.Views.RegisterView extends Marionette.View
    template: _.template(App.Templates['regFormTpl.ejs'])
    ui:
        registrate: '#reg-button'

    events:
        'click @ui.registrate': 'customerRegistration'

    customerRegistration: (e) ->
        e.preventDefault()

        regData = new App.Models.RegData
            login: $('#login').val()
            email: $('#email').val()
            password: $('#password').val()
            confirmPassword: $('#password_confirm').val()


        if regData.save()
            console.log ('done')
        else
            console.log ('false')

model

class App.Models.RegData extends Backbone.Model
    urlRoot: '/someurl'

    defaults:
        login: ''
        email: ''
        password: ''
        confirmPassword: ''

    validate: (attrs) ->
        console.log(attrs)

        errors = {}

        if attrs.login.length < 5
            errors.username = 'error desc'

        if attrs.password != attrs.confirmPassword
            errors.password = 'error desc'

        unless _.isEmpty(errors)
            return errors

I have my doubts about whose responsibility to handle the situation when the failed validation

I have no experience in the development of this framework. As I read the guides... earlier it was controller which trigger Event which one was listened by view.

In Mn 3+ controller was removed.


Solution

  • You can user your "View" itself as the responsible to handle the display of the errors in your form since this has access to the DOM elements.

    In this example it is required the fields 'id' in your form and in your errors map matches.

     customerRegistration: (e) ->
       ...
       // remove previous errors
       this.cleanFormErrors();
    
       if (!regData.isValid()) {
         _.each(regData.validationError, fieldName => this.showFormError(fieldName)); 
       }
       ...
     showFormError: (fieldId) ->
       this.$el('[#' + fieldId + ']').addClass('has-error');
    
     cleanFormErrors: () ->
       this.$el.find('.has-error').removeClass('has-error');
    

    Eventually these two methods can be delegated to a Marionette.Behavior to be able to reuse the logic in other Views, like:

    class App.Behaviors.DisplayErrors extends Marionette.Behavior
      onShowFormError: (fieldId) ->
        this.$el('[#' + fieldId + ']').addClass('has-error');
    
      onCleanFormErrors: () ->
        this.$el.find('.has-error').removeClass('has-error');
    

    Here is the modified View code using behaviors:

    class App.Views.RegisterView extends Marionette.View
       behaviors: {
         'errorsBehavior': {
           'behaviorClass': App.Behaviors.DisplayErrors
         }
       }
      customerRegistration: (e) ->
        ...
       this.triggerMethod('clean:form:errors');
       if (!regData.isValid()) {
         _.each(regData.validationError, fieldName =>   this.triggerMethod("show:form:errors")); 
       }
       ...
    

    Hope this can guide you to solve your question.