set a timer between requests from html inputs by withSuccessHandler and onSuccess - html

I have the problem in html page.
User enters data in html inputs and clicks enter.
After this it must start checking by the function "keyPressFunction" throw withSuccessHandler(onSuccess) to the Google-apps script function "searchData" in 3 tables on spreadsheet and result must return to var "findData" with true/false. If it true, then focus goes to next input. After third input the data writes to table.
But answer from apps-script returns slowly, near 5 seconds, but the focus is already goes out, when the data is really uncorrect. Can you help me this timer between requests?
For understanding the test project is here https://docs.google.com/spreadsheets/d/1FqUmJcTipwKX9Q5m-4dlmXIChp5k1Z98xR2m42GpIT0/edit#gid=0
and last deployed link of web app is here https://script.google.com/a/fmlogistic.com/macros/s/AKfycbwAcfIVGrbcu24t_6OxtR2gvltG3ojbh1_pNxLed1O8/dev
<script>
const inputs = document.querySelector('.dws-input');
const formControl = document.querySelectorAll('.form-control');
let findData;
let curInpID;
let firstValid, secValid, thirdValid, allValid;
formControl[0].focus();
function keyPressFunction(ev) {
let userInfo = {};
userInfo.login = document.getElementById("tLogin").value;
userInfo.table = document.getElementById("tTable").value;
userInfo.order = document.getElementById("tOrder").value;
let inputData = ev.target.value
let btnReset = document.getElementById("del");
if (ev.code !== 'Enter') return;
if (ev.target.classList.contains("is-valid")) ev.target.classList.remove("is-valid");
if (ev.target.classList.contains("is-invalid")) ev.target.classList.remove("is-invalid");
curInpID = ev.target.id;
google.script.run.withSuccessHandler(onSuccess).searchData(inputData, curInpID);
//the true/false returns here in findData:
console.log(findData);
if (!findData) {
ev.target.classList.add("is-invalid");
ev.target.focus();
return;
} else {
ev.target.classList.add("is-valid");
};
btnReset.disabled = (!firstValid == true);
allValid = (firstValid == true && secValid == true && thirdValid == true) ? true : false;
for (const i of formControl) {
if (i.value === '') {
i.nextElementSibling.focus();
break;
}
}
if (allValid){
google.script.run.userClicked(userInfo);
document.getElementById("tTable").value = '';
document.getElementById("tOrder").value = '';
secValid = false;
thirdValid = false;
document.getElementById("tTable").focus();
}
}
function onSuccess(_findData) {
findData = _findData;
if (!firstValid) firstValid = (findData && curInpID == "tLogin") ? true : false;
if (!secValid) secValid = (findData && firstValid && curInpID == "tTable") ? true : false;
if (!thirdValid) thirdValid = (findData && firstValid && secValid && curInpID == "tOrder") ? true : false;
allValid = (firstValid && secValid && thirdValid) ? true : false;
}
inputs.addEventListener('keydown', keyPressFunction);
</script>
<!doctype html>
<html lang="en">
<head>
<title>CLR: PACKING</title>
<meta charset = "UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div class="conteiner">
<form novalidate>
<h6 class="title">PACKING</h6>
<div class="dws-input">
<div class="col-md-3"></div>
<div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tLogin" name= "username" placeholder= "Login:" autofocus >
<label for="tLogin">Login:</label>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tTable" name= "text" placeholder= "Table:" >
<label for="tTable">Table:</label>
</div>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" novalidate class="form-control" id="tOrder" name= "text" placeholder= "Order:" >
<label for="tOrder">Order:</label>
</div>
</div>
</form>
</div>
<?!= include("index-js"); ?>
</body>
</html>
at Apps script I have next script:
const url = SpreadsheetApp.getActiveSpreadsheet().getUrl();
let ss = SpreadsheetApp.openByUrl(url);
let sheetTo = ss.getSheetByName("#sistem");
let sheetIn = ss.getSheetByName("#packing");
function doGet(e){
var htmlServ = HtmlService.createTemplateFromFile("index");
return htmlServ.evaluate();
}
function userClicked(userInfo){
sheetIn.appendRow([userInfo.login, userInfo.table, userInfo.order, new Date()]);
Logger.login(userInfo.name + "clicked the button");
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function searchData(inputData, curInpID){
var result;
var lrLogins = sheetTo.getRange("A:A").getValues().filter(String).length;
var arrLogins = sheetTo.getRange(1, 1, lrLogins, 1).getValues().flat();
var lrTMPLORDS = sheetTo.getRange("K:K").getValues().filter(String).length;
var curTMPLORDS = sheetTo.getRange(1, 11, lrTMPLORDS, 1).getValues();
var lrTABLES = sheetTo.getRange("R:R").getValues().filter(String).length;
var curTABLES = sheetTo.getRange(1, 18, lrTABLES, 1).getValues().flat();
if (curInpID == "tLogin"){
result = (arrLogins.indexOf(inputData) !== -1) ? true : false;
}
else if (curInpID == "tTable"){
result = (curTABLES.indexOf(inputData) !== -1) ? true : false;
}
else if (curInpID == "tOrder"){
for (i = 0 ; i < curTMPLORDS.length; i ++){
var regexstring = curTMPLORDS[i];
var regexp = new RegExp(regexstring, "i");
var result = regexp.test(inputData);
if (result) break;
}
}
return result;
}

Issue:
If I understand you correctly, you want to avoid the keydown events to execute keyPressFunction while the server-side function searchData hasn't still returned the data.
Solution:
If that's the case, I'd suggest you to use removeEventListener at the start of the keyPressFunction (in order to avoid successive keydown event to trigger more executions of this function), and add it again via addEventListener when executing you success handler function (onSuccess).
It could be something along the following lines:
function keyPressFunction(ev) {
inputs.removeEventListener('keydown', keyPressFunction);
// ... REST OF YOUR FUNCTION
}
function onSuccess(_findData) {
// ... REST OF YOUR FUNCTION
inputs.addEventListener('keydown', keyPressFunction);
}
Update:
keyPressFunction finishes execution without calling the server-function searchData if the pressed key is not Enter. Since the event will only be reactivated after searchData returns and onSuccess runs, it will not be reactivated if the pressed key is not Enter. Because of this, keyPressFunction will only run once (if the pressed key is not Enter).
In order to avoid this, move the removeEventListener line to just before calling searchData:
function keyPressFunction(ev) {
// ... REST OF YOUR FUNCTION
inputs.removeEventListener('keydown', keyPressFunction);
google.script.run.withSuccessHandler(onSuccess).searchData(inputData, curInpID);
}
Sidenote: Please note that everything that is written in keyPressFunction after calling searchData will never be executed, since the execution will be moved to the failure or success handlers (onSuccess in your case). So move that on top of the mentioned line (starting with google.script.run) if you want it to run.
Reference:
removeEventListener

Related

Show div depending to value of function in apps script

I develop and web app in apps script where i can select a name. Each name is in my Sheets and is depending to a profil. I can have 2 possibilities : The name have a profil or doesn't have. In the screenshot below, Sir A have a profil and Sir B and C doesn't have.
I would like to show a div in my html's page if the selected name doesn't have profil (and already hide if the selected name have a profil). So i create a function to detect if the select name have a value written in my Sheets. If it's correct, i write yes in one div (and no if it's not correct). But when i want to show div, it's doesn't work.
To try to understand my problem, i created a button to launch a function where i get the value of my result. I have undefined each time and i don't know why.
This is my html's code :
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('JavaScript'); ?>
<?!= include('StyleSheet'); ?>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<form>
<!-- NAME -->
<div class="form-row">
<div class="form-group col-md-12">
<label for="name"><b>Name :</b></label>
<select class="form-control" id="name" onChange = "showProfil();">
<option disabled selected>Choose ...</option>
<?!=getNames()?>
</select>
</div>
</div>
<!-- RESULT -->
<div><label> Result : </label><p id = "result"></p></div>
<!-- BUTTON -->
<input type="button" class="btn btn-primary btn-block" value="SHOW DIV ?" id = "btnAccesQuestions" onclick = "showDivResultNo();">
<!-- DIV DISPLAY WHEN RESULT IS NO -->
<div id = "divResultNo">
<h2> Result is "NO"</h2>
</div>
</form>
</body>
</html>
This is my server side code :
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate().setTitle('Formulaire de demande de formation');
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getNames(){
const classeur = SpreadsheetApp.getActiveSpreadsheet();
const feuille = classeur.getSheetByName("Sheet1");
var tNames = feuille.getRange("A2:A").getValues().filter(d =>d[0] !== "").flat();
var names = deleteDuplicateValues(tNames);
return names.map(d => "<option>" + d + "</option>").join("");
}
function deleteDuplicateValues(array) {
var outArray = [];
array.sort(lowerCase);
function lowerCase(a,b){
return a.toLowerCase()>b.toLowerCase() ? 1 : -1;
}
outArray.push(array[0]);
for(var n in array){
if(outArray[outArray.length-1].toLowerCase()!=array[n].toLowerCase()){
outArray.push(array[n]);
}
}
return outArray;
}
function getProfil(name){
const classeur = SpreadsheetApp.getActiveSpreadsheet();
const feuille = classeur.getSheetByName("Sheet1");
var tProfils = feuille.getRange("A2:B").getValues().filter(d =>d[0] !== "");
for (let i = 0; i < tProfils.length; i ++){
if(tProfils[i][0] == name){
if(tProfils[i][1] == ""){
var resultat = "no";
}
else {
var resultat = "yes";
}
}
}
return resultat;
}
function testProfil(){
Logger.log(getProfil("Sir A"));
}
This is my js code :
<script>
function showProfil(){
var name = document.getElementById("name").value;
google.script.run.withSuccessHandler(profil => {
document.getElementById("result").innerHTML = profil;
}).getProfil(name);
}
function showDivResultNo(){
var name = document.getElementById("name").value;
var result = document.getElementById("result").value;
console.log(result)
if (name != "Choose ..." && name != "" && result == "no"){
console.log("show div after that");
}
else {
console.log("div always hidden");
}
}
</script>
And this is a screenshot of my web app after selected Sir A and press button :
If anyone can help me, it would be appreciated. You can acces to my Sheet in this link. Thank you for advance.
In your script, how about the following modification?
From:
var result = document.getElementById("result").value;
To:
var result = document.getElementById("result").innerHTML;
I thought that from your HTML, I thought that the reason of your issue of I have undefined each time and i don't know why. might be due to .value.

Apps script return values from server function to html form

I need help of professionals at Apps script. I have the project implemented by web-app.
I wrote script on server-part
var url = "https://docs.google.com/spreadsheets/d/1s8l-8N8dI-GGJi_mmYs2f_88VBcnzWfv3YHgk1HvIh0/edit?usp=sharing";
var sprSRCH = SpreadsheetApp.openByUrl(url);
let sheetSRCHSSCC = sprSRCH.getSheetByName("PUTAWAY_TO");
function GetQ(){
var QPLAN = sheetSRCHSSCC.getRange("M2:M").getValues().filter(String).length;
var myArray = sheetSRCHSSCC.getRange("O2:O" + (QPLAN + 1)).getValues();
var QFACT = 0;
for (i = 0; i < myArray.length; i++) {
if (myArray[i] != "") {
QFACT += 1
}
}
}
I need to return values from this function to inputs:
QFACT to FACT
QPLAN to PLAN
<div class="input-field col s3">
<input disabled value="" id="PLAN" type="text" >
<label for="disabled">PLAN</label>
</div>
<div class="input-field col s3">
<input disabled value="" id="FACT" type="text" >
<label for="disabled">FACT</label>
</div>
I will be grateful for the help. I'm new at this))
If you are using Apps Script deploying Web App, I can see 2 possibilities :
1/ Get data at the loading of the page (and only at the loading) :
In code.gs :
function doGet() {
var tmp = HtmlService.createTemplateFromFile('page');
tmp.QFACT = "hello";
tmp.PLAN = "World!";
return tmp.evaluate();
}
In page.html :
<html>
<body>
<h5><?= QFACT ?></h5>
<h5><?= QPLAN ?></h5>
</body>
</html>
2/ If you need to refresh the data by click button, or something else, you will need to operate diffently :
Add a page-js.html to your project, and bind it at the end of your page.html
<html>
<body>
<h5 id="QFACT"></h5>
<h5 id="QPLAN"></h5>
</body>
<?!= include("page-js"); ?>
</html>
then in your page-js.html :
<script>
function refresh() {
google.script.run.withSuccessHandler(callback).refresh();
}
function callback(e) {
document.getElementById('QPLAN').innerHTML = e.QPLAN;
document.getElementById('QFACT').innerHTML = e.QFACT;
}
</script>
and finally add the refresh() function in your code.gs :
function refresh() {
var obj = {};
obj.QPLAN = "QPLAN";
obj.QFACT = "QFACT";
return obj;
}

I need with parsing an array from google script to HTML

I have a date picker that I'd like to use to choose an event and then show details from a spread sheet.
HTML:
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
$( "#datepicker" ).datepicker({
onSelect: function(date) {
var stuff= updDate(date);
},
selectWeek: true,
inline: true,
startDate: '01/01/2000',
firstDay: 1,
});
});
</script>
<script>
function updDate(date){
google.script.run.updDate(date);
}
</script>
</head>
<body>
<p>Date: <input type="text" id="datepicker" onchange="updDate()"></p>
Hello, world!
<input type="button" value="Close"
onclick="google.script.host.close()" />
</body>
</html>
Google Script:
function updDate(date){
var searchString = date;
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var s2 = SpreadsheetApp.openById("*************");
var row = new Array();
var k;
for (var i in data) {
//Logger.log("length is: "+data[i].length)
//var p = data[i].length
for (var j in data[i]) {
//Logger.log("We are at i: "+i) //Row
//Logger.log("We are at j: "+j) //Col
if (i !=0){
if(data[i][j] != ""){
if(j == 4){
//Logger.log("date from picker: " + date);
//Logger.log("date from Data: " + data[i][j]);
var ssDate = Utilities.formatDate(data[i][j], "GMT", "MM/dd/yyyy");
//Logger.log("date post Convert: " +ssDate);
if(date == ssDate){
k= i
var p = data[i].length
Logger.log("P is: " +p);
}
}
}
}
}
}
Logger.log("K is: "+k)
var q = 1
while (q <= p){
row[q] = data[k][q];
q++
}
Logger.log("Row: " +row);
return row;
}
Eventually I'd like to get the data read into a table but I've been hitting a wall when it comes to successfully getting the data read into a variable in the HTML.
Right now I get this error:
Uncaught ScriptError: The script completed but the returned value is not a supported return type.
Any help in returning the array "row"(in the google script) to the variable "stuff"(in the HTML) successfully or any pointers about how to better execute this task would be greatly appreciated.
Loren
Edit code:
function updDate(date){
var stuff = google.script.run.withSuccessHandler(myReturnFunction).updDate(date);
Console.log(stuff)
}
function myReturnFunction(){
window.myReturnFunction = function(whatGotReturned) {console.log(whatGotReturned);};
}
Sandy Good had it right in the comments above:
function updDate(date){
var junk = google.script.run.withSuccessHandler(myReturnFunction).updDate(date);
}
function myReturnFunction(whatGotReturned){
console.log(whatGotReturned);
}

Allow only numbers into a input text box

I have a number input text box and I want to allow the user to edit but do not want to allow the user to enter any other text except numbers. I want them only to be able to use the arrows on the number input box.
<input type = "number" min="0" max="10" step="0.5" input id="rating" name = "rating" class = "login-input" placeholder = "Rating 1-5:" value="0">
You can achieve this by pure JavaScript. Create this function that you can reuse in your script.
function allowNumbersOnly(e) {
var code = (e.which) ? e.which : e.keyCode;
if (code > 31 && (code < 48 || code > 57)) {
e.preventDefault();
}
}
You may preferably call this onkeypress event handler.
<input type="text" id="onlyNumbers" onkeypress="allowNumbersOnly(event)" />
function allowNumbersOnly(e) {
var code = (e.which) ? e.which : e.keyCode;
if (code > 31 && (code < 48 || code > 57)) {
e.preventDefault();
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
Try editing in me:
<input type="text" id="onlyNumbers" onkeypress="allowNumbersOnly(event)" />
</body>
</html>
However, I would recommend the unobtrusive style of writing JS using because it is good to keep the HTML semantic and away from pollution. You can execute the function on event handler that we would attach to this text box using vanilla JavaScript or jQuery.
function allowNumbersOnly(e) {
var code = (e.which) ? e.which : e.keyCode;
if (code > 31 && (code < 48 || code > 57)) {
e.preventDefault();
}
}
// using classic addEventListener method:
document.getElementById('onlyNumbers').addEventListener('keypress', function(e){ allowNumbersOnly(e);
}, false);
//using jQuery
$(function(){
$('#onlyNumbers2').keypress(function(e) {
allowNumbersOnly(e);
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>
<body>
<div>
Using addEventListener: <input type="text" id="onlyNumbers" />
</div>
<div>
Using jQuery: <input type="text" id="onlyNumbers2" />
</div>
</body>
</html>
To restrict every character you can just simply use e.preventDefault().
Besides, you can also use return false instead but preventDefault() is better in this case and return false should be chosen wisely. It is good to know the difference between both of them.
document.getElementById('rating').onkeypress = function() { return false; }
This will prevent the default behavior of keypresses on that element i.e. text showing up.
HTML
<input type="text" class="IntOnly">
Javascript
let ele = document.getElementsByClassName('IntOnly');
for (const e of ele) {
//e.addEventListener('change', filterNonIntOut.bind(null, e));
//e.addEventListener('paste', filterNonIntOut.bind(null, e));
e.addEventListener('input', filterNonIntOut.bind(null, e));
}
function filterNonIntOut(theTextbox) {
//console.log(ele);
let startPos = theTextbox.selectionStart;
let endPos = theTextbox.selectionEnd;
let str = theTextbox.value;
str = str.trim();
if (str == '') {
theTextbox.value = '';
return;
}
let result = "";
for (var i = 0; i < str.length; i++) {
let ch = str.charAt(i);
//console.log(ch);
if (ch === '1'
|| ch === '2'
|| ch === '3'
|| ch === '4'
|| ch === '5'
|| ch === '6'
|| ch === '7'
|| ch === '8'
|| ch === '9'
|| ch === '0'
) {
result += ch;
}
else {
startPos -= 1;
endPos -= 1;
}
}
theTextbox.value = result;
theTextbox.focus();
theTextbox.setSelectionRange(startPos, endPos);
}

Codeception acceptance test error for save/reset

I am trying to perform acceptance tests for my website using Codeception, and I am experiencing a strange error due to a reset button on the form I am testing. Basically, my test for clicking on 'Save' works only if either the reset button on my form is AFTER the Save button, or if the reset button is left off the form altogether. If the reset button is inserted in the form before the save button, Codeception throws an Unreachable field "reset" error. Here is my Codeception code:
<?php
$I = new WebGuy($scenario);
$I->wantTo('find an employee in the database');
$I->amOnPage('/employees/find/');
$I->fillField('employeeLookup[first_name]', 'Sergi');
$I->click('Save', '#employeeLookup_save');
$I->see('Based on your search for Sergi, the following employees were found:');
$I->see('Remmele');
$I->see('Feb 28 1992');
And here is my HTML (much of it being generated from Symfony2):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Find existing employee</title>
</head>
<body>
<div id="content">
<p>Hello, enter either the first name, or the last name of the employee
you are searching for.</p>
<form name="employeeLookup" method="post" action="">
<div><label for="employeeLookup_first_name" class="required">Name: </label><input type="text" id="employeeLookup_first_name" name="employeeLookup[first_name]" required="required" /></div>
<div><button type="reset" id="employeeLookup_reset" name="employeeLookup[reset]">Reset</button></div>
<div><button type="submit" id="employeeLookup_save" name="employeeLookup[save]">Save</button></div>
<input type="hidden" id="employeeLookup__token" name="employeeLookup[_token]" value="RcpMVTGgB6WhKgDoXXRwmV_l4AFYKWTZko-dnBDhhvM" /></form>
</div>
<div id="sfwdte5d291" class="sf-toolbar" style="display: none"></div><script>/*<![CDATA[*/ Sfjs = (function() { "use strict"; var noop = function() {}, profilerStorageKey = 'sf2/profiler/', request = function(url, onSuccess, onError, payload, options) { var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); options = options || {}; xhr.open(options.method || 'GET', url, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onreadystatechange = function(state) { if (4 === xhr.readyState && 200 === xhr.status) { (onSuccess || noop)(xhr); } else if (4 === xhr.readyState && xhr.status != 200) { (onError || noop)(xhr); } }; xhr.send(payload || ''); }, hasClass = function(el, klass) { return el.className.match(new RegExp('\\b' + klass + '\\b')); }, removeClass = function(el, klass) { el.className = el.className.replace(new RegExp('\\b' + klass + '\\b'), ' '); }, addClass = function(el, klass) { if (!hasClass(el, klass)) { el.className += " " + klass; } }, getPreference = function(name) { if (!window.localStorage) { return null; } return localStorage.getItem(profilerStorageKey + name); }, setPreference = function(name, value) { if (!window.localStorage) { return null; } localStorage.setItem(profilerStorageKey + name, value); }; return { hasClass: hasClass, removeClass: removeClass, addClass: addClass, getPreference: getPreference, setPreference: setPreference, request: request, load: function(selector, url, onSuccess, onError, options) { var el = document.getElementById(selector); if (el && el.getAttribute('data-sfurl') !== url) { request( url, function(xhr) { el.innerHTML = xhr.responseText; el.setAttribute('data-sfurl', url); removeClass(el, 'loading'); (onSuccess || noop)(xhr, el); }, function(xhr) { (onError || noop)(xhr, el); }, options ); } return this; }, toggle: function(selector, elOn, elOff) { var i, style, tmp = elOn.style.display, el = document.getElementById(selector); elOn.style.display = elOff.style.display; elOff.style.display = tmp; if (el) { el.style.display = 'none' === tmp ? 'none' : 'block'; } return this; } } })();/*]]>*/</script><script>/*<![CDATA[*/ (function () { Sfjs.load( 'sfwdte5d291', '/employees/app_dev.php/_wdt/e5d291', function(xhr, el) { el.style.display = -1 !== xhr.responseText.indexOf('sf-toolbarreset') ? 'block' : 'none'; if (el.style.display == 'none') { return; } if (Sfjs.getPreference('toolbar/displayState') == 'none') { document.getElementById('sfToolbarMainContent-e5d291').style.display = 'none'; document.getElementById('sfToolbarClearer-e5d291').style.display = 'none'; document.getElementById('sfMiniToolbar-e5d291').style.display = 'block'; } else { document.getElementById('sfToolbarMainContent-e5d291').style.display = 'block'; document.getElementById('sfToolbarClearer-e5d291').style.display = 'block'; document.getElementById('sfMiniToolbar-e5d291').style.display = 'none'; } }, function(xhr) { if (xhr.status !== 0) { confirm('An error occurred while loading the web debug toolbar (' + xhr.status + ': ' + xhr.statusText + ').\n\nDo you want to open the profiler?') && (window.location = '/employees/app_dev.php/_profiler/e5d291'); } } ); })();/*]]>*/</script>
</body>
</html>
Finally, here is the relevant output of the error message from Codeception:
1) Failed to find an employee in the database in FindEmployeeCept.php
Sorry, I couldn't click "Save","#employeeLookup_save":
Behat\Mink\Exception\ElementException: Exception thrown by ((//html/descendant-or-self::*[#id = 'employeeLookup_save'])[1]/.//input[./#type = 'submit' or ./#type = 'image' or ./#type = 'button'][(((./#id = 'Save' or ./#name = 'Save') or contains(./#value, 'Save')) or contains(./#title, 'Save'))] | .//input[./#type = 'image'][contains(./#alt, 'Save')] | .//button[((((./#id = 'Save' or ./#name = 'Save') or contains(./#value, 'Save')) or contains(normalize-space(string(.)), 'Save')) or contains(./#title, 'Save'))] | .//input[./#type = 'image'][contains(./#alt, 'Save')] | .//*[./#role = 'button'][(((./#id = 'Save' or ./#name = 'Save') or contains(./#value, 'Save')) or contains(./#title, 'Save') or contains(normalize-space(string(.)), 'Save'))])[1]
Unreachable field "reset"
Again, if the reset button is rendered after the save button in the HTML, the acceptance tests pass just fine. Also, if the reset button is left off of the form entirely, the acceptance test passes as well. Does anyone have any idea what is causing this?