表单和数据库中的不同数据类型以及前向和后向转换

时间:2015-06-30 16:44:14

标签: meteor meteor-autoform

我觉得这很容易但是,是的......事实并非如此。我已经发布了一个朝着同一方向发出的问题,但提出了另一个问题。

我想做什么

我有歌曲的集合,它具有时间属性(歌曲的播放时间)。在表单验证和后端验证中,此属性应处理不同!

!我想用autoform(和simple-schema / collection2)为我提供的东西。如果那可能......

  • 表单中,时间应输入并验证为符合正则表达式/^\d{1,2}:?[0-5][0-9]$/字符串(因此格式“mm:ss “ mmss )。
  • 数据库中,它应存储为数字

我尝试做什么

1。 “formToDoc-way”

这是我的javascript

// schema for collection
var schema = {
    time: {
        label: "Time (MM:SS)",
        type: Number // !!!
    },
    // ...
};
SongsSchema = new SimpleSchema(schema);
Songs.attachSchema(SongsSchema);

// schema for form validation
schema.time.type = String // changing from Number to String!
schema.time.regEx = /^\d{1,2}:?[0-5][0-9]$/;
SongsSchemaForm = new SimpleSchema(schema);

这是我的模板:

{{>quickForm
   id="..."
   type="insert"
   collection="Songs"
   schema="SongsSchemaForm"
}}

我想要的工作流程是:

  1. 使用架构
  2. 将时间验证为String
  3. 时间正在转换为秒(数字)
  4. 时间在后端验证为数字
  5. 歌曲存储
  6. 回来的路。

    我首先尝试使用钩子formToDoc并将字符串转换为秒(数字)。

    问题:

    我发现,通过给定架构(对于表单)的表单验证发生在转换为`formToDoc之后,因此它已经是一个数字验证为字符串失败。
    这就是为什么我寻找另一个在验证表单后触发的钩子。这就是我尝试的原因......

    2。 “before.insert-way”

    我使用了钩子before.insert和数据库的工作方式!

    AutoForm.hooks({
        formCreateSong: {
            before: {
                insert: function (doc) {
                    // converting the doc.time to Number (seconds)
                    // ...
                    return doc;
                }
            },
    
            docToForm: function (doc) {
                // convert the doc.time (Number) back to a string (MM:SS)
                // ...
                return doc;
            }
        }
    });
    

    问题:

    当我实施update - 表单时,docToForm未被调用,因此更新形式中的数值是(以秒为单位)。

    的问题:

    1. 如何从数据库返回到表单的路上,所以从秒转换为字符串MM:SS?
    2. 有没有更好的方法来处理这个用例(表单验证和后端验证中的不同数据类型)?
    3. 我正在寻找一种解决这个问题的“流星自动”方法。

      非常感谢你阅读并希望得到一个好的答案; - )

2 个答案:

答案 0 :(得分:0)

我觉得time应该在视图内部而不是在模型内部格式化。所以这里是time我使用的模式:

...
function convertTimeToSeconds (timeString) {
  var timeSplit = timeString.split(':')
  return (parseInt(timeSplit[0]) * 60 + parseInt(timeSplit[1]))
}

time: {
  type: Number,
  autoValue: function () {
    if(!/^\d{1,2}:?[0-5][0-9]$/.test(this.value)) return false
    return convertTimeToSeconds(this.value)
  }
}
...

这当然有一个小缺点。您不能再使用quickForm - 帮助程序,但必须使用autoForm

然后显示值{我只需find songs,然后写一个帮手:

Template.registerHelper('formateTime', function (seconds) {
  var secondsMod = seconds % 60
  return [(seconds - secondsMod) / 60, secondsMod].join(':')
})

在你的模板中:

{{ formatTime time }}

答案 1 :(得分:0)

简单的答案是不验证字符串,验证字符串转换成的数字。

使用simpleschema,您所要做的就是创建自定义验证。该自定义验证将获取字符串,将其转换为数字,然后验证该数字。

然后,当你从数据库中取出它时,你必须拿下那个数字&将其转换为字符串。现在,simpleschema本身并没有做到这一点,但在你的表单中做起来很容易。

现在,如果你想获得幻想,请按照我的建议:

添加新架构字段:

SimpleSchema.extendOptions({
  userValue: Match.Optional(Function),
  dbValue: Match.Optional(Function),
});

然后,在time字段中添加一个函数(存储为日期字段):

    userValue: function () {
      return moment(this.value).format('mm:ss');
    },
    dbValue: function () {
      return timeToNumber(this.value);
    }

然后,创建一个将timeString转换为数字的函数(快速而肮脏的示例,您必须添加错误检查):

function timeToNumber(str) {
  str.replace(':',''); //remove colon
  var mins = +str.substr(0,2);
  var secs = +str.substr(2,2);
  return mins * 60 + secs; 
}

然后,对于实时验证,您可以使用schema.namedContext().validateOne。要更新数据库,只需发送timeToNumber(input.value)即可。