Ember数据模型的错误属性(DS.Errors)未填充

Joh*_*ika 12 ember.js ember-data

我正在使用Ember Data,我似乎无法获得模型的'errors'属性来填充来自我的REST API的错误消息.我非常关注本指南中的示例:

http://emberjs.com/api/data/classes/DS.Errors.html

我的应用程序如下所示:

    window.App = Ember.Application.create();

    App.User = DS.Model.extend({
        username: DS.attr('string'),
        email: DS.attr('string')
    });

    App.ApplicationRoute = Ember.Route.extend({
        model: function () {
            return this.store.createRecord('user', {
                username: 'mike',
                email: 'invalidEmail'
            });
        },

        actions: {
            save: function () {
                this.modelFor(this.routeName).save();
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

我的API返回:

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 125

{
  "errors": {
    "username": ["Username is taken!"],
    "email": ["Email is invalid."]
  }
}
Run Code Online (Sandbox Code Playgroud)

在模型上调用save()后,我在用户模型上看到的是:

user.get('isError') // true
user.get('errors.messages') // []
Run Code Online (Sandbox Code Playgroud)

即使模型正确地注册了isError属性,我也似乎无法填充错误消息.我怎样才能让它发挥作用?我正在研究Ember Data版本1.0.0-beta.8.2a68c63a的最新beta版本

Kin*_*n2k 10

这个区域肯定缺少文档,除非您使用的是活动模型适配器,否则不会填充错误.

这是一个工作的例子,也看看Ember:error.messages在保存时没有显示服务器错误我在说同样的事情

http://jsbin.com/motuvaye/24/edit

您可以通过覆盖ajaxError和复制活动模型适配器的工作方式,在RESTAdapter上轻松实现它.

App.ApplicationAdapter = DS.RESTAdapter.extend({

  ajaxError: function(jqXHR) {


    var error = this._super(jqXHR);

    if (jqXHR && jqXHR.status === 422) {
      var response = Ember.$.parseJSON(jqXHR.responseText),
          errors = {};

      if (response.errors !== undefined) {
        var jsonErrors = response.errors;

        Ember.EnumerableUtils.forEach(Ember.keys(jsonErrors), function(key) {

          errors[Ember.String.camelize(key)] = jsonErrors[key];
        });
      }
      return new DS.InvalidError(errors);
    } else {
      return error;
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

http://jsbin.com/motuvaye/27/edit

https://github.com/emberjs/data/blob/v1.0.0-beta.8/packages/activemodel-adapter/lib/system/active_model_adapter.js#L102


Joh*_*ika 8

我对Ember Data的errors.messages属性有过长期非常令人沮丧的经历,所以我想我总结了我的所有发现,以防其他人试图使用这个功能.

1)文档已过期

正如@ kingpin2k在他的回答中提到的那样,http : //emberjs.com/api/data/classes/DS.Errors.html上的文档已经过时了.他们在该页面上提供的示例仅在您使用DS.ActiveModelAdapter时才有效.如果您使用的是默认的DS.RESTAdapter,那么您需要执行类似的操作.请注意,我更喜欢这种更简单的方法,而不仅仅是复制ActiveModelAdapter的ajaxError实现:

App.ApplicationAdapter = DS.RESTAdapter.extend({
    ajaxError: function (jqXHR) {

        this._super(jqXHR);

        var response = Ember.$.parseJSON(jqXHR.responseText);
        if (response.errors)
            return new DS.InvalidError(response.errors);
        else
            return new DS.InvalidError({ summary: 'Error connecting to the server.' });
    }
});
Run Code Online (Sandbox Code Playgroud)

2)您必须提供拒绝回调

这很奇怪,但是当你在你的模型上调用save()时,你需要提供一个拒绝回调,否则,你将得到一个未被捕获的'后端拒绝提交'异常,JavaScript将停止执行.我不知道为什么会这样.

没有拒绝回调的示例.这将导致异常:

    user.save().then(function (model) {
        // do something
    });
Run Code Online (Sandbox Code Playgroud)

拒绝回调的示例.一切都会运作良好:

    user.save().then(function (model) {
        // do something
    }, function (error) {
        // must supply reject callback, otherwise Ember will throw a 'backend rejected the commit' error.
    });
Run Code Online (Sandbox Code Playgroud)

3)默认情况下,只有作为模型一部分的错误属性才会在errors.messages中注册. 例如,如果这是您的模型:

App.User = DS.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string')
});
Run Code Online (Sandbox Code Playgroud)

...如果这是你的错误有效载荷:

{
    "errors": {
        "firstName":"is required",
        "summary":"something went wrong"
    }
}
Run Code Online (Sandbox Code Playgroud)

然后摘要不会出现在user.get('errors.messages')中.可以在Ember Data的adapterDidInvalidate方法中找到此问题的根源.它使用this.eachAttribute和this.eachRelationship将错误消息的注册限制为仅属于模型的那些消息.

  adapterDidInvalidate: function(errors) {
    var recordErrors = get(this, 'errors');
    function addError(name) {
      if (errors[name]) {
        recordErrors.add(name, errors[name]);
      }
    }

    this.eachAttribute(addError);
    this.eachRelationship(addError);
  }
Run Code Online (Sandbox Code Playgroud)

这里有关于这个问题的讨论:https://github.com/emberjs/data/issues/1877

在Ember团队修复此问题之前,您可以通过创建一个覆盖默认的adapterDidInvalidate实现的自定义基本模型来解决此问题,并且所有其他模型都从中继承:

基本型号:

App.Model = DS.Model.extend({
    adapterDidInvalidate: function (errors) {
        var recordErrors = this.get('errors');
        Ember.keys(errors).forEach(function (key) {
            recordErrors.add(key, errors[key]);
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

用户模型:

App.User = App.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string')
});
Run Code Online (Sandbox Code Playgroud)

4)如果从适配器的ajaxError(我们上面覆盖的那个)返回DS.InvalidError,那么你的模型将停留在'isSaving'状态,你将无法摆脱它.

如果您使用DS.ActiveModelAdapter,也会出现此问题.

例如:

    user.deleteRecord();
    user.save().then(function (model) {
        // do something
    }, function (error) {

    });
Run Code Online (Sandbox Code Playgroud)

当服务器响应错误时,模型的isSaving状态为true,我无法在不重新加载页面的情况下重置它.

更新:2014-10-30 对于那些正在努力解决DS.Errors的人来说,这里有一篇很好的博客文章,总结了这一点:http://alexspeller.com/server-side-validations-with-ember-data-and-ds- 错误/