Различные типы данных в форме и базе данных и прямое и обратное преобразование
Я думал, что это будет легко, но, да... это было не так. Я уже разместил вопрос, который шел в том же направлении, но сформулировал другой вопрос.
Что я хочу сделать
У меня есть коллекция песен, которая имеет атрибут времени (время воспроизведения песни). Этот атрибут должен обрабатываться по-разному в проверке формы и проверке на сервере!
! Я хотел бы сделать это с тем, что мне предлагает автоформа (и simple-schema / collection2). Если это возможно...
- в форме время должно быть введено и проверено как строка, которая соответствует регулярному выражению
/^\d{1,2}:?[0-5][0-9]$/
(так что либо формат "мм: сс" или ммсс). - в базе данных он должен храниться как номер
Что я пытался сделать
1. "FormToDoc-путь"
Это мой 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"
}}
Мой желаемый рабочий процесс будет:
- время проверяется как строка с использованием схемы
- время конвертируется в секунды (число)
- время проверяется как число в бэкэнде
- песня хранится
И обратный путь.
Я сначала попытался использовать крюк formToDoc
и преобразовал строку в секунды (число).
Эта проблема:
Я обнаружил, что проверка формы с помощью заданной схемы (для формы) происходит ПОСЛЕ преобразования в `formToDoc, так что это уже Number и проверка как String не удалась.
Вот почему я искал другой крюк, который срабатывает после проверки формы. Вот почему я пытался...
2. "Перед тем, как вставить"
Я использовал крючок 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
не был назван, поэтому в форме обновления было числовое значение (в секундах).
Вопросы:
- Как я могу сделать обратный путь из базы данных в форму, чтобы преобразование из секунд в строку MM:SS?
- Есть ли лучший способ, как справиться с этим вариантом использования (разные типы данных в форме проверки и бэкэнд-проверки)?
Я ищу "метеорный автоформ" способ решения этой проблемы.
Большое спасибо за чтение и, надеюсь, хороший ответ;-)
2 ответа
Простой ответ - не проверять строку, а проверять число, в которое преобразуется строка.
С 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)
,
Я чувствую себя как 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 }}