Forum Discussion
RichardMulcahy
2 months agoCommunity Member
Any JavaScript Experts Out There?
I found this sample code on the web, but it's not working for me. I'm trying to limit the number of characters a user can enter (for example 5), and if they exceed then I show a layer with an error m...
Nathan_Hilliard
2 months agoCommunity Member
I came across a mutation observer script that will successfully monitor the input value in the current version of Storyline. I inserted it into your original script (the one in the SL file, after fixing the quote character errors), and it worked as expected.
The script includes two event handlers; one for user inputs and one for programatic changes to the input value.
Two things became apparent.
- Users input changes don't seem to fire events, but the programatic changes can still be captured.
- Your selection method for the inputs creates 4 input references. Two (0 and 1) are under the .acc-shadow-dom class, and do not generate events. The remining two (2 and 3) do generate mutation events. Your maxChars array, as implemented, therefore needs 4 entries.
The updated script is as follows
//function below borrowed from
//https://stackoverflow.com/questions/32383349/detect-input-value-change-with-mutationobserver#61975440
function observeElement(element, property, callback, delay = 0) {
let elementPrototype = Object.getPrototypeOf(element);
if (elementPrototype.hasOwnProperty(property)) {
let descriptor = Object.getOwnPropertyDescriptor(elementPrototype, property);
Object.defineProperty(element, property, {
get: function() {
return descriptor.get.apply(this, arguments);
},
set: function () {
let oldValue = this[property];
descriptor.set.apply(this, arguments);
let newValue = this[property];
if (typeof callback == "function") {
setTimeout(callback.bind(this, oldValue, newValue), delay);
}
return newValue;
}
});
}
}
//------------------------------------------------------------------------------
//Excerpt from your original script
function inputLengthCheck(textField, index) {
var maxLength = maxChars[index];
console.log("Idx",index, "maxLen", maxLength);
if (textField.value.length > maxLength) {
textField.value = textField.value.slice(0, maxLength);
player.SetVar("ShowLayer", true);
} else {
player.SetVar("ShowLayer", false);
}
}
//------------------------------------------------------------------------------
//The body of your original script
var textFields = document.querySelectorAll("input[type='text']");
//Note: in your current selection method, there are actually 4 imput boxes.
//The two that function with the events are 2 and 3.
//0 and 1 are part of the shadow-dom (class = acc-shadow=dom)
var maxChars = [4,4,4,4];
var player = GetPlayer();
textFields.forEach(function(textField, index) {
//Note: this event handler does not get called on user input in Storyline
textField.addEventListener("input", function () {
console.log("Input value changed via UI. New value: '%s'", this.value);
//do length check
inputLengthCheck(textField, index);
});
//Note: This event handler does get called in Storyline
observeElement(textField, "value", function (oldValue, newValue) {
console.log("Input value changed via API. Value changed from '%s' to '%s'", oldValue, newValue);
//do length check
inputLengthCheck(textField, index);
});
});