'AJV: can't get any context with { passContext: true } since "this" is undefined in user-defined keyword function
I can't get any context data in my custom keyword although I set passContext and bind this with validate.call({ context }, values).
made a reproduction repo, in which "this" is ajv instance but still no context available.
so I'd appreciate it if anyone could let me know if I'm missing something basic. Thanks.
What version of Ajv are you using? Does the issue happen if you use the latest version?
"ajv": "^8.9.0",
"ajv-i18n": "^4.2.0",
"ajv-keywords": "^5.1.0",
Ajv options object
passContext
JSON Schema
const schema: JSONSchemaType<ViewModel> = {
definitions: {
Service: {
type: 'object',
properties: {
timeWindow: {
type: 'array',
within24Hours: true,
items: {
type: 'object',
properties: {
start: {
type: 'string',
pattern: '[0-9]{2}:[0-9]{2}',
},
end: {
type: 'string',
pattern: '[0-9]{2}:[0-9]{2}',
},
},
required: ['start', 'end'],
additionalProperties: false,
},
},
required: ['timeWindow'],
additionalProperties: false,
},
},
type: 'object',
properties: {
pickup: {
$ref: '#/definitions/Service',
},
delivery: {
$ref: '#/definitions/Service',
},
},
anyRequired: ['pickup', 'delivery'],
additionalProperties: false,
};
Sample data
{
delivery: {
timeWindow: [{ start: '17:00', end: '20:00' }],
}
};
Your code
import Ajv from 'ajv';
import AjvKeywords from 'ajv-keywords';
import AjvLocaleJa from 'ajv-i18n/localize/ja';
export const ajv = new Ajv({ allErrors: true, $data: true, passContext: true });
AjvKeywords(ajv);
ajv.addKeyword({
keyword: 'within24Hours',
type: 'array',
schema: false,
validate: (_, data) => {
console.log(this); => logs undefined
return someValidationFnUsingThis(this.contextData, data)
},
});
const validate = ajv.compile<ViewModel>(schema);
const isValid = validate.call({ contextData }, jsonFormValues);
AjvLocaleJa(validate.errors);
Validation result, data AFTER validation, error messages
I made a small reproduction repo, where "this" in ajv keyword is ajv instance but still no context available.
in keyword validate function, console.log(this, { schema, data }) logs the following output.
ajv: Ajv {
schemas: { 'http://json-schema.org/draft-07/schema': [SchemaEnv] },
refs: {
'http://json-schema.org/draft-07/schema': [SchemaEnv],
'http://json-schema.org/schema': 'http://json-schema.org/draft-07/schema',
'': [SchemaEnv]
},
formats: {},
_compilations: Set(0) {},
_loading: {},
_cache: Map(18) {
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv],
[Object] => [SchemaEnv]
},
opts: {
passContext: true,
strictSchema: true,
strictNumbers: true,
strictTypes: 'log',
strictTuples: 'log',
strictRequired: false,
code: [Object],
loopRequired: 200,
loopEnum: 200,
meta: true,
messages: true,
inlineRefs: true,
schemaId: '$id',
addUsedSchema: true,
validateSchema: true,
validateFormats: true,
unicodeRegExp: true,
int32range: true,
defaultMeta: 'http://json-schema.org/draft-07/schema'
},
scope: ValueScope {
_names: [Object],
_prefixes: [Set],
_parent: undefined,
_values: [Object],
_scope: [Object],
opts: [Object]
},
logger: Object [console] {
log: [Function: log],
warn: [Function: warn],
dir: [Function: dir],
time: [Function: time],
timeEnd: [Function: timeEnd],
timeLog: [Function: timeLog],
trace: [Function: trace],
assert: [Function: assert],
clear: [Function: clear],
count: [Function: count],
countReset: [Function: countReset],
group: [Function: group],
groupEnd: [Function: groupEnd],
table: [Function: table],
debug: [Function: debug],
info: [Function: info],
dirxml: [Function: dirxml],
error: [Function: error],
groupCollapsed: [Function: groupCollapsed],
Console: [Function: Console],
profile: [Function: profile],
profileEnd: [Function: profileEnd],
timeStamp: [Function: timeStamp],
context: [Function: context]
},
RULES: {
types: [Object],
rules: [Array],
post: [Object],
all: [Object],
keywords: [Object]
},
_metaOpts: {
passContext: true,
strictSchema: true,
strictNumbers: true,
strictTypes: 'log',
strictTuples: 'log',
strictRequired: false,
code: [Object],
loopRequired: 200,
loopEnum: 200,
meta: true,
messages: true,
inlineRefs: true,
schemaId: '$id',
addUsedSchema: true,
validateSchema: true,
validateFormats: false,
unicodeRegExp: true,
int32range: true
},
errors: null
}
} { schema: true, data: [ { start: '00:00', end: '00:00' } ] }
What results did you expect?
can get context data via this in validate function.
Are you going to resolve the issue? I don't think I can...
Solution 1:[1]
It was just basic javascript issue about binding this using arrow function.
so what's working and what's not is
- validate: () => {
+ validate {
console.log(this)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Otani Shuzo |
