How to add virtual property of type Array using Keystone.js?
Asked Answered
H

1

8

This is my code for my model: 'Info' and its the tokens property that creates the problem.

var keystone = require('keystone'),
    Types = keystone.Field.Types;
var Info = new keystone.List('Info');
Info.add({
    title: { type: String, required: true, initial: true },
    subtitle: { type: String, initial: true },
    content: { type: Types.Markdown, height: 500, initial: true },
    author: { type: Types.Relationship, ref: 'User', initial: true },
    date: { type: Types.Date, default: Date.now, initial: true },
    published: { type: Boolean, default: false, initial: true },
    tokens: { type: Array, virtual: true, noedit: true, collapse: true }
});

Info.defaultColumns = 'title, author, date|15%, published|15%'
Info.register();

When running the app i get:

Error: Unrecognised field constructor: function Array() { [native code] }
at List.field (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/lib/list.js:315:10)
at List.<anonymous> (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/lib/list.js:200:16)
at List.<anonymous> (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/lib/list.js:191:5)
at List.<anonymous> (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/lib/list.js:230:5)
at Function._.each._.forEach (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/node_modules/underscore/underscore.js:82:22)
at List.add (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/node_modules/keystone/lib/list.js:204:4)
at Object.<anonymous> (/Users/bobmoff/Dropbox (Mobiento)/IMGNRY/Nordea/dev/code/rantebevis-cms/models/infos.js:4:6)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
Hub answered 27/2, 2014 at 9:13 Comment(0)
U
9

I'm not sure what you are planning to store / do with tokens, so if this doesn't answer your question please clarify :)

I'm guessing you either mean:

Both are possible by modifying the mongoose schema directly, rather than using Keystone's add method on the List.

To add an array path (so you could, for example, store an array of string tokens generated through some process on save) you would do this:

var keystone = require('keystone'),
    Types = keystone.Field.Types;

var Info = new keystone.List('Info');
Info.add({
    title: { type: String, required: true, initial: true },
    subtitle: { type: String, initial: true },
    content: { type: Types.Markdown, height: 500, initial: true },
    author: { type: Types.Relationship, ref: 'User', initial: true },
    date: { type: Types.Date, default: Date.now, initial: true },
    published: { type: Boolean, default: false, initial: true }
});

Info.schema.add({
    tokens: { type: [String] }
});

Info.defaultColumns = 'title, author, date|15%, published|15%';
Info.register();

To create a virtual property, you'd specify it with a getter like this:

Info.schema.virtual('tokens', function() {
    var tokens = [];
    // calculate tokens somehow
    return tokens;
});

By accessing the schema you bypass Keystone's list, which means the fields won't show up in the Admin UI. There's an issue to add support for custom templates in the Admin UI though which will allow this in the future.

There's also an issue for an array field type, so if you are storing strings in an array for now you'll be able to include it in the Admin UI when that feature is implemented.

On a related note, all the functionality mongoose offers is available via the schema so you can define things like custom methods, statics and pre / post save hooks too. For more about what you can do with mongoose schemas, check out the guide.

Unipod answered 27/2, 2014 at 14:8 Comment(1)
I tried adding the tokens propety directly to the schema, and that works. But when I create a new Info item, it gets stored with an empty array in the tokens property. I just want this property to exist during the response in my API. It seems like on-the-fly-added properties gets removed when send in the response (using res.send(items);) I dont want to do the calculation inside the getter, coz that gives me to little controll when it happens.Hub

© 2022 - 2024 — McMap. All rights reserved.