Проверка формы с использованием клиентского обработчика: почему порядок последовательности ввода меняет результат?

Я недавно предложил (вэта почта) скрипт, который проверяет, есть ли ответы в разных полях формы, прежде чем разрешить отправку, и я сделал это, используя клиентский обработчик с валидаторами.

Играя с этим сценарием, я заметил, что в некоторых случаях кнопка отправки включена, даже если не выполнены все условия проверки. Это зависит от порядка заполнения полей.

Для ясности: если вы заполняете каждое поле одно за другим, все в порядке, если по какой-то причине вы меняете эту последовательность (начиная с конца или с середины), случается, чтоfileupload проверка не принимается во внимание, и кнопка отправки активируется без выбора файла.

(Написав это, я понимаю, что это не так ясно ;-), ноглядя на онлайн-тест покажет что я имею ввиду !!)

Вот демонстрационный код, который я использовал, если вы найдете в нем что-то неправильное, объясняющее такое поведение, я буду рад узнать.

var submissionSSKey = '0AnqSFd3iikE3dFZ6M1JDekJIa1I5UEZIZURGN3hhM3c';
var listitems = ['Select a value','value1','value2','value3','value4','value5','value6']
var Panelstyle = {'background':'beige','padding':'40px','borderStyle':'ridge','borderWidth':'15PX','borderColor':'#eecc99'}

function doGet() {
  var app = UiApp.createApplication().setTitle('Form test').setStyleAttribute('padding','50PX');
  var panel = app.createFormPanel().setStyleAttributes(Panelstyle).setPixelSize(400, 250);
  var title = app.createHTML('<B>Form validation test</B>').setStyleAttribute('fontSize','20px').setStyleAttribute('color','brown');
  var grid = app.createGrid(9,2).setId('grid');
  var list1 = app.createListBox().setName('list1');
   for(var i in listitems){list1.addItem(listitems[i])}    
  var list2 = app.createListBox().setName('list2');
   for(var i in listitems){list2.addItem(listitems[i])}    
  var list3 = app.createListBox().setName('list3');
   for(var i in listitems){list3.addItem(listitems[i])}    
  var Textbox1 = app.createTextBox().setWidth('150px').setName('TB1');
  var Textbox2 = app.createTextBox().setWidth('150px').setName('TB2');
  var DateB = app.createDateBox().setWidth('150px').setName('dateB');
  var upLoad = app.createFileUpload().setName('uploadedFile');
  var submitButton = app.createSubmitButton('<B>Submit</B>'); 
  var warning = app.createHTML('Please fill in all fields').setStyleAttribute('background','#FFcc99').setStyleAttribute('fontSize','20px');
  //file upload
  var cliHandler2 = app.createClientHandler()
  .validateLength(Textbox1, 1, 40).validateLength(Textbox2, 1, 40).validateNotMatches(list1,'Select a value').validateNotMatches(list2,'Select a value')
  .validateNotMatches(list3,'Select a value').validateMatches(DateB, '2','g').validateNotMatches(upLoad, 'FileUpload')
  .forTargets(submitButton).setEnabled(true)
  .forTargets(warning).setHTML('Now you can submit your form').setStyleAttribute('background','#99FF99').setStyleAttribute('fontSize','12px');

  //Grid layout of items on form
  grid.setText(0, 0, 'This is a ')
      .setWidget(0, 1, title)
      .setText(1, 0, 'List Selector 1')
      .setWidget(1, 1, list1.addClickHandler(cliHandler2))
      .setText(2, 0, 'List Selector 2')
      .setWidget(2, 1, list2.addClickHandler(cliHandler2))
      .setText(3, 0, 'List Selector 3')
      .setWidget(3, 1, list3.addClickHandler(cliHandler2))
      .setText(4, 0, 'Text Box 1')
      .setWidget(4, 1, Textbox1.addClickHandler(cliHandler2))
      .setText(5, 0, 'Text Box 2')
      .setWidget(5, 1, Textbox2.addClickHandler(cliHandler2))
      .setText(6, 0, 'Date Box')
      .setWidget(6, 1, DateB)
      .setText(7, 0, 'File Upload')
      .setWidget(7, 1, upLoad.addChangeHandler(cliHandler2))
      .setWidget(8, 0, submitButton)
      .setWidget(8, 1, warning);

  var cliHandler = app.createClientHandler().forTargets(warning).setHTML('<B>PLEASE WAIT WHILE DATA IS UPLOADING<B>').setStyleAttribute('background','yellow');
  submitButton.addClickHandler(cliHandler).setEnabled(false);  
  panel.add(grid);
  app.add(panel);
  return app;
}


function doPost(e) {
  var app = UiApp.getActiveApplication();
  var ListVal1 = e.parameter.list1;  
  var ListVal2 = e.parameter.list2;  
  var ListVal3 = e.parameter.list3;  
  var textVal1 = e.parameter.TB1;
  var textVal2 = e.parameter.TB2;
  var dateVal = e.parameter.dateB;
  var sheet = SpreadsheetApp.openById(submissionSSKey).getSheetByName('Summary');
  var lastRow = sheet.getLastRow();
  var targetRange = sheet.getRange(lastRow+1, 1, 1, 6).setValues([[ListVal1,ListVal2,ListVal3,textVal1,textVal2,dateVal]]);
  var fileBlob = e.parameter.uploadedFile;
  var doc = DocsList.createFile(fileBlob);
  app.add(app.createLabel('Thank you for submitting'));
  return app
}

РЕДАКТИРОВАТЬ : Вот модифицированная часть кода, следующая за ответом Фила. Проверка работает более надежно, но все еще есть некоторые раздражающие недостатки дружелюбия пользователя ...

код удален,РЕДАКТИРОВАТЬ 2 окончательный код, полный doGet:

var submissionSSKey = '0AnqSFd3iikE3dFZ6M1JDekJIa1I5UEZIZURGN3hhM3c';
var listitems = ['Select a value','value1','value2','value3','value4','value5','value6']
var Panelstyle = {'background':'beige','padding':'40px','borderStyle':'ridge','borderWidth':'15PX','borderColor':'#eecc99'}

function doGet() {
  var app = UiApp.createApplication().setTitle('Form test').setStyleAttribute('padding','50PX');
  var panel = app.createFormPanel().setStyleAttributes(Panelstyle).setPixelSize(400, 250);
  var title = app.createHTML('<B>Form validation test</B>').setStyleAttribute('fontSize','20px').setStyleAttribute('color','brown');
  var grid = app.createGrid(10,2).setId('grid');
  var list1 = app.createListBox().setName('list1');
   for(var i in listitems){list1.addItem(listitems[i])}    
  var list2 = app.createListBox().setName('list2');
   for(var i in listitems){list2.addItem(listitems[i])}    
  var list3 = app.createListBox().setName('list3');
   for(var i in listitems){list3.addItem(listitems[i])}    
  var Textbox1 = app.createTextBox().setWidth('150px').setName('TB1');
  var Textbox2 = app.createTextBox().setWidth('150px').setName('TB2');
  var DateB = app.createDateBox().setWidth('150px').setName('dateB');
  var upLoad = app.createFileUpload().setName('uploadedFile');
  var uploadtracker = app.createTextBox().setVisible(false);
  var submitButton = app.createSubmitButton('<B>Submit</B>'); 
  var warning = app.createHTML('Please fill in all fields').setStyleAttribute('background','#FFcc99').setStyleAttribute('fontSize','20px');
  //file upload
  var cliHandler2 = app.createClientHandler()
  .validateLength(Textbox1, 1, 40).validateLength(Textbox2, 1, 40).validateNotMatches(list1,'Select a value').validateNotMatches(list2,'Select a value')
  .validateNotMatches(list3,'Select a value').validateMatches(DateB, '2','g').validateMatches(uploadtracker, 'selected')
  .forTargets(submitButton).setEnabled(true)
  .forTargets(warning).setHTML('Now you can submit your form').setStyleAttribute('background','#99FF99').setStyleAttribute('fontSize','12px');
  var cliHandler3 = app.createClientHandler().forTargets(uploadtracker).setText('selected')
  //Grid layout of items on form
  grid.setText(0, 0, 'This is a ')
      .setWidget(0, 1, title)
      .setText(1, 0, 'List Selector 1')
      .setWidget(1, 1, list1)
      .setText(2, 0, 'List Selector 2')
      .setWidget(2, 1, list2)
      .setText(3, 0, 'List Selector 3')
      .setWidget(3, 1, list3)
      .setText(4, 0, 'Text Box 1')
      .setWidget(4, 1, Textbox1)
      .setText(5, 0, 'Text Box 2')
      .setWidget(5, 1, Textbox2)
      .setText(6, 0, 'Date Box')
      .setWidget(6, 1, DateB.addValueChangeHandler(cliHandler2))
      .setText(7, 0, 'File Upload')
      .setWidget(7, 1, upLoad.addChangeHandler(cliHandler3).addChangeHandler(cliHandler2))
      .setWidget(8, 0, submitButton)
      .setWidget(8, 1, warning)
      .setWidget(9,0,uploadtracker)
      .addClickHandler(cliHandler2);

  var cliHandler = app.createClientHandler().forTargets(warning).setHTML('<B>PLEASE WAIT WHILE DATA IS UPLOADING<B>').setStyleAttribute('background','yellow');
  submitButton.addClickHandler(cliHandler).setEnabled(false);  
  panel.add(grid);
  app.add(panel);
  return app;
}

Ответы на вопрос(2)

Ваш ответ на вопрос