Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Add onBlur behavior to SC2 macro

I have some user input data (name, email, phone nr.), that I´d like to validate using an input field's onBlur behaviour.
In HTML, what I am looking for, would look something like this:
<fieldset>
  <label for="email">Email</label>
  <input type="text" name="email" id="email" onblur="validateEmail(value)" />
  <span id="emailError" style="display: none;">You must enter a valid email address</span>
  <label for="Name">Name</label>
  <input type="text" name="name" id="name" onblur="validateName(value)" />
  <span id="nameError" style="display: none;">Please enter your full name.</span>
  <label for="Name">Phone number</label>
  <input type="text" name="phone" id="phone" onblur="validatePhone(value)" />
  <span id="phoneError" style="display: none;">Please provide a valid phone number.</span>
</fieldset> 

Is there a way to put the functions in StoryJavascript and call them from within <<textbox>> macros?

Comments

  • By default javascript executed within the Story Javascript area is done so within a local scope, this is why function define there are not available within the local scope of a displayed Passage.

    You can get around this by defining those functions in a way that gives them global scope and one was to do this is to assign them to your own global namespace.
    if (typeof window.My == "undefined") {
    	window.My = {
    		validateEmail: function(value) {
    			// the code to do something with value.
    		}
    	};
    };
    
    ... you should then be able to call the global function like so:
    <input type="text" name="email" id="email" onblur="My.validateEmail(value)" />
    
  • Hey Greyelf!

    Thanks for your reply. I tried it your way, but I am still getting errors, which I can´t quite figure out how to solve.

    So here is what I put in into the Story Javascript section (I reckon the drama starts here):
    if (typeof window.My == "undefined") {
    	window.My = {
    		validateEmail: function(value) {
    			var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
          if(re.test(email)){
            document.getElementById('email').style.background ='#ccffcc';
            document.getElementById('emailError').style.display = "none";
            return true;
          }else{
            document.getElementById('email').style.background ='#e35152';
            return false;
          }
    		}
    	};
    };
    
    if (typeof window.My == "undefined") {
    	window.My = {
    		validateName: function(value) {
    			// Validation rule
          var re = /[A-Za-z -']$/;
          // Check input
          if(re.test(document.getElementById(x).value)){
            // Style green
            document.getElementById(x).style.background ='#ccffcc';
            // Hide error prompt
            document.getElementById(x + 'Error').style.display = "none";
            return true;
          }else{
            // Style red
            document.getElementById(x).style.background ='#e35152';
            // Show error prompt
            document.getElementById(x + 'Error').style.display = "block";
            return false; 
          }
    	}
    };
    };
    
    (I took the code from here)

    The passage with the form field reads:
    <fieldset>
    <label for="name">Name</label>
          <input type="text" name="name" id="name" onblur="My.validateName(name)" />
          <span id="nameError" style="display: none;">You can only use alphabetic characters, hyphens and apostrophes</span>
    <label for="email">Email</label>
          <input type="text" name="email" id="email" onblur="My.validateEmail(value)" />
          <span id="emailError" style="display: none;">You must enter a valid email address</span>
    </fieldset>
    

    The validateEmail function seems to be called correctly onblur, but the correspondent <span> doesn't show. The validateName function doesn´t work. (error: "undefined is not a function")

    Also, I have a big doubt at this point: Can I assign the field values to variables (which I can later use in Sugarcube) from within the validation-functions (WITHOUT a submit button)?

    Thanks a lot,

    richVIE


  • edited December 2016
    warning: my knowledge of HTML and Javascript is limited, you may want to get the advice of a more experienced HTML / Javascript coder.

    There are a couple of issues with your code/markup.

    1. Your existing Javascript code:

    a. The if condition (typeof window.My == "undefined") of your second block of code will always return false because the My namespace was defined in the first block of code, which is why your validateName function is not getting defined.

    b.. Your functions are defining parameters (value) which are never used within the related function.

    c. Your functions are referencing variables (email and x) which are not defined.

    The following Javascript define a My namespace, as well as the validateEmail and validateName functions (which are slightly modified versions of your own code to take advantage of two new parameters and may still contain errors.)
    if (typeof window.My == "undefined") {
    	window.My = {};
    };
    
    My.validateEmail = function(id, value) {
    	console.log('email: id: ' + id + ' value: ' + value);
    	var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    	if (re.test(value)) {
    		document.getElementById(id).style.background ='#ccffcc';
    		document.getElementById(id+'Error').style.display = "none";
    		return true;
    	} else {
    		document.getElementById(id).style.background ='#e35152';
    		return false;
    	}
    };
    
    My.validateName = function(id, value) {
    	console.log('name: id: ' + id + ' value: ' + value);
    	// Validation rule
    	var re = /[A-Za-z -']$/;
    	// Check input
    	if (re.test(value)){
    		// Style green
    		document.getElementById(id).style.background ='#ccffcc';
    		// Hide error prompt
    		document.getElementById(id + 'Error').style.display = "none";
    		return true;
    	} else {
    		// Style red
    		document.getElementById(id).style.background ='#e35152';
    		// Show error prompt
    		document.getElementById(id + 'Error').style.display = "block";
    		return false; 
    	}
    };
    


    2. The parameters you are passing to the functions within the passage markup.

    Your first input element (ID'ed name) is passing the value of the element's name property but the related function accepts it as a parameter named value, which it never uses internally. The second input element (ID'ed email) is passing the value of the element's value property into a parameter named value which again is never used.

    The following passage content has been change to take advantage of the functions defined in point 1.
    <fieldset>
    	<label for="name">Name</label>
    	<input type="text" name="name" id="name" onblur="My.validateName(id, value)" />
    	<span id="nameError" style="display: none;">You can only use alphabetic characters, hyphens and apostrophes</span>
    	<label for="email">Email</label>
    	<input type="text" name="email" id="email" onblur="My.validateEmail(id, value)" />
    	<span id="emailError" style="display: none;">You must enter a valid email address</span>
    </fieldset>
    
  • Thank you so much, greyelf, both for the coding and the explanations. Can I bother you with one last issue?

    Is there a way to assign the form values to variables I can work with in Sugarcube WITHIN the validation functions (without a submit button)?

    I tried
    var name = value;
    
    after the check input part, and wanted to use $name in another passage. Didn't work.



  • You will want read the State API section of the documentation, in particular about the State.variables object.

    Assuming you have pre-initialised a variable named $name you can assign a value to it within your Javascript code like so:
    State.variables["name"] = "some value";
    
    or
    
    State.variables.name = "some value";
    
Sign In or Register to comment.