Slevin
Slevin

Reputation: 4222

How to show error messages in template after becameInvalid method

I'm using Ember.js to display a list of customers. Inside this template, I have a modal to create new customers. Now, when creating invalid customers (e.g. duplicate name), the errors should be shown in the template. How can I get this to work?

model

Docket.Customer = DS.Model.extend({
  name:        DS.attr('string'),
  initial:     DS.attr('string'),
  description: DS.attr('string'),
  errors: {},
  becameInvalid: function(errors) {
    this.set('errors', errors.get('errors'));
    console.log(this.get('errors'));
  }
});

console output

enter image description here

template

<h1>Customers<button data-uk-modal="{target:'#customer-modal'}" class="icon-plus">New customer</button></h1>

    <div id="customer-modal" class="uk-modal">
        <div class="uk-modal-dialog uk-modal-dialog-slide">
            <a class="uk-modal-close uk-close"></a>
            <form class="uk-form" {{action "save" on="submit"}}>
                <fieldset>
                    <legend>New customer</legend>
                    <div class="uk-form-row">
                        {{view Ember.TextField valueBinding="name" name="name" class="uk-width-1-1" placeholder="Name" required="" }}
                        {{#if errors}}foo{{/if}}
                        {{#if errors.name}}{{errors.name}}{{/if}}
                    </div>
                    <div class="uk-form-row">
                        {{view Ember.TextField valueBinding="initial" name="initial" class="uk-width-1-1" placeholder="Initial" required="" }}
                    </div>
                    <div class="uk-form-row">
                        {{view Ember.TextArea valueBinding="description" name="description" class="uk-width-1-1" placeholder="Description"}}
                    </div>
                    <div class="uk-form-row">
                        <button type="submit" class="icon-check">Save</button>
                    </div>
                </fieldset>
            </form>
        </div>
    </div>

    <ul class="entries">
    {{#each}}
       <li>
           <div class="actions">
               <button {{action "remove" id}} class="icon-close"></button>
           </div>
           <div class="link" {{action "edit" id}} data-uk-modal="{target:'#customer-modal'}">
                <span class="initial">{{initial}}</span>{{name}}
            </div>
       </li>
    {{else}}
        <li>No customers</li>
    {{/each}}
    </ul>

Upvotes: 4

Views: 5141

Answers (3)

Slevin
Slevin

Reputation: 4222

I figured it out:

setup

  • Ember 1.2.0
  • Ember Data 1.0.0-beta.4+canary.7af6fcb0
  • Handlebars 1.1.2 runtime

model

Docket.Customer = DS.Model.extend({
  name:        DS.attr('string'),
  initial:     DS.attr('string'),
  description: DS.attr('string'),
  number:      DS.attr('string'),
  archived:    DS.attr('boolean')
});

controller

var _this = this;

// Create new record
var customer = this.store.createRecord('customer', data);

// Check for server errors (422) when saving
customer.save().then(function(){
  _this.resetAndCloseForm(form);
}, function(response){
  _this.set('errors',response.errors);
});

route

model: function() {
  this.store.find('customer');
  return this.store.filter('customer', function(customer) {

    // prevent Ember to insert new elements to the DOM if they are invalid
    // .get('isValid') returns always true, I think this is a bug, so I'm checking the ID
    return customer.get('id')
  })
}

template

{{#if errors}}{{errors.name}}{{/if}}

Upvotes: 2

Alex Navasardyan
Alex Navasardyan

Reputation: 536

You should consider moving your validations to the controller. Form validations and validations in general are very contextual. Customer model might have different set of validations depending on which part of your app you're in.

If you decide to move validations to the controller, you would need to create an observer that is going to watch the changes of a particular property/properties and run validations accordingly.

Note: I'm talking about client side validations (doesn't involve talking to the server before validations conditions are met), not server side ones.

App.CustomerController = Ember.ObjectController.extend({
  errors: [],
  runNameValidation: function() {
    // run validations for 'name'
    // if validations fail, push error to 'errors' array
    // on the controller
  }.observes('model.name')
});

There's a validations library that takes care of it for you (it abstracts out validations bit and wraps it into a validations mixin for better reuse). Also, if you use for form specifically, you should consider looking at easyForm.

Update:

If you want to use server side validations, then all you need to add to your template is:

{{model.errors}}

When you try to save ED model and it server fails to do it, model is going to have errors array which you can use. Also, I would suggest creating the errors component, instead of creating the errors helper.

Upvotes: 3

Marcio Junior
Marcio Junior

Reputation: 19128

You can create a custom handlebars helper, like the following:

Ember.Handlebars.helper('show-errors', function(errors) {
    var html = '';
    if (errors) {        
        html += '<ul>';
        $.each(errors, function(key, values) {
            html += '<li>' + key + ' - ' + values.join(',') + '</li>'
        });
        html += '</ul>'
    }    
    return html.htmlSafe();
})

So just use {{show-errors recordInstance.errors}} in some template to use it.

In the first moment, there isn't errors so nothing will be displayed. When your record has a error, errors hash will be populed and the template will be updated.

Give a look in this fiddle http://jsfiddle.net/marciojunior/vh6aL/

Upvotes: 3

Related Questions