Meteor collection2 array with Strings and Object - meteor

i'm using Meteor with collection2 and I have an array that looks like this:
productTypes = ["string1", "string2", "string3", {Other: "test"}]
Essentially there will be anywhere from 0 to 7 strings in the array, and Other: 'Test' may or may not be present
So i'm trying to make a schema that handles that case. Is there a way to tell it that there will be strings and an object within an array?
I've tried
const residentSchema = new SimpleSchema({
productTypes: {type: [String, Object], optional: true, blackbox: true},
})
But that obviously won't work because it's expecting one String and one Object. Does anyone know how I can make this work? Thanks in advance
Edit:
I am now storing it with this format:
productTypes = { list: ["string1", "string2", "string3"], Other: "test"}
but when I add a schema like this:
const productTypeSchema = new SimpleSchema({
list: {type: Array},
other: {type: String}
})
const residentSchema = new SimpleSchema({
productTypes: {type: productTypeSchema},
})
My App crashes. When I remove the line list: {type: Array} it is fine.
Is Array now allowed as a value of SimpleSchema?

With collection2 you can have an array of primitives or an array of objects but not a mixed array. Just from a modeling pov it's really messy.
I suggest you refactor your array, instead of:
productTypes = ["string1", "string2", "string3", {Other: "test"}]
for example:
productTypes = { list: ["string1", "string2", "string3"], Other: "test"}

Related

Elements of array are fixed-length while array itself is not

var data = List();
snapshot.data.documents.forEach((doc) => data.add(doc.data)); //my example data is one doc
data.add({"x": "y"}); //works
data[0]["bar"].add({"foo": "bar"}); //doesn't
My data looks like this:
data = [
{
"foo": "",
"bar": [
{"foo": "bar"},
{"foo": "bar"},
{"foo": "bar"},
],
},
];
When I do the second array modification, it gives me this error:
Unhandled Exception: Unsupported operation: Cannot add to a fixed-length list
I have tried doing this with normal data that is not fetched from firebase, and it works as expected. I also tried using List.from to populate the array but it didn't work either.
snapshot.data.documents[0]['bar'] apparently is a fixed-length (i.e., non-growable) List. You can't make a non-growable List growable. You instead need to create a growable copy:
data[0]["bar"] = data[0]["bar"].toList(); // Create a copy.
data[0]["bar"].add({"foo": "bar"}); // Now this should work.
Alternatively:
data[0]["bar"] = [...data[0]["bar"], {"foo": "bar"}];
However, while the latter approach is more compact, it is less clear that the copy is explicitly desired.
Do like this:
var data = List();
var data2= List();
snapshot.data.documents.forEach((doc) => data.add(doc.data)); //my example data is one doc
data.add({"x": "y"}); //works
data2=data[0]["bar"];
data2.add({"foo": "bar"});
The problem is add method is used over an object type. You need to add a cast before using add method:
(data[0]["bar"] as List<Map<String, String>>).add({"foo": "bar"});

How do I reference another collection as a field in a Meteor Schema

I'm using meteor simple schema, and autoform. I would like to have a reference to one type of object in the schema of the other. The two schemas are defined in separate files, I would also like to populate autoform with a dropdown of the possible references, and I'm unclear how to do this.
I've tried
venue:{
type: Venues,
label: "Venue",
},
and
venue:{
type: SimpleSchema.Venues,
label: "Venue",
},
and neither works
First you have to define your schema like this:
VenueSchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
}
})
Than you can in another schema declare an attribute Venue
CustomerSchema = new SimpleSchema({
venue: {
type: VenueSchema
},
//an array of venues
venues: {
type: [VenueSchema],
minCount: 1
}
});
Take a look on basic usage of simpleSchema docs -> https://github.com/aldeed/meteor-simple-schema#basic-usage
I hope that helps.

How do you clear an immutable.js map back to its defaults

I have an immutable.js map. For example:
// default, when user first gets on page
var myObject = Immutable.Map({
productID: '',
colors: ['brown', 'red'],
sku: ''
sizes: [10]
})
Now, depending on how they get to my app - I populate that above "myObject" with different data.
so, for example: lets say they come from pathA
// pathA passes in some data... hydrate the myObject
var myObject = Immutable.Map({
productID: '090ABl',
colors: ['brown', 'red', 'yellow'],
sku: '__whatever'
sizes: [10, 18, 9]
})
so, for example: lets say they come from pathB
** this is where the issue comes from. I have that previous "state" of myObject hanging around. I need to "clear and go back to the initial state". I am using redux.
// pathB passes in some data... hydrate the myObject
var myObject = Immutable.Map({
productID: '090XZLG',
colors: ['red', 'yellow'],
sku: '__food'
sizes: [9]
})
The data is combing etc.. I need it to "clear out.". Curious if there is an Immutable.js method that enables to refresh the myObject with a new one, that is the same as the initial state. I am new to immutable.js so I am a bit curious about why its so hard to do simple things :-)
When using immutable for the state object in redux, in many of my reducers I set a certain key to what I get from the initial state.
i.e.:
function reeducer(state = initialState, action) {
switch (action.type) {
...
case CLEAR_SELECTION:
return state.set('selected', initialState.get('selected'));
...
}
}
And of course to make it a bit cleaner (specially to avoid repeating a string) one could create a function for this:
function resetKey(state, initialState, key) {
return state.set(key, initialState.get(key));
}
(Alternatively it could be called copyKey or copySection)
Or it could be a resetPath/copyPath
function resetPath(state, initialState, path) {
return state.setIn(key, initialState.getIn(path));
}
The immutable.js object does not 'know' what its 'defaults' are, so there is no way of resetting it. If you have a default object in your application just keep a reference to that in a variable, like you would if it were a plain JavaScript object:
var defaultObject = Immutable.Map({
productID: '',
colors: ['brown', 'red'],
sku: ''
sizes: [10]
})
Then when the user arrives at a certain path, you simply make your modifications and keep them in a different variable:
var myObject = defaultObject.set(...);

autoform won't render select option field

I have an issue regarding collection2 with relationships and autoform.
I try to implement an 1:n relationship, where each object has exactly 1 objectType, while to each objectType multiple objects can be referred to.
My schema looks as follows:
// register collections
Objects = new Mongo.Collection('objects');
ObjectTypes = new Mongo.Collection('objectTypes');
// define schema
var Schemas = {};
Schemas.ObjectType = new SimpleSchema({ // object type schema
name: {
type: String
}
});
Schemas.Object = new SimpleSchema({ // object schema
type: {
type: ObjectTypes.Schema,
optional: true
},
title: {
type: String
}
});
// attach schemas
ObjectTypes.attachSchema(Schemas.ObjectType);
Objects.attachSchema(Schemas.Object);
My autoform looks like this:
{{> quickForm collection="Objects" id="insertTestForm" type="insert"}}
I actually would expect a select option field for my type attribute, however, a text input appears. Anyone knows why?
According to the documentation [1], it should be a select option field:
If you use a field that has a type that is a Mongo.Collection instance, autoform will automatically provide select options based on _id and name fields from the related Mongo.Collection. You may override with your own options to use a field other than name or to show a limited subset of all documents. You can also use allowedValues to limit which _ids should be shown in the options list.
[1] https://github.com/aldeed/meteor-collection2/blob/master/RELATIONSHIPS.md#user-content-autoform
EDIT
If I use
type: ObjectTypes,
instead of
type: ObjectTypes.Schema,
my app crashes, throwing the following error:
Your app is crashing. Here's the latest log.
/Users/XXX/.meteor/packages/meteor-tool/.1.1.3.ik16id++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:245
throw(ex);
^
RangeError: Maximum call stack size exceeded
Exited with code: 8
Your application is crashing. Waiting for file change.
Your type isn't "a Mongo.Collection instance" like the documentation says; it's a Schema. Try this:
Schemas.Object = new SimpleSchema({
type: {
type: ObjectTypes,
optional: true
},
...
Since nobody could help me solve this incident, I came up with an alternate solution:
// register collections
Objects = new Mongo.Collection('objects');
ObjectTypes = new Mongo.Collection('objectTypes');
// define schema
var Schemas = {};
Schemas.Object = new SimpleSchema({ // object schema
type: {
type: String,
optional: true,
autoform: {
return ObjectTypes.find().map(function(c) {
return{label: c.name, value: c._id}
});
}
},
// ...
});
// attach schema
Objects.attachSchema(Schemas.Object);
As u can see, I manually map the attributes I need from the objectTypes collection into the autoform attribute. Since it returns an array of objects, containing the label and value attributes, autoform will automatically render a select option.

creating dojo datagrid programmatically "sorry an error occured"

I am trying to create a Dojo dojox.grid.DataGrid programmatically. It is getting created but does not show the output, instead it shows an error with the message: "Sorry, an error occurred"
Here is the code:
var info=[
{
"Propery":"key1","Value":"value1"},
{
"Property":"key2", "Value":"value2"},
{
"Property":"key3","Value":"value3"}
];
var layout = [
{
name: "Property",
field: 'Property',
width: "180px"},
{
name: "Value",
field: 'Value',
width: "180px"}
];
var myStore = new dojo.data.ItemFileReadStore({data:{items:info}});
var grid = new dojox.grid.DataGrid({
store: myStore,
structure: layout
},"myDiv");
grid.startup();
I don't know where it is going wrong, please help me out.
Dude, this is like the third time I answer a question of yours. It strongly reminds me of the two before, but i'll have a try anyway.
Your example can't work, because in your layout-variable, you refer to a field named 'property' which doesn't exist in data.items (info).
You also did't get the concept of the json-array right. It schould represent like a bunch of object with a very similar structure. Assume you want to store some people, then you would have some keys like firstname, lastname, age, gender etc. Each person would have different values on this. The json-array would look like that:
var people = [
{
firstname: 'maja',
lastname: 'van hinten'
age: 23
gender: 'w'},
{
firstname: 'willy',
lastname: 'wantstoknowit'
age: 11
gender: 'm'},
{
firstname: 'helmut',
lastname: 'kohl'
age: 101
gender: 'm'},
];
Note, that the names of the properties are similar, just the values differ.
What you try to do obviously is, to store one single object as an array, and make each property an object. Think about it: [] means array, {} means object in JavaScript.
In fact, your info-variable should look like this:
var info = [
{
"key1": "value1",
"key2": "value2",
"key3": "value3"}
];
and if you would like to store some more object it would look like this:
var info = [
{
"key1": "value1",
"key2": "value2",
"key3": "value3"},
{
"key1": "value4",
"key2": "value5",
"key3": "value6"},
{
"key1": "value7",
"key2": "value8",
"key3": "value9"}
];
... objects stored in an array. Simple as that.
Now to your layout var:
It should discribe the structure of your DataGrid in relation to the data given by its store. So it descripes the columns as a whole, not the single cells.
You can therefore only refer to the property-names (key1, key2, key3, or firstname, lastname, age, gender) but not to the values, as the may be different sometimes. You only know the structure of your objects, not its actual content.
Therefore, it should look like that:
var layout = [
{
name: "Key1's content", // you can name this whatever you want
field: 'key1', // but not this, it refers to the property name of your objects
width: "180px"},
{
name: "Key2's content", // this could be named randomly too of course
field: "key2",
width: "180px"},
{
name: "Key3's content", // and that one as well
field: "key3",
width: "180px"}
];
Not sure if this will help, but in the example code you posted, you misspell the word 'Property' in one of your item, while the other two items have the word 'Property' spelled correctly. Refer to item with property key1. You have to make sure all your field names are spelled consistently.

Resources