绑定到表单时的骨干模型状态

时间:2014-12-17 00:11:04

标签: javascript validation backbone.js backbone-views

我正在使用Backbone构建一个表单,并希望在“模糊”事件中验证其字段。

加入这个事件很容易,但我很好奇的是模型是否应该在模糊时更新或仅在表单提交时更新?

更新模糊模型

  • model.set({...}, {validate:true});
  • 如果您的模型具有多个属性,则每次都会对所有属性运行验证
  • 在创建新的项目时,模型状态并不重要,因为它可能尚未与任何其他模块共享
  • 编辑时,模型处于此奇怪的过时/更新状态,具体取决于人员在表单中的位置。如果模型在多个模块之间共享怎么办?

在提交时更新模型

  • 无法使用model.set()进行验证,因此模型需要公开一些验证方法(例如MyModel.validZip()
  • 提交时,即使所有字段都已经过验证,也需要调用set()来更新模型,这将导致验证再次发生(不完全确定这是不好的)

我已经阅读了几个相关的Backbone github问题(123),Backbone开发人员似乎在模型和表单之间画了一条线。

此外,Backbone.Form插件似乎保留内部fields属性以跟踪表单字段,完成后,请调用.commit()更新模型。

因此,似乎在提交时更新模型是更好的方法。那是你的体验吗?

4 个答案:

答案 0 :(得分:6)

表单中的正确用户体验非常棘手。我过去曾试过你的两种方法。在我看来,还有第三种选择:始终让模型与您的观看状态保持同步。

这段简短的视频突出了我的一些推理:http://screencast.com/t/qukIe6XW5

在这段视频中,我正在输入一个表格。表单自动更新以显示我输入的字符数和允许的字数。提供即时反馈而不是让用户从表单中删除焦点,发现他们有验证错误,然后回到表单,这是一个很好的用户体验。为了实现这一目标,您需要始终能够了解您的观点状态。

  

但我不希望我的模特状态自动更新!用户需要先按提交!

这听起来像引入另一类模型会让你的生活更轻松。考虑创建一个viewmodel,它保留对模型实例的引用。通过引入视图模型,您将能够在不影响模型状态的情况下记录视图的更改。这有助于降低发生错误事件的风险,如果出现任何问题,您的服务器将能够捕获更改并通过服务器端验证失败。

以下是我的来源进行就地编辑的链接:

您将看到我向EditPlaylistPromptView提供EditPlaylistPrompt模型,该模型存储对正在编辑的播放列表的引用。但是,在用户处理视图时,它不会直接修改该播放列表。它只是在通过验证后更新播放列表。请注意,我没有通过模型进行验证,但我可能会,只是放松它的那个方面。

这是我想要如何形象化的图片。完全正确的是,模型应该关注强制分离关注点的观点。但是,只有当您使用3层对象时才会这样。更灵活,引入一个名为ViewModel的新中间层,让您的生活变得更简单:

enter image description here

答案 1 :(得分:4)

在提交时更新模型似乎是一种更好的方法。 Backbone是一个MVC框架(更多的是MV *,但设计遵循相同的原则)。话虽这么说,控制器的重点是有一个专门用于限制或控制用户如何与数据(模型)交互的单独层。因此,只有让用户更新模型直到所有内容都有效才符合传统的MVC逻辑。

此外,您只需在用户提交后进行验证,并且基本上已经说过这就是我想要的东西'。模糊更新可以预先验证信息。

参见维基百科MVC:" [MVC]将给定的软件应用程序划分为三个相互关联的部分,以便将信息的内部表示与信息呈现给or accepted from the user"

的方式分开。

答案 2 :(得分:3)

这取决于您希望用户与您的应用进行互动的方式。如果您希望事物始终保持同步(例如谷歌文档),您可以在“更改”上更新模型,然后在“模糊”或某个特定时间间隔内提交到后端。

如果您希望用户必须单击“提交”,最好不要在准备好将数据发送到后端之前更新模型。

答案 3 :(得分:3)

我只能从我的经验中看出,这显然是非常自以为是。

我不喜欢在模型上实际设置值,而不首先询问服务器是否有值更改是否足以提交,因此广播到最终显示的所有模块或取决于模型有问题的对象。服务器很可能不接受输入,即使它通过了客户端能够检查的所有条件(例如有效的电子邮件,但在服务器上不是唯一的)。 话虽这么说,一些输入应该并且可以立即验证,而不首先询问后端。最终,它可能会成为“两全其美”。狡猾的智慧,我知道;)。

这里最重要的是能够回滚到先前的有效状态,无论过程的哪个部分导致失效。我指的是你上面提到的这个奇怪的过时/更新状态。如果“计算机说是”(后端,那就是),我们只能绝对确定更改的正确性。

现在,如何实现这一目标?这里有两种方法(两个例子的前提条件:所有模型对象都有一个唯一的ID属性,如果不是,我们说的是“创建”):

修改临时对象,如果验证,则镜像到实际对象。

  • 让表单代表一个新的模型对象,无论我们是在说“更新”还是“创建”。您可以通过稍后询问ID来完全区分这两者:

    // update
    var tempModel = new MyModel(modelToUpdate.serialize());
    // or create
    var tempModel = new MyModel();
    
  • set和/或submit对象值取决于您要提供的用户体验。我将验证过程尽可能通用,并始终验证对象(每个键/值对)作为一个整体。稍后再详细说明。

  • 如果是有效(且完整)的修改过程,请将更改镜像回实际模型对象或创建新对象:

    var model;
    if (tempModel.isValid() === false) {
        // report Error
    } else if (tempModel.get('id')) {
        model = modelToUpdate.set(tempModel.serialize()).save();
    } else {
        model = tempModel.save();
        // do what you got to do with a new model object
    }
    
  • 主要缺点:只要您不跟踪临时创建的模型对象,应用程序的其他部分就不会知道即将发生的更改。

将当前状态保存在临时对象中,如果验证失败,则回滚到其状态。

  • 在修改过程开始之前保存模型对象的当前和希望有效状态:

    var currentlyValid = new MyModel(modelToUpdate.serialize());
    
  • set和/或submit您认为合适的实际对象。你应该不再关心特定的键/值对,但要确保整个对象是有效的。这里的主要优点是应用程序的其他部分依赖于和/或显示有问题的对象,将保持同步。主要缺点:你必须分别处理新项目的创建。

  • 如果修改得到验证,则会丢失临时对象。如果没有,请回滚到先前保存的状态。

    if (modelToUpdate.isValid()) {
        var currentlyValid = null;
        modelToUpdate.save();
    } else {
        modelToUpdate.set(currentlyValid.serialize());
    }
    
  • 主要观点:我想不出用这种方法创建新对象的简化方法。取决于实施,我猜。

我更喜欢第一种方法。如果所有关于同步应用程序的其他部分应该在模型对象上显示当前临时对象 on blur 的更改,可以建立一个具有指向属性的应用程序模型对象在后者,并在临时对象被修改时触发更改事件:

var app = MyApplication({
    modelThatIsGettingModified: <Reference to the temp object>; 
});

为什么我们不使用previousAttributes回滚?

因为通过客户端验证的每个set调用都将修改此模型属性的返回,无论整个对象是否得到服务器确认。

关于验证的一个词

鉴于Backbone模型的验证方法......

  

...未定义,我们鼓励您覆盖它   使用自定义验证逻辑,如果你有任何可以   在JavaScript中执行...(来源Backbone docs

...我建议您始终对所有键/值对进行验证。可能会产生一些开销,这是肯定的,但这可以让你统一验证过程。我非常了解123,但说实话,只要您控制DOM,这些事情就不会减慢您的应用。简化验证过程在这里更为重要。 如果这些裁员会对您的事物的表现产生影响,you probably shouldn't be using Backbone at all IMHO