将键盘输入限制为 A-Z,而不是 React 组件上的任何键盘输入
Limiting keyboard inputs to A-Z as opposed to any keyboard input on React component
我刚刚遇到一个组件,我正在努力了解它,但基本上我关心的值是 allowForClassification
,这是一个传递给子组件的布尔值并决定我们是否显示一个按钮。 (基本上意味着只有在用户输入一个字母后才会出现“查找”按钮——目前即使是空格键也会触发该按钮出现)。
但是我很难理解在这个组件中到底在哪里进行了检查,我知道如果 canClassify
& !classifyInProgress
在底部 allowForClassification
设置为 true被退回,但我找不到他们在哪里检查键盘输入,任何建议都会很有帮助。
const getCcceValues = (object?: FormObjectModel | null) => {
const ccceInput: $Shape<CcceInput> = {};
if (!object) {
return {};
}
const ccceValues = object.attributeCollection.questions.reduce(
(acc, attribute) => {
const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);
if (fieldEntry) {
acc[fieldEntry] = attribute.value;
}
return acc;
},
ccceInput
);
// ready to perfom classification based on user input
const canClassify = Object.values(ccceValues).every(Boolean);
return { canClassify, ccceValues };
};
export const useCcceEmbed = (
ccceResultAttribute: AttributeType,
onChange: Function
): CcceHook => {
const { object, form } = useFormObjectContext();
const [resultCode, setResultCode] = useState<string | null>(null);
const { canClassify, ccceValues } = getCcceValues(object);
const { handleSubmit } = useFormSubmit();
const [showModal, setShowModal] = useState<boolean>(false);
const handleCloseModal = useCallback(() => setShowModal(false), []);
const handleShowModal = useCallback(() => setShowModal(true), []);
// state value to keep track of a current active classification
const [classifyInProgress, setClassifyInProgress] = useState<boolean>(false);
const handleResult = useCallback(
(result) => {
if (result?.hsCode) {
onChange(ccceResultAttribute, result.hsCode);
setResultCode(result.hsCode);
setClassifyInProgress(false);
handleSubmit(form);
}
},
[ccceResultAttribute, form, handleSubmit, onChange]
);
const handleCancelClassify = useCallback(() => {
setClassifyInProgress(false);
handleCloseModal();
}, [handleCloseModal]);
const handleClassify = useCallback(
(event?: SyntheticEvent<any>) => {
if (event) {
event.preventDefault();
console.log("scenario 1");
}
if (classifyInProgress || !canClassify) {
console.log("scenario 2");
return;
}
const ccce = window.ccce;
if (!ccceValues || !ccce) {
throw new Error("Unable to classify - no values or not initialised");
console.log("scenario 3");
}
setClassifyInProgress(true);
const classificationParameters = {
...ccceValues,
...DEFAULT_EMBED_PROPS,
};
ccce.classify(
classificationParameters,
handleResult,
handleCancelClassify
);
},
[
classifyInProgress,
canClassify,
ccceValues,
handleResult,
handleCancelClassify,
]
);
return {
allowForClassification: canClassify && !classifyInProgress,
classifyInProgress,
dataProfileId,
embedID: EMBED_ID,
handleCancelClassify,
handleClassify,
handleCloseModal,
handleShowModal,
isDebugMode,
resultCode,
shouldShowModal: showModal,
};
};
解决方案
此代码中缺少很多内容,可能有更好的方法来执行此操作。但这是我想出的。
我们可以评估输入值是否包含字符,而不是评估输入值是否为空。
替换此行:
const canClassify = Object.values(ccceValues).every(Boolean);
用这两行:
const regex = new RegExp('\w', 'g');
const canClassify = Object.values(ccceValues).every(value => regex.test(value));
或者这一行:
const canClassify = Object.values(ccceValues).every(value => /\w/g.test(value))
为什么是那条线?
我通过逆向工作得出了那个解决方案。这是我通过代码到达正确位置所采取的所有步骤。
allowForClassification: canClassify && !classifyInProgress,
如果 canClassify
是 true
且 classifyInProgress
是 false
,则 allowForClassification
是 true
。如果我们已经在执行分类,我们不想分类。这就说得通了。所以这是我们关心的 canClassify
值。
const { canClassify, ccceValues } = getCcceValues(object);
canClassify
来自getCcceValues
函数,其值可能取决于object
.
的值
const { object, form } = useFormObjectContext();
object
来自一些外部挂钩,这对我来说是死胡同,因为我看不到该代码。但请注意,这里 可能 有一些替代解决方案。
const canClassify = Object.values(ccceValues).every(Boolean);
.every(Boolean)
与写成长格式 .every(value => Boolean(value))
的含义相同。如果 ccceValues
的每个值在转换为 Boolean
时都是 true
,则 canClassify
是 true
。这意味着该值不是以下任何值:false
、0
、-0
、0n
、""
、null
、undefined
, NaN
. (source)
const ccceInput: $Shape<CcceInput> = {};
const ccceValues = object.attributeCollection.questions.reduce(
(acc, attribute) => {
const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);
if (fieldEntry) {
acc[fieldEntry] = attribute.value;
}
return acc;
},
ccceInput
);
ccceValues
有点复杂。它由 array .reduce() 操作创建。它以 ccceInput
的初始值开始,这是一个空对象 {}
。在迭代的每一步,它可能会在该对象上设置一个 属性。最后的值就是设置了一堆属性后的对象。
回调中的参数是 acc
——我们正在构建的对象,以及 attribute
——questions
数组的当前元素。我们设置的键是 fieldEntry
,值是 attribute.value
.
请记住,canClassify
检查所有 值 是否“真实”。所以关键不重要。我们只关心值(attribute.value
).
为什么是那个代码?
但是反过来,我们了解到当 canClassify
/allowForClassifiation
是 true
时,在您希望它是 false
的情况下,这是因为当您希望它是 false
时,有些值 Boolean(attribute.value)
是 true
。这是为什么?
我将做出一个合乎逻辑的假设,即 attribute.value
变量包含用户在框中键入的字符串。
记住我之前所说的 Boolean
选角。空字符串 ''
为 false
,所有其他字符串为 true
。因此,如果 object.attributeCollection.questions
中至少有一个用户未输入任何内容的框,则 allowForClassification
将是 false
,因为 attribute.value
将是 ''
。
只要用户点击最后一个框中的空格键,attribute.value
就会变成 ' '
。 此字符串的 Boolean
值为 true
,因此 allowForClassification
现在为 true
。
但是您想应用不同的规则集。当且仅当它包含至少一个字母时,您才会将值视为 true
。我们可以使用简单的 regular expression 来检查。我不确定您的确切规则集(数字可以吗?下划线呢?accented/non-Latin 字符呢?),因此您可能需要调整正则表达式。但这应该让你完成了 99%。
const regex = new RegExp('\w', 'g');
// can also be written as: const regex = /\w/g;
我正在使用 \w
字母数字 character class and the g
global match flag 来匹配字符串中任意位置的任何字母数字字符。
要检查字符串是否匹配此正则表达式,请使用 .test()
方法。
const hasCharacter = regex.test(someString);
我们想在 canClassify
的 .every()
回调中使用此函数,而不是 Boolean
构造函数。所以我们写:
const canClassify = Object.values(ccceValues).every(value => regex.test(value));
我刚刚遇到一个组件,我正在努力了解它,但基本上我关心的值是 allowForClassification
,这是一个传递给子组件的布尔值并决定我们是否显示一个按钮。 (基本上意味着只有在用户输入一个字母后才会出现“查找”按钮——目前即使是空格键也会触发该按钮出现)。
但是我很难理解在这个组件中到底在哪里进行了检查,我知道如果 canClassify
& !classifyInProgress
在底部 allowForClassification
设置为 true被退回,但我找不到他们在哪里检查键盘输入,任何建议都会很有帮助。
const getCcceValues = (object?: FormObjectModel | null) => {
const ccceInput: $Shape<CcceInput> = {};
if (!object) {
return {};
}
const ccceValues = object.attributeCollection.questions.reduce(
(acc, attribute) => {
const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);
if (fieldEntry) {
acc[fieldEntry] = attribute.value;
}
return acc;
},
ccceInput
);
// ready to perfom classification based on user input
const canClassify = Object.values(ccceValues).every(Boolean);
return { canClassify, ccceValues };
};
export const useCcceEmbed = (
ccceResultAttribute: AttributeType,
onChange: Function
): CcceHook => {
const { object, form } = useFormObjectContext();
const [resultCode, setResultCode] = useState<string | null>(null);
const { canClassify, ccceValues } = getCcceValues(object);
const { handleSubmit } = useFormSubmit();
const [showModal, setShowModal] = useState<boolean>(false);
const handleCloseModal = useCallback(() => setShowModal(false), []);
const handleShowModal = useCallback(() => setShowModal(true), []);
// state value to keep track of a current active classification
const [classifyInProgress, setClassifyInProgress] = useState<boolean>(false);
const handleResult = useCallback(
(result) => {
if (result?.hsCode) {
onChange(ccceResultAttribute, result.hsCode);
setResultCode(result.hsCode);
setClassifyInProgress(false);
handleSubmit(form);
}
},
[ccceResultAttribute, form, handleSubmit, onChange]
);
const handleCancelClassify = useCallback(() => {
setClassifyInProgress(false);
handleCloseModal();
}, [handleCloseModal]);
const handleClassify = useCallback(
(event?: SyntheticEvent<any>) => {
if (event) {
event.preventDefault();
console.log("scenario 1");
}
if (classifyInProgress || !canClassify) {
console.log("scenario 2");
return;
}
const ccce = window.ccce;
if (!ccceValues || !ccce) {
throw new Error("Unable to classify - no values or not initialised");
console.log("scenario 3");
}
setClassifyInProgress(true);
const classificationParameters = {
...ccceValues,
...DEFAULT_EMBED_PROPS,
};
ccce.classify(
classificationParameters,
handleResult,
handleCancelClassify
);
},
[
classifyInProgress,
canClassify,
ccceValues,
handleResult,
handleCancelClassify,
]
);
return {
allowForClassification: canClassify && !classifyInProgress,
classifyInProgress,
dataProfileId,
embedID: EMBED_ID,
handleCancelClassify,
handleClassify,
handleCloseModal,
handleShowModal,
isDebugMode,
resultCode,
shouldShowModal: showModal,
};
};
解决方案
此代码中缺少很多内容,可能有更好的方法来执行此操作。但这是我想出的。
我们可以评估输入值是否包含字符,而不是评估输入值是否为空。
替换此行:
const canClassify = Object.values(ccceValues).every(Boolean);
用这两行:
const regex = new RegExp('\w', 'g');
const canClassify = Object.values(ccceValues).every(value => regex.test(value));
或者这一行:
const canClassify = Object.values(ccceValues).every(value => /\w/g.test(value))
为什么是那条线?
我通过逆向工作得出了那个解决方案。这是我通过代码到达正确位置所采取的所有步骤。
allowForClassification: canClassify && !classifyInProgress,
如果 canClassify
是 true
且 classifyInProgress
是 false
,则 allowForClassification
是 true
。如果我们已经在执行分类,我们不想分类。这就说得通了。所以这是我们关心的 canClassify
值。
const { canClassify, ccceValues } = getCcceValues(object);
canClassify
来自getCcceValues
函数,其值可能取决于object
.
const { object, form } = useFormObjectContext();
object
来自一些外部挂钩,这对我来说是死胡同,因为我看不到该代码。但请注意,这里 可能 有一些替代解决方案。
const canClassify = Object.values(ccceValues).every(Boolean);
.every(Boolean)
与写成长格式 .every(value => Boolean(value))
的含义相同。如果 ccceValues
的每个值在转换为 Boolean
时都是 true
,则 canClassify
是 true
。这意味着该值不是以下任何值:false
、0
、-0
、0n
、""
、null
、undefined
, NaN
. (source)
const ccceInput: $Shape<CcceInput> = {};
const ccceValues = object.attributeCollection.questions.reduce(
(acc, attribute) => {
const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);
if (fieldEntry) {
acc[fieldEntry] = attribute.value;
}
return acc;
},
ccceInput
);
ccceValues
有点复杂。它由 array .reduce() 操作创建。它以 ccceInput
的初始值开始,这是一个空对象 {}
。在迭代的每一步,它可能会在该对象上设置一个 属性。最后的值就是设置了一堆属性后的对象。
回调中的参数是 acc
——我们正在构建的对象,以及 attribute
——questions
数组的当前元素。我们设置的键是 fieldEntry
,值是 attribute.value
.
请记住,canClassify
检查所有 值 是否“真实”。所以关键不重要。我们只关心值(attribute.value
).
为什么是那个代码?
但是反过来,我们了解到当 canClassify
/allowForClassifiation
是 true
时,在您希望它是 false
的情况下,这是因为当您希望它是 false
时,有些值 Boolean(attribute.value)
是 true
。这是为什么?
我将做出一个合乎逻辑的假设,即 attribute.value
变量包含用户在框中键入的字符串。
记住我之前所说的 Boolean
选角。空字符串 ''
为 false
,所有其他字符串为 true
。因此,如果 object.attributeCollection.questions
中至少有一个用户未输入任何内容的框,则 allowForClassification
将是 false
,因为 attribute.value
将是 ''
。
只要用户点击最后一个框中的空格键,attribute.value
就会变成 ' '
。 此字符串的 Boolean
值为 true
,因此 allowForClassification
现在为 true
。
但是您想应用不同的规则集。当且仅当它包含至少一个字母时,您才会将值视为 true
。我们可以使用简单的 regular expression 来检查。我不确定您的确切规则集(数字可以吗?下划线呢?accented/non-Latin 字符呢?),因此您可能需要调整正则表达式。但这应该让你完成了 99%。
const regex = new RegExp('\w', 'g');
// can also be written as: const regex = /\w/g;
我正在使用 \w
字母数字 character class and the g
global match flag 来匹配字符串中任意位置的任何字母数字字符。
要检查字符串是否匹配此正则表达式,请使用 .test()
方法。
const hasCharacter = regex.test(someString);
我们想在 canClassify
的 .every()
回调中使用此函数,而不是 Boolean
构造函数。所以我们写:
const canClassify = Object.values(ccceValues).every(value => regex.test(value));