Javascript-форум (https://javascript.ru/forum/)
-   Javascript под браузер (https://javascript.ru/forum/css-html/)
-   -   Область видимости, создание переменных с помощью цикла (https://javascript.ru/forum/css-html/78459-oblast-vidimosti-sozdanie-peremennykh-s-pomoshhyu-cikla.html)

Mikael86 17.09.2019 11:56

Область видимости, создание переменных с помощью цикла
 
Есть ряд переменных
var family = document.getElementsByName("family");
  var name = document.getElementsByName("name");
  var select = document.getElementsByName("select"); 
  var date = document.getElementsByName("date");
  var email = document.getElementsByName("email");
  var phone = document.getElementsByName("phone");
  var text = document.getElementsByName("text");

из них запускаются функции
$(family).change(function(){validname($(family));});
  $(name).change(function(){validname($(name));});
  $(select).change(function(){validtext($(select));});
  $(date).change(function(){validdate($(date));});
  $(email).change(function(){validname($(email));});
  $(phone).change(function(){validphone($(phone));});
  $(text).change(function(){validlenght($(text));});

Вопрос, можно ли их генерировать циклом из массива
что то вроде такого
arr_form = ['family', 'name', 'date', 'select', 'email', 'phone', 'text'];  
  arr_form.forEach(function(element) {
    element = document.getElementsByName(element);
    console.log(element[0].value);
  });

Я так понимаю проблема в области видимости, потому такое решение не взаимодействует с функциями. Пробовал вариант с let но наверное что то не так прописал.
В идеале целью было создать массив ключ-опция, где ключ имя переменной, опция - функция. Что то вроде такого
// значения по умолчанию
let [firstName="Гость", lastName="Анонимный"] = [];

alert(firstName); // Гость
alert(lastName);  // Анонимный

рони 17.09.2019 12:04

Mikael86,
:-? в чём проблема?

Mikael86 17.09.2019 12:08

Цитата:

Сообщение от рони (Сообщение 512872)
Mikael86,
:-? в чём проблема?

arr_form = ['family', 'name', 'date', 'select', 'email', 'phone', 'text'];
arr_form.forEach(function(element) {
element = document.getElementsByName(element);
console.log(element[0].value);
});
Такое решение не работает с функциями, переменные как я понял существуют только внутри цикла
$(name).change(function(){validname($(name));});

рони 17.09.2019 12:16

Mikael86,
var arr_form = ['family', 'name', 'date', 'select', 'email', 'phone', 'text'];
  arr_form.forEach(function(name) {
    var element = document.getElementsByName(name)[0];
    $(element).change(function(){validname($(element))});
  });

Mikael86 17.09.2019 12:20

Немного не то и присвоить разные валидаторы не выйдет и похоже будет работать не онлайн а только в пределах цикла.
validdate, validmail, validtext, validlenght и другие подключаются по ситуации. Извиняюсь вы правы, функция постоянно работает, попробую переформировать массив и формат считывания под значение - опцию. Огромное спасибо, как всегда меня выручаете)

рони 17.09.2019 12:21

Mikael86,
:-?

Mikael86 19.09.2019 02:56

Проблемы со считыванием двухмерного массива обрезает значения
 
перестроил массив под автоматическую генерацию проверок и вычитку,
попытался прогнать через цикл - не заработало. В консоли при попытке вычитать запросы увидел
интересную картинку - все значения key, name, validator, alert обрезаны до 4х символов.

Сам массив
var json_form = [ 
   ['Фамилия:',       'family', 'validname',  'Ошибка при вводе фамилии!!!'],
   ['Имя:',           'name',   'validname',  'Ошибка при вводе имени!!!'],
   ['Телефон:',       'phone',  'validphone', 'Ошибка при вводе телефона!!!'],
   ['E-mail:',        'mail',   'validmail',  'Ошибка при вводе Email!!!'],
   ['Дата отправки:', 'date',   'validdate',  'Ошибка при вводе даты!!!'],
   ['Check статус:',  'check',  'validcheck', 'Не подтверждено!!!'],
   ['Пол:',           'radio',  'validradio', 'Не выбран ни один элемент!!!'],
   ['Сообщение:',     'text',   'validlenght','Поле не заполнено или превышено количество символов!!!'],
   ['Год рождения:',  'select', 'validselect','Не выбрано']
];

Цикл считывания
$('#form').ready(function(){
  errorcount = 0;
  $.each(json_form, function () {
    $.each(this, function(row, value) {
        key = value[0]; name = value[1]; validator = value[2]; alert = value[3];
        console.log(key + name + validator + alert);
        alert_block = $("<p class='error_block'>"+alert+"</p>");

        var name = document.getElementsByName(name);
        checklabel(name);    
        function checklabel(text){      
          if($(text).next().is('label')) {
            label = $(text).next("label"); 
            $(label).after(alert_block)          
          }
          else {
            $(text).after(alert_block)
          }
        };
    
        $(name).change(function(){eval(validator)($(name))});        
    });
  });
  $("input[name=phone]").mask('+3 (999) 999-99-99');/////////подключение маски телефона
});

Mikael86 19.09.2019 03:11

При удалении наружного цикла функция добавления alert-ов заработала, но функции onchange все так же не пашут.
$(name).change(function(){eval(validator)($(name))});

Malleys 19.09.2019 07:10

Цитата:

Сообщение от Mikael86
Есть ряд переменных

Вы можете взять все элементы вашей формы и с уже ними работать. (Например, const elements = document.querySelector("#form").elements;)

Цитата:

Сообщение от Mikael86
функции onchange все так же не пашут.

Событие change всплывает при изменении поля, вы можете на него подписаться и проверять, правильно ли заполнено поле при его изменении
addEventListener("change", ({ target }) => {
	target.checkValidity();
});


Выберите все элементы, которые вас интересуют и подпишитесь на событие invalid, которое происходит при проверке неправильно заполненного поля.

Не нужно создавать отдельные массивы с описанием, как должны проверятся поля, для этого есть сами поля. Для этого есть CSS-селекторы :valid, :invalid, методы для проверки, событие invalid. Вот пример, составленный на основе вашего описания...
<style>

form {
	max-width: 20em;
	padding: 1em;
	margin: auto;
	font: 1em system-ui;
}
	
form > * {
	display: flex;
	flex-direction: column;
	margin-bottom: 1em;
}

input, button, select, textarea { font: inherit; }
	
textarea { resize: vertical; }
	
fieldset {
	border: 1px solid #f1f1f1;
	border-radius: 0.5em;
	flex-direction: row;
}
	
input:not([type]), input[type="tel"], input[type="email"], input[type="date"], input[type="number"], textarea {
	border: none;
	border-radius: 0.5em;
	background: #f1f1f1;
	padding: 0.5em;
}
	
span.error-message {
	padding: 0.5em;
	border-radius: 0.5em;
	color: #F44336;
	font-size: 80%;
	font-weight: bold;
	display: block;
}

:valid + span.error-message {
	display: none;
}
	
</style>

<form>
	<label>
		Фамилия
		<input name="family" required autocomplete="family-name" minlength="1" pattern="\s*\S([\s\S]*\S)?\s*"
			data-custom-validity="Введите свою фамилию!">
	</label>
	
	<label>
		Имя
		<input name="name" required autocomplete="given-name" minlength="1" pattern="\s*\S([\s\S]*\S)?\s*"
			data-custom-validity="Введите своё имя!">
	</label>
	
	<label>
		Телефон
		<input name="phone" type="tel" required autocomplete="tel"
			data-custom-validity="Введите свой номер телефона!">
	</label>
	
	<label>
		Э-почта
		<input name="mail" type="email" required autocomplete="email"
			data-custom-validity="Введите свой Email!">
	</label>
	
	<label>
		Дата отправки
		<input name="date" type="date" required
			data-custom-validity="Введите дату!">
	</label>
	
	<fieldset>
		<legend>Подтверждение</legend>
		<label>
			<input name="check" type="checkbox" required
			data-custom-validity="Подтвердите!">
			Согласен с условиями
		</label>
	</fieldset>
	
	
	<fieldset>
		<legend>Пол</legend>
		<label>
			<input name="radio" type="radio" value="male" required autocomplete="sex"
			data-custom-validity="Выберите свой пол!">
			Мужчина
		</label>
		<label>
			<input name="radio" type="radio" value="female" required autocomplete="sex"
			data-custom-validity="Выберите свой пол!">
			Женщина
		</label>
	</fieldset>
	
	<label>
		Сообщение
		<textarea name="text" required minlength="10" maxlength="1500"
			data-custom-validity="Заполните поле (от 10 до 1500 символов)!"></textarea>
	</label>
	
	<label>
		Год рождения
		<input name="select" type="number" min="1880" max="2001" step="1" required autocomplete="bday-year" size="4"
			data-custom-validity="Введите год рождения (18+)">
	</label>
	
	<button>Отправить</button>
</form>

<script>
	
	addEventListener("change", ({ target }) => {
		target.checkValidity();
	});

	for(const element of document.querySelector("form").elements) {
		element.addEventListener("invalid", event => {
			event.preventDefault();

			for(const label of event.target.labels) {
				for(const errorMessage of label.querySelectorAll(".error-message"))
					errorMessage.remove();

				const errorMessage = document.createElement("span");
				errorMessage.className = "error-message";
				errorMessage.textContent = event.target.dataset.customValidity || event.target.validationMessage;

				label.append(errorMessage);
			}
		});
	}

</script>

рони 19.09.2019 08:23

Malleys,
может строка 129 лишняя?
for(const errorMessage of label.querySelectorAll(".error-message")) 
                    errorMessage.remove();

и её можно заменить на
if(label.querySelector(".error-message")) continue;

Mikael86 19.09.2019 11:46

Решил задачу в 3 массива, мб кому пригодится, в итоге довольно удобно вышло
 
вынес в отдельный файл все функции и обработчики
$(document).ready(function(){
  $('input[type=checkbox]').val('Нет');
  $('input[type=checkbox]:checked').val('Да');
  $('input[type=checkbox]').change(function () {     
      if (this.checked) {
        this.value = 'Да';
      }
      else {
        this.value = 'Нет';
      }
  });
});

$(document).ready(function(){
  $('input[type=radio]').val('Не выбрано');
  $('input[type=radio]').click(function () {
      name = $(this).attr("name")
      label= $(this).next("label");
      radio = document.getElementsByName(name); 

      $.each(radio, function( key, value ) { 
          value.value = label.text()       
      });
  });
});


////////////////////////////////////////////////////////
////////////Функции проверки формы начало///////////////
////////////////////////////////////////////////////////
function validnot(text) {return true}

///////////Проверка заполнения телефона/////////
function validphone(text) {   
  text_val = text.val();
  var pattern1 = /^\+[\d]{1}\ \([\d]{2,3}\)\ [\d]{2,3}-[\d]{2,3}-[\d]{2,3}$/;
  var pattern2 = /^\d[\d\(\)\ -]{4,14}\d$/;
  var pattern3 = /^[\d]{10,11}$/;

  if (pattern1.test(text_val) == true) {
      $(text).removeClass("error");
      $(text).addClass("accept");
      $(text).next(".error_block").css("display","none");
  } 
  else if (pattern2.test(text_val) == true) {
      $(text).removeClass("error");
      $(text).addClass("accept");
      $(text).next(".error_block").css("display","none");
  }
  else if (pattern3.test(text_val) == true) {
      $(text).removeClass("error");
      $(text).addClass("accept");
      $(text).next(".error_block").css("display","none");
  }
  else {
      $(text).removeClass("accept");
      $(text).addClass("error");
      $(text).next(".error_block").css("display","block");
      errorcount++;
  }
}

///////////Проверка заполнения radio/////////
function validradio(text) {
    countradio = 0; 
    $.each( text, function( key, value ) {
      if ($(value).is(':checked')) {               
        countradio++;
      }
      else {}      
    });

    if (countradio > 0){
      $.each( text, function( key, value ) {
        label = $(value).next("label");
        $(label).next(".error_block").css("display","none");        
      }); 

    }
    else {
      $.each( text, function( key, value ) {
        label = $(value).next("label");        
        $(label).next(".error_block").css("display","block");
      });
      errorcount++;
    }
}

///////////Проверка Select/////////
function validselect(text) {   
  text_val = text.val();

  if (text_val == "" || text_val == " "){
    errorcount++;
  } 
  else {}
}

///////////Проверка checkbox/////////
function validcheck(text){  
  text_val = text.val(); 
  label = $(text).next("label"); 

  if (text.is(':checked')){
    $(label).next(".error_block").css("display","none");
  }
  else {
    $(label).next(".error_block").css("display","block");   
    errorcount++;
  }
}  

///////////////////// Проверка длинны текста////////////////////
function validlenght(text) {   
  text_val = text.val();
  var limit = 5; //////Максимальная длинна текста/////////
  var text_length = text_val.length;   

  if (text_val == "" || text_val == " "){
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;
  }
  else if (text_length > limit){
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;
  } 
  else {
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
}

///////////Проверка наличия текста/////////
function validtext(text) {   
  text_val = text.val();

  if (text_val == "" || text_val == " "){
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;
  } 
  else {
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
}

///////////Проверка наличия текста (только буквы)/////////
function validname(text) {   
  text_val = text.val();
  var pattern = /^[a-zа-яё]+$/i;

  if (pattern.test(text_val) == true) {
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  } 
  else {
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;   
  }
}

///////////Проверка заполнения E-mail/////////
function validmail(text) {   
  text_val = text.val();
  var pattern = /^[\w\.\d-_]+@[\w\.\d-_]+\.\w{2,4}$/i;

  if (pattern.test(text_val) == true) {
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  } 
  else {
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;
  }
}

/////////Проверка заполнения даты/////////
function validdate(text) {
  text_val = text.val();

  var pattern1 = /^[\d]{1,2}\/[\d]{1,2}\/[\d]{4}$/;
  var pattern2 = /^[\d]{1,2}\.[\d]{1,2}\.[\d]{4}$/;
  var pattern3 = /^[\d]{1,2}\,[\d]{1,2}\,[\d]{4}$/;
  var pattern4 = /^[\d]{1,2}\-[\d]{1,2}\-[\d]{4}$/;
  var pattern5 = /^[\d]{1,2}\\[\d]{1,2}\\[\d]{4}$/;



  if (pattern1.test(text_val) == true){       
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
  else if (pattern2.test(text_val) == true){       
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
  else if (pattern3.test(text_val) == true){       
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
  else if (pattern4.test(text_val) == true){ 
    $(text).removeClass("error");
    $(text).addClass("accept");
    $(text).next(".error_block").css("display","none");
  }
  else {
    $(text).removeClass("accept");
    $(text).addClass("error");
    $(text).next(".error_block").css("display","block");
    errorcount++;
  }
}
/////////////////////////////////////////////////////////
//////////////Функции проверки формы конец///////////////
/////////////////////////////////////////////////////////


function set_alerts_forms(text){
    $.each(text, function () {
    $.each(this, function (name, value) {
          var name = document.getElementsByName(name);
          alert_block = $("<p class='error_block'>"+value+"</p>");
          checklabel(name);
          function checklabel(text){      
            if($(text).next().is('label')) {
              label = $(text).next("label"); 
              $(label).after(alert_block)          
            }
            else {
              $(text).after(alert_block)
            }
          };       
        });
    });
} 

function set_valids_forms(text){
    $.each(text, function () {
        $.each(this, function (name, value) {
            var name = document.getElementsByName(name);
            $(name).change(function(){eval(value)($(name))});        
        });
    });
} 

function set_valids_onsend_forms(text){
    $.each(text, function () {
      $.each(this, function (name, value) {
          var name = document.getElementsByName(name);
          eval(value)($(name));     
      });
    });
}
function set_messege_forms(text){
    $.each(text, function () {
    $.each(this, function (name, value) {
        var name = document.getElementsByName(name);
        text_val = $(name).val();
        key = value;
        message += key +' '+ text_val +'\r\n';         
      });
    });
}


function sendform(key, validator, form_block){
  errorcount = 0;
  set_valids_onsend_forms(validator);
  if (errorcount == 0){
      message = '';  
      set_messege_forms(key);
      alert('Ваше сообщение успешно отправлено');
      alert(message);
      clearform(form_block);
  }
  else {
    return false;
  }
}

function clearform (text){
    $(text).each(function(){      
      elem = $(this).find('input[type=text],textarea');
      $.each(elem, function (name, value){ 
        value.value = '';          
      });
    });
}


function MyMailer(nameform, validators, alerts, keys){
  var this_form = document.getElementById(nameform);

  var Submit = $(this_form).find("button");
  errorcount = 0;

  set_valids_forms(validators);
  set_alerts_forms(alerts); 

  $(Submit).click(function(){
    sendform(keys, validators, alerts)
  }) 
}

Mikael86 19.09.2019 11:47

и массив + активация формы
/////////////////////////////////////////////////////////////////////////////////
///////////////////////Массивы блоков формы /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

var json_form1_validator = [ 
   {'family': 'validname'},
   {'name': 'validname'},
   {'phone': 'validphone'},
   {'mail': 'validmail'},
   {'date': 'validdate'},
   {'check': 'validcheck'},
   {'radio': 'validradio'},
   {'text': 'validlenght'},
   {'select': 'validselect'}
];

var json_form1_alerts = [ 
   {'family': 'Ошибка при вводе фамилии!!!'},
   {'name': 'Ошибка при вводе имени!!!'},
   {'phone': 'Ошибка при вводе телефона!!!'},
   {'mail': 'Ошибка при вводе Email!!!'},
   {'date': 'Ошибка при вводе даты!!!'},
   {'check': 'Не подтверждено!!!'},
   {'radio': 'Не выбран элемент!!!'},
   {'text': 'Поле не заполнено!!!'},
   {'select': ''}
];

var json_form1_keys = [ 
   {'family': 'Фамилия:'},
   {'name': 'Имя:'},
   {'phone': 'Телефон:'},
   {'mail': 'E-mail:'},
   {'date': 'Дата отправки:'},
   {'check': 'Check статус:'},
   {'radio': 'Пол:'},
   {'text': 'Сообщение:'},
   {'select': 'Год рождения:'}
];

$("input[name=phone]").mask('+3 (999) 999-99-99');/////////подключение маски телефона

///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////SEND MAIL + ONLINE VALIDATION////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////Имя формы/////Массив валидации/////Массив алертов////Массив ключей////////////////
MyMailer(form1, json_form1_validator, json_form1_alerts, json_form1_keys);/////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

Malleys 19.09.2019 12:29

Цитата:

Сообщение от Mikael86
Решил задачу в 3 массива, мб кому пригодится, в итоге довольно удобно вышло

Цитата:

Сообщение от Mikael86
массив + активация формы

Такое нагромождение костылей... Вот что значит изобретать костыли, когда уже давным давно в браузерах есть API для валидации... и главное это всё ужасно не удобно и благоприятная почва для кучи ошибок... не говоря уже о том, что нужно менять в шести местах.

Цитата:

Сообщение от Mikael86
... довольно удобно вышло

Удобно тогда, когда одно поле редактируется в одном месте, а не так, что нужно будет возвращаться и отгадывать где же ещё нужно поменять, чтобы оно наконец-то заработало...

А ваши clearform, функция отправки по нажатию на кнопку. Зачем заново изобретать функционал? Зачем ограничение по нажатию? Неужели нельзя просто отравлять форму любым способом? А если автозаполнение? А если голосовой ввод? Ещё есть у нативной формы такая вещь, что если нажать на Enter у правильно заполненной формы, то форма отправится. Вы это зачем-то выключили?

И зачем на каждом изменении полей вызывать eval? Это можно сделать без eval!

Очень грязное, неочевидное решение, которое всё-таки отправит форму (а это вообще форма? Если нет то это очень плохое решение!) на сервер, если JavaScript отвалится.

Цитата:

Сообщение от рони
может строка 129 лишняя?

Нет, вы можете захотеть сделать интерактивный вывод сообщения о неправильно заполненном поле, который зависит от того, что уже введено.

Mikael86 19.09.2019 13:45

Спасибо за то что указали на ошибки, но я учу javascript по сути неделю после основной работы, так что ошибки естественны. В данный момент это решение удовлетворяет мои потребности, в дальнейшем я наверняка перепишу всё. Но на текущем уровне развития меня хватило только на это. В любом случае ещё раз спасибо что указали на проблемы с этим кодом, и спасибо всем кто давал подсказки.

рони 19.09.2019 19:41

Цитата:

Сообщение от Malleys
Нет, вы можете захотеть сделать интерактивный вывод сообщения о неправильно заполненном поле, который зависит от того, что уже введено.

что бы это значило? а пока, я не понимаю зачем удалять, и тут же снова создавать снова и снова, в чём преимущество с тем чтобы создать один раз и не удалять более?

Mikael86 20.09.2019 01:11

Цитата:

Сообщение от рони (Сообщение 512971)
что бы это значило? а пока, я не понимаю зачем удалять, и тут же снова создавать снова и снова, в чём преимущество с тем чтобы создать один раз и не удалять более?

Я отлично понимаю что можно и нужно сделать лучше, и я бы рад создать один раз и не трогать, но в текущий момент у меня не хватает знаний.
Нет предела совершенству, вырасту по навыкам - сделаю лучше


Часовой пояс GMT +3, время: 15:17.