Cannot call simpleSchema of undefined error if using validatedMethod

This is how I’m trying to use ValidatedMethods with SimpleSchema. But this gives me the error in methods.js:

TypeError: Cannot call method 'simpleSchema' of undefined

It must be a problem with the simpleSchema, but I don’t find the thing I have to change. Maybe it is a problem with imports…

imports/api/article/collection.js

Articles = new Mongo.Collection('laboratoryValues');

export default Articles.attachSchema(new SimpleSchema({
	_id: 					{ type: String, regEx: SimpleSchema.RegEx.Id },
	title: 					{ type: String },
	slug: 					{ type: String, unique: true }
}));

imports/api/article/methods.js

import Articles from './collection.js';

export const updateArticle = new ValidatedMethod({
	name: 	'article.update',
	mixins: [LoggedInMixin, simpleSchemaMixin],
	schema: Articles.simpleSchema().pick(['_id', 'title']),
	run({ id, title }) {
		Articles.update(
			{ _id: id }, 
			{ 
				$set: {
					title: title
				}
			}
		);
	}
});

imports/ui/article/article.js

import Articles from '../../api/article/collection.js';
import '../../api/article/methods.js';	

let id = 'GyMDumDbziFwxNDPo',
	title = 'changeit';

updateArticle.call(
	{ id: id, title: title },
	(error, response) => {
		if (error) 	console.log(error)
		else console.log('ok');
});

It’s complaining that Articles isn’t defined. It’s Articles that you need to export. I’ve taken your example and changed it to more closely match my normal pattern below. I didn’t actually put these in an editor or app to see if they work so your mileage may vary :slight_smile:

imports/api/article/collection.js

export const Articles = new Mongo.Collection('laboratoryValues');

Articles.attachSchema(new SimpleSchema({
	_id: 					{ type: String, regEx: SimpleSchema.RegEx.Id },
	title: 					{ type: String },
	slug: 					{ type: String, unique: true }
}));

imports/api/article/methods.js

import { Articles } from './collection.js';

export const updateArticle = new ValidatedMethod({
	name: 	'article.update',
	mixins: [LoggedInMixin, simpleSchemaMixin],
	schema: Articles.simpleSchema().pick(['_id', 'title']),
	run({ id, title }) {
		Articles.update(
			{ _id: id }, 
			{ 
				$set: {
					title: title
				}
			}
		);
	}
});

imports/ui/article/article.js

import { Articles } from '../../api/article/collection.js';
import { updateArticle } from '../../api/article/methods.js';	

let id = 'GyMDumDbziFwxNDPo',
	title = 'changeit';

updateArticle.call(
	{ id: id, title: title },
	(error, response) => {
		if (error) 	console.log(error)
		else console.log('ok');
});

I strongly suggest implementing ESLint with your editor of choice. These types of errors will then be highlighted in your editor as you create them saving you lots of pain.

Instructions for installing ESLint and integrating with a few popular editors may be found in the Code Style section of the Meteor Guide.

I’m using sublime with ESLint package, but I don’t get infos for wrong importing…

Hmmm, likely differences in ESLint setup. I just looked at my package.json and .eslintrc.json files in comparison to the current recommendations in the style guide and found that I’m very behind already. So I’m going to need to spend some time updating and experimenting before I can speak better to this. Always something.

Last question on that: How do I pick a nested Schema?

If this is my collection.js

export default Articles = new Mongo.Collection('articles');

const valuesSchema = new SimpleSchema({
	field1:	{ type: String, optional: true },
	field2:	{ type: String, optional: true },
	field3:	{ type: String, optional: true }
});

const mainSchema = new SimpleSchema({
	_id:		{ type: String, regEx: SimpleSchema.RegEx.Id },
	title:		{ type: String },
	values: 	{ type: [valuesSchema], optional: true}
});

LaboratoryValues.attachSchema(mainSchema);

…and this the client call…

const 	id = 'GyMDumDbziFwxNDPo'
		values = {
			field1:	'one',
			field2:	'two',
			field3:	'three',
		};

updateArticle.call(
	{ id: id, values: values }
);

How should I do the method? My problem is to get the nested schema for values and my attempt is not working…

export const updateArticle = new ValidatedMethod({
	name: 	'article.update',
	mixins: [simpleSchemaMixin],
	schema: Articles.simpleSchema().pick(['_id', 'values']),
	run({ id, values }) {
		Articles.update(
			{ _id: id }, 
			{ 
				$push: {
					values: values
				}
			}
		);
	}
});

I’ve never tackled a case quite like that. I looked through my code and found one case where I referenced what would be the equivalent of your “field1”. The syntax to get to that was ‘values.$.field1’. So, ‘values’ refers to an array (not what I think you expected), ‘values.$’ refers to a valuesSchema object, and ‘values.$.field1’ gets into the object. Using that knowledge…

First, Values is an array of valuesSchema in your definition. Your call might thus work if you code it as updateArticle.call({ _id: id, values: [values] }); (note also that I changed your id parameter name to match your pick statement).

Second, if you instead want to get to the actual valuesSchema, I believe you have to dereference the array. It will be called “values.$” instead of “values”. So, picking it isn’t going to work because that would give you a parameter name of values.$ which isn’t a good thing. You want your schema field names to match those in your ‘run’ option. You’ll need to get just the schema and give it a new name. This is a technique I use with _id more than anything else. I note in your example above that you pick _id from the schema but reference “id” in the run parameter. That shouldn’t work. This might work…

  schema: { 
    articleId: Articles.simpleSchema().schema('_id'),
    values: Articles.simpleSchema().schema('values.$'),
  ],
  run({ articleId, values }) {

Some people at this point feel that the work is getting too heavy. I wish there was a lighter way to get this out of SimpleSchema, but feel that it is still worth it to maintain a single point of maintenance of the schema.