Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Ответ Ajax в нужную строку таблицы формы (https://javascript.ru/forum/dom-window/85499-otvet-ajax-v-nuzhnuyu-stroku-tablicy-formy.html)

Sheratan 20.09.2023 15:28

Ответ Ajax в нужную строку таблицы формы
 
В форме имеется таблица с дополняемыми строками скриптом JS
При вводе в первое поле "артикул" по AJAX делается запрос и в div получаем результат для выбора нужной позиции
При нажатии на выбранную позицию нужно заполнить поля название и код (item_name и item_code) в той строке таблицы в которой был ввод артикула

В JS новичок и совсем не понимаю как получить строку с полями и в нее же внести значения из одного общего DIV. Или целесообразнее делать вывод результатов в DIV для каждой строки таблицы?

Прошу помочь или подсказать или скинуть примеры подобной реализации

function find_item(str) {
 if (str.length==0) {
   document.getElementById("livesearch").innerHTML="";
    document.getElementById("livesearch").style.border="0px";
   return;
  }
 if (window.XMLHttpRequest) {
    // код для IE7+, Firefox, Chrome, Opera, Safari
   xmlhttp=new XMLHttpRequest();
  }else {  // код для IE6, IE5
   xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
 xmlhttp.onreadystatechange=function() {
   if (this.readyState==4 && this.status==200) {
    document.getElementById("livesearch").innerHTML=this.responseText;
      document.getElementById("livesearch").style.border="1px solid #A5ACB2";
    }
  }
 xmlhttp.open("POST","test_ajax_out.php?q="+str,true);
 xmlhttp.send();
}


<form id="myForm">
<table>
<tr>
    <td><input type="text" name="article[]" onkeyup="find_item(this.value)" placeholder="Артикул" /></td>
    <td><input name="item_name[]" placeholder="Название" /></td>
    <td><input name="item_code[]" placeholder="Код" /></td></tr>
<tr>
    <td><input type="text" name="article[]" onkeyup="find_item(this.value)" placeholder="Артикул" /></td>
    <td><input name="item_name[]" placeholder="Название" /></td>
    <td><input name="item_code[]" placeholder="Код" /></td></tr>
<tr>
    <td><input type="text" name="article[]" onkeyup="find_item(this.value)" placeholder="Артикул" /></td>
    <td><input name="item_name[]" placeholder="Название" /></td>
    <td><input name="item_code[]" placeholder="Код" /></td></tr>
</table>   
<div id="livesearch">найденные варианты</div> 
</form>


Ответ AJAX - по запросу будут получены данные
<a href="#" onclick="" id="aa11">aaaaa</a><br />
<a href="#" onclick="" id="bb22">bbbbb</a><br />
<a href="#" onclick="" id="cc33">ccccc</a><br />
<a href="#" onclick="" id="dd44">ddddd</a><br />
<a href="#" onclick="" id="ee55">eeeee</a><br />

Sheratan 20.09.2023 17:22

jquery-3.4.1 подключен
cms нет, весь код свой

voraa 21.09.2023 08:26

И не использовать метод POST для GET запроса
Цитата:

Сообщение от Sheratan
xmlhttp.open("POST","test_ajax_out.php?q="+str,tru e);


Sheratan 21.09.2023 15:52

Спасибо за подсказку.
-Переделал вывод на json
-Настроил вставку нескольких значений в свои поля
Но в силу своей безграмотности и малого опыта не понимаю как реализовать работу с несколькими строками.
Сейчас работает только первая строка.
Т.е. куда и как прикрутить $(this).closest('tr') чтобы не использовать id в полях.
Пожалуйста, помогите докурутить построчную работу.

<div>
<table>
<tr>
	<td><input type="text" name="article[]" id="article" placeholder="article" /></td>
	<td><input type="text" name="name[]" id="name" placeholder="Name"  /></td>
	<td><input type="text" name="code[]" id="code" placeholder="Code"  /></td>
	<td><input type="text" name="ven[]"  id="ven"  placeholder="ven"  /></td>
</tr>
<tr>
	<td><input type="text" name="article[]"  placeholder="article" /></td>
	<td><input type="text" name="name[]"  placeholder="Name"  /></td>
	<td><input type="text" name="code[]"  placeholder="Code"  /></td>
	<td><input type="text" name="ven[]"   placeholder="ven"  /></td>
</tr>
<tr>
	<td><input type="text" name="article[]"  placeholder="article" /></td>
	<td><input type="text" name="name[]"  placeholder="Name"  /></td>
	<td><input type="text" name="code[]"  placeholder="Code"  /></td>
	<td><input type="text" name="ven[]"   placeholder="ven"  /></td>
</tr>
</table>
<ul id="result"></ul>
</div>


$(document).ready(function(){
 $.ajaxSetup({ cache: false });
 $('#article').keyup(function(){
  $('#result').html('');
  $('#code').val('');
  var searchField = $('#article').val();
  var expression = new RegExp(searchField, "i");
  var flickerAPI  = "test_ajax5_out.php";
  $.getJSON(flickerAPI , function(data) {
   $.each(data, function(key, value){
    if (value.article.search(expression) != -1)
    {
     $('#result').append('<li>'+value.name+'<span style="visibility: hidden;">|'+value.code+'|'+value.article+'|'+value.ven+'</span></li>');
    }
   });   
  });
 });
 
 $('#result').on('click', 'li', function() {
  var click_text = $(this).text().split('|');
  $('#article').val($.trim(click_text[2]));
  $('#name').val($.trim(click_text[0]));
  $('#code').val($.trim(click_text[1]));
  $('#ven').val($.trim(click_text[3]));
  $("#result").html('');
 });
});

Sheratan 21.09.2023 21:51

Да, данные на сервер пока не передаются, т.к. основная проблема в многострочности поиска.
По первой строке все работает как нужно/ Вводится артикул - выдаются совпадающие по коду данные

выборка из базы это на потом отложил.
Пока важнее настроить таблицу

flickerAPI убрал, это было наследие от проб разных скриптов

voraa 22.09.2023 08:21

Хотелось бы понять всю задачу, что бы код 100 раз не делать.

У вас в таблице input задан и для Name и для Code и для ven вместе с placeholder. В них тоже должно что то вводиться и искаться по ним?

Sheratan 22.09.2023 09:12

задача:
- вводится артикул или его часть - появляется список, где есть вхождения введенного значения.
если в списке есть позиция и ее выбирают, то заполняются поля name code ven, а так-же сам артикул заполняется полностью.
При заполнении из списка поля name code ven перестают быть доступными для ввода (readonly),
далее переход к новой строке...
- Если введенный артикул или его часть не нашлись в списке или из списка не было ничего выбрано, то руками заполняются все поля,
далее переход к новой строке...

Список формируется по запросу введенного артикула и выбирается из базы более 50000 позиций

Собственно это все

voraa 22.09.2023 09:59

Переделав вариант из поста #1
могу предложить следующее

<div>
<table>
<tr>
    <td><input type="text" name="article[]" id="article" placeholder="article" /></td>
    <td><input type="text" name="name[]" id="name" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" id="code" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  id="ven"  placeholder="ven"  /></td>
</tr>
<tr>
    <td><input type="text" name="article[]" id="article" placeholder="article" /></td>
    <td><input type="text" name="name[]" id="name" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" id="code" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  id="ven"  placeholder="ven"  /></td>
</tr>
<tr>
    <td><input type="text" name="article[]" id="article" placeholder="article" /></td>
    <td><input type="text" name="name[]" id="name" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" id="code" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  id="ven"  placeholder="ven"  /></td>
</tr>
</table>
<ul id="result"></ul>
</div>
</body>


// Заполнение строки даблицы
// data - эдемент массива данных
// inp - элемент ввода по которому искали
// li - элемент на котором кликнули
function outputInTable(data, inp, li) {
	const tr = inp.closest('tr');
	tr.querySelector('[name="article[]"]').value = data.article;
	tr.querySelector('[name="name[]"]').value = data.name;
	tr.querySelector('[name="code[]"]').value = data.code;
	tr.querySelector('[name="ven[]"]').value = data.ven;
	li.closest('ul').textContent = '';
}

// Вывод списка найденых
// inp - элемент в котором был ввод
// ardata - массив найденых значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		li.addEventListener('click', () => outputInTable(data, inp, li), {once:true});
	}
}

function findItem ({target}) {
	const searchStr = target.value;
	fetch('test_ajax_out.php?q='+searchStr)
	.then(responce => responce.json())
	.then (data => outputSearchData(target, data))
}

document.addEventListener('DOMContentLoaded', () => {
	const articles = document.querySelectorAll('input[name="article[]"]')
	articles.forEach(article => article.addEventListener('keyup', findItem));
})

Sheratan 22.09.2023 10:55

Спасибо!
Отличная работа!
1 вопрос - в каком месте и как установить readonly для трех полей?
2 вопрос - после выбора в списке и подстановки в таблицу, в случае правки артикула нужно сбросить заполненные поля и снять readonly

voraa 22.09.2023 11:10

Цитата:

Сообщение от Sheratan
Один вопрос - в каком месте и как установить readonly для трех полей?

Немного переделал
// Заполнение строки даблицы
// data - эдемент массива данных
// inp - элемент ввода по которому искали
function outputInTable(data, inp) {
	const tr = inp.closest('tr');
	const article = tr.querySelector('[name="article[]"]');
	article.value = data.article;
	const name = tr.querySelector('[name="name[]"]');
	name.value = data.name;
	name.readOnly = true;
	const code = tr.querySelector('[name="code[]"]');
	code.value = data.code;
	code.readOnly = true;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = data.ven;
	ven.readOnly = true;
}

// Вывод списка найденых
// inp - элемент в котором был ввод
// ardata - массив найденых значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		li.addEventListener('click', () => {
				outputInTable(data, inp);
				ul.textContent = '';
			},
			{once:true}
		);
	}
}

function findItem ({target}) {
	const searchStr = target.value;
	fetch('test_ajax_out.php?q='+searchStr)
	.then(responce => responce.json())
	.then (data => outputSearchData(target, data))
}

document.addEventListener('DOMContentLoaded', () => {
	const articles = document.querySelectorAll('input[name="article[]"]')
	articles.forEach(article => article.addEventListener('input', findItem));
})

Sheratan 22.09.2023 11:18

readonly работает
но как ее снять и очистить поля, если решил ввести новую позиции как-бы отменив свой выбор в списке
а то получается что можно использовать name code и ven с любым article не совпадающем в списке

voraa 22.09.2023 11:55

Цитата:

Сообщение от Sheratan
если решил ввести новую позиции как-бы отменив свой выбор в списке

Не убирать список после выбора позиции в нем. При вводе в другой article просто показывать новый список.
Другое дело, что если пользователь вводит в article, потом выбирает из списка, потом решает, что ошибся, меняет article так, что список оказывается пустым и теперь ему надо вводить все поля вручную. Тут уже будет невозможно ввести, так как поля уже отмечены readonly.
Надо снимать этот атрибут, если список пуст.
По хорошему надо и значения всех полей убирать, если пользователь начинает исправлять article

Что то типа такого
// Заполнение строки даблицы
// data - эдемент массива данных
// tr - строка в которую был ввод
function outputInTable(data, tr) {
	const article = tr.querySelector('[name="article[]"]');
	article.value = data.article;
	const name = tr.querySelector('[name="name[]"]');
	name.value = data.name;
	name.readOnly = true;
	const code = tr.querySelector('[name="code[]"]');
	code.value = data.code;
	code.readOnly = true;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = data.ven;
	ven.readOnly = true;
}

// Очистка строки в которую идет ввод и снятие readonly
// tr - строка в которую был ввод
function clearFields (tr) {
	const name = tr.querySelector('[name="name[]"]');
	name.value = '';
	name.readOnly = false;
	const code = tr.querySelector('[name="code[]"]');
	code.value = '';
	code.readOnly = false;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = '';
	ven.readOnly = false;
}

// Вывод списка найденых
// inp - элемент в котором был ввод
// ardata - массив найденых значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	const tr = inp.closest('tr');
	clearFields(tr);
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		li.addEventListener('click', () => outputInTable(data, tr), {once:true}	);
	}
}

function findItem ({target}) {
	const searchStr = target.value;
	fetch('test_ajax_out.php?q='+searchStr)
	.then(responce => responce.json())
	.then (data => outputSearchData(target, data))
}

document.addEventListener('DOMContentLoaded', () => {
	const articles = document.querySelectorAll('input[name="article[]"]')
	articles.forEach(article => article.addEventListener('input', findItem));
})

Sheratan 22.09.2023 13:16

Цитата:

Сообщение от voraa
Не убирать список после выбора позиции в нем. При вводе в другой article просто показывать новый список.

Полученный список вариантов после нажатия и заполнения полей конечно надо убрать т.к. он мешает дальнейшей работе

voraa 22.09.2023 13:38

Ну значит убирать список. Но, что бы его снова получить, пользователь должен начать редактировать поле article. Ему так и так придется его редактировать, что бы получить список. По полностью заполненному значению поля мы получим только одну строку (или не одной).
// Заполнение строки таблицы
// data - элемент массива данных
// tr - строка в которую был ввод
function outputInTable(data, tr) {
	const article = tr.querySelector('[name="article[]"]');
	article.value = data.article;
	const name = tr.querySelector('[name="name[]"]');
	name.value = data.name;
	name.readOnly = true;
	const code = tr.querySelector('[name="code[]"]');
	code.value = data.code;
	code.readOnly = true;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = data.ven;
	ven.readOnly = true;
}

// Очистка строки в которую идет ввод и снятие readonly
// tr - строка в которую был ввод
function clearFields (tr) {
	const name = tr.querySelector('[name="name[]"]');
	name.value = '';
	name.readOnly = false;
	const code = tr.querySelector('[name="code[]"]');
	code.value = '';
	code.readOnly = false;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = '';
	ven.readOnly = false;
}

// Вывод списка найденых
// inp - элемент в котором был ввод
// ardata - массив найденых значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	const tr = inp.closest('tr');
	clearFields(tr);
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		li.addEventListener('click', () => {
				outputInTable(data, tr);
				ul.textContent = '';
			},
			{once:true}	);
	}
}

function findItem ({target}) {
	const searchStr = target.value;
	fetch('test_ajax_out.php?q='+searchStr)
	.then(responce => responce.json())
	.then (data => outputSearchData(target, data))
}

document.addEventListener('DOMContentLoaded', () => {
	const articles = document.querySelectorAll('input[name="article[]"]')
	articles.forEach(article => article.addEventListener('input', findItem));
})


PS Если там более 50 000 позиций, то имеет смыл подумать, что бы не выводить так много. Может быть выводить список только если введено не менее 3-4 символов.

Sheratan 22.09.2023 14:09

Цитата:

Сообщение от voraa (Сообщение 553367)
PS Если там более 50 000 позиций, то имеет смыл подумать, что бы не выводить так много. Может быть выводить список только если введено не менее 3-4 символов.

Это я планировал делать на SQL запросе. (кол-во введенных символов и LIMIT)
Или рекомендуешь не делать JS запрос если текста мало?

voraa 22.09.2023 14:57

Цитата:

Сообщение от Sheratan
Это я планировал делать на SQL запросе.
Или рекомендуешь не делать JS запрос если текста мало?

А что вернет сервер, если текста мало? Пустой массив? И какой смысл делать такой запрос?

Эту функцию так переписать
const MINSEARCHLENGTH = 3;

async function findItem ({target}) {
	const searchStr = target.value;
	let data;
	if (searchStr.length >= MINSEARCHLENGTH) {
		const responce = await fetch('test_ajax_out.php?q='+searchStr);
		data = await responce.json();
	} else {
		data = await [];
	}
	outputSearchData(target, data);
}

Sheratan 22.09.2023 16:02

Все отлично!

Единственно, что в "боевом" скрипте не зашла совместимость с добавлением строк
В добавленных сроках не работает поиск

сможешь помочь в нем?

voraa 22.09.2023 16:16

Цитата:

Сообщение от Sheratan
В добавленных сроках не работает поиск

Вот почему не спрашивать и не описывать задачу всю сразу. Со всеми особенностями. Как будто одно от другого не зависит
Тогда к table id добавить
<body>
<div>
<table id="table">
<tr>
    <td><input type="text" name="article[]" placeholder="article" /></td>
    <td><input type="text" name="name[]" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  placeholder="ven"  /></td>
</tr>
<tr>
    <td><input type="text" name="article[]" placeholder="article" /></td>
    <td><input type="text" name="name[]" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  placeholder="ven"  /></td>
</tr>
<tr>
    <td><input type="text" name="article[]" placeholder="article" /></td>
    <td><input type="text" name="name[]" placeholder="Name"  /></td>
    <td><input type="text" name="code[]" placeholder="Code"  /></td>
    <td><input type="text" name="ven[]"  placeholder="ven"  /></td>
</tr>
</table>
<ul id="result"></ul>
</div>


И событие input ловим на таблице и проверяем, что это нужный элемент (делегирование)
// Заполнение строки таблицы
// data - элемент массива данных
// tr - строка в которую был ввод
function outputInTable(data, tr) {
	const article = tr.querySelector('[name="article[]"]');
	article.value = data.article;
	const name = tr.querySelector('[name="name[]"]');
	name.value = data.name;
	name.readOnly = true;
	const code = tr.querySelector('[name="code[]"]');
	code.value = data.code;
	code.readOnly = true;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = data.ven;
	ven.readOnly = true;
}

// Очистка строки в которую идет ввод и снятие readonly
// tr - строка в которую был ввод
function clearFields (tr) {
	const name = tr.querySelector('[name="name[]"]');
	name.value = '';
	name.readOnly = false;
	const code = tr.querySelector('[name="code[]"]');
	code.value = '';
	code.readOnly = false;
	const ven = tr.querySelector('[name="ven[]"]');
	ven.value = '';
	ven.readOnly = false;
}

// Вывод списка найденных
// inp - элемент в котором был ввод
// ardata - массив найденных значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	const tr = inp.closest('tr');
	clearFields(tr);
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		li.addEventListener('click', () => {
				outputInTable(data, tr);
				ul.textContent = '';
			},
			{once:true}	);
	}
}

const MINSEARCHLENGTH = 3;

async function findItem ({target}) {
	if (target.name !== 'article[]') return;
	const searchStr = target.value;
	let data;
	if (searchStr.length >= MINSEARCHLENGTH) {
		const responce = await fetch('test_ajax_out.php?q='+searchStr);
		data = await responce.json();
	} else {
		data = await [];
	}
	outputSearchData(target, data);
}

document.addEventListener('DOMContentLoaded', () => {
	const table = document.getElementById('table')
	table.addEventListener('input', findItem);
})

Sheratan 22.09.2023 16:42

Цитата:

Сообщение от voraa
Вот почему не спрашивать и не описывать задачу всю сразу. Со всеми особенностями.

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

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

function outputSearchData (inp, ardata) {
document.getElementById('search_result').style.dis play='block';

voraa 22.09.2023 16:48

Цитата:

Сообщение от Sheratan
не ищет сейчас совсем

const table = document.getElementById('table')
table.addEventListener('input', findItem);

Если вы свою table обозвали id='11' то и в .getElementById надо было '11' ставить. В консоле же ошибки сразу видны.

Sheratan 22.09.2023 17:05

Увы, таблиц несколько и они еще и вложенные в другую таблицу

voraa 22.09.2023 17:09

Так и надо указать ид самой внешней таблицы (или внутренние все разные? в примере одинаковые)

Sheratan 22.09.2023 17:13

вложенные по структуре одинаковые

Sheratan 22.09.2023 17:15

на основную индекс добавил, в скрипте указал
нет поиска

правились имена полей в таблице и скрипте

Sheratan 22.09.2023 17:18

нашел ошибку, работает поиск

Sheratan 22.09.2023 17:19

появление div с поиском при вводе 1,2 символов как скрыть?
(внизу зеленый div)

voraa 22.09.2023 18:05

Цитата:

Сообщение от Sheratan
появление div с поиском при вводе 1,2 символов как скрыть?

Как то так можно
// Вывод списка найденых
// inp - элемент в котором был ввод
// ardata - массив найденых значений
function outputSearchData (inp, ardata) {
	const ul = document.getElementById('result');
	ul.textContent = '';
	const tr = inp.closest('tr');
	clearFields(tr);
	let disp = 'none';
	for (const data of ardata) {
		const li = document.createElement('li');
		li.textContent = data.name;
		ul.append(li);
		disp = 'block';
		li.addEventListener('click', () => {
				outputInTable(data, tr);
				ul.textContent = '';
			},
			{once:true}	);
	}
	document.getElementById('search_result').style.display = disp;
}

Sheratan 22.09.2023 20:34

Через несколько попыток удалось решить так
li.addEventListener('click', () => {
				outputInTable(data, tr);
				ul.textContent = '';
				document.getElementById('search_result').style.display='none';


Огромное спасибо за терпение и помощь!!!
:thanks:


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