Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Кнопка переименования элемента списка. (https://javascript.ru/forum/dom-window/74320-knopka-pereimenovaniya-ehlementa-spiska.html)

Setraiser 01.07.2018 13:18

Кнопка переименования элемента списка.
 
Всем Добрый День.

Я новичок в изучении JavaScript. Работаю над простым модулем, если его можно назвать таковым, простой ToDoList (Список дел). Он сам работает прекрасно, но я хочу сделать кнопку переименования элемента списка. Но проблема заключается в том, что в элементе списка (li), помимо его названия, лежат ещё две кнопки: ода кнопка для переименования, другая для удаления (<li>text<button>Edit</button><span>X</span></li>). И если например делать переименование элемента через prompt, то оно, конечно, переименует его, но при этом сотрет ещё и теги внутри (кнопки). Я решил попробовать сделать переименование при помощи регулярных выражений и использовать replace (string.replace(/[^<>/]/, prompt) - это просто наглядный пример, как примерно я думал делать переименование. Здесь проблема заключается в том, что при нажатии на кнопку prompt для переименования вылетает, но при нажатии OK, он ничего не переименовывает, при это, не выдает никакую ошибку.

list.addEventListener('click', function(ev) {
  if(ev.target.tagName === "BUTTON") {
    var li = document.querySelector('li');
    var regRename = /[^<>/]/ig;
       
     //var a = prompt('Переименование элемента');
     li.textContent.replace(regRename, prompt());
     
     if(reg.test(li.textContent) === false) return false;
    
  }
}, false);

рони 01.07.2018 13:38

Setraiser,
https://javascript.ru/forum/misc/455...tml#post302151

Setraiser 01.07.2018 14:47

А есть что нибудь именно на нативном JS? JQ пока не сильно пользовался, хочу пока реализовать пока без него.

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

Но у меня еще возник вопрос. В таком случае в value не будут находится кнопки?

p.s. прошу понять и простить, если где то могу тупить

рони 01.07.2018 14:49

Цитата:

Сообщение от Setraiser
В таком случае в value не будут находится кнопки?

не будут

рони 01.07.2018 14:55

Цитата:

Сообщение от Setraiser
А есть что нибудь именно на нативном JS?

https://javascript.ru/forum/dom-wind...tml#post302977

j0hnik 01.07.2018 17:57

<ul contenteditable="true">
	<li>задача 1</li>
	<li>задача 2</li>
	<li>задача 3</li>
</ul>

j0hnik 02.07.2018 04:34

<li>Пункт1</li>
<li>Пункт2</li>
<li>Пункт3</li>
<input type="checkbox"> Редактирование
<script>
document.querySelector("input").onchange = e => document.querySelectorAll("li").forEach(el=>el.contentEditable = e.target.checked ? true : false);
</script>

Setraiser 02.07.2018 18:00

Спасибо) Получилось) Но хотелось бы ещё узнать, когда нужно уже подтвердить изменение, т.е. вернуть обратно в элемент списка ли (input превратить в li обратно), то это можно сделать обратный replaceChild? Или как то можно использовать toggle, например нажав на кнопку Edit, включается редактирование элемента списка в виде input, и второй раз нажать, оно возвращается обратно.

рони 02.07.2018 18:39

Цитата:

Сообщение от Setraiser
например нажав на кнопку Edit, включается редактирование элемента списка в виде input, и второй раз нажать, оно возвращается обратно.

и в чём проблема?

Setraiser 02.07.2018 19:44

Я пробовал делать подтверждение изменения текста в строке через событие keyup. Но у меня возникала ошибка, когда я делал replaceChild.
var input = document.createElement('input');
input.className = 'data';
input.value = div.firstChild.data;
div.replaceChild(input, div.firstChild);

// div - родительский элемент кнопки, где была нажата кнопка, т.е. <li>, где меняется текст.
Потом пробовал сделать при нажатии enter наоборот.

div.firstChild.data = input.value;
input.replaceChild(div, input.firstChild);


Т.е. назначается значение li с input.value, потом делаем replaceChild, меняем input на li (Родительский). По сути вроде так, но он ругается на то, что input не узел. У меня тут пробел в том, что я не знаю, как вернуть обратно, ведь по сути, то же самое, но оно выходит, воспринимает это по другому. Как вернуть input обратно на li?
И делать это, например, через тот самый toggle - нажал кнопку и div.firstChild.data превращается в input.value, другой раз нажал, и input.value превращается в div.firstChild.data.

рони 02.07.2018 20:18

редактирование текста в начале LI
 
Setraiser,
<!DOCTYPE html>

<html>
<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  </style>
 <script src="https://cdn.polyfill.io/v1/polyfill.js?Element.prototype.closest"></script>

  <script>
document.addEventListener("DOMContentLoaded", function() {
    var input = document.createElement("input"),
        title = ["Edit", "Ok"],
        list = document.querySelector(".list"),
        edit = 0,
        li;

    function replaceNode(elem) {
        var first = elem.firstChild,
            button = elem.querySelector("button");
            edit ^= 1;
        edit ? input.value = first.data : input.data = first.value;
        input = elem.replaceChild(input, first);
        button.textContent = title[edit];
        edit ? elem.firstChild.focus() : li = void 0
    }
    list.addEventListener("click", function(event) {
        var target = event.target,
            parent = target.parentNode;
        if (target.closest(".edit")) {
            if (li && li != parent) replaceNode(li);
            li = parent;
            replaceNode(li)
        }
        if (target.closest(".del")) {
            if (li && li == parent) replaceNode(li);
            list.removeChild(parent)
        }
    })
});
  </script>
</head>

<body>
<ul class="list">
    <li>text 1<button class="edit">Edit</button><span class="del">X</span></li>
    <li>text 2<button class="edit">Edit</button><span class="del">X</span></li>
    <li>text 3<button class="edit">Edit</button><span class="del">X</span></li>
</ul>

</body>
</html>

Setraiser 03.07.2018 17:37

У меня несколько иной случай, в вашем примере элементы списка уже есть, в моем же случае, в начале просто строка (input) для добавления элементов. И поэтому начинает ругаться на addEventListener.

http://prntscr.com/k22b5v

Поэтому, у меня тоже возникают проблемы при моих попытках добавить событие на input.

Когда добавляю событие на input (его же по логике пока нет, он null, он начинает ругаться). Пробовал делать например при keyup делать еще div.replacChild(span, div.firstChild) - поменять первый элемент (input), на span, ведь изначально первый элемент - простая строка, не тег. Поэтому я решил поменять на span.

У меня сейчас проблема, как я писал выше, не добавляет событие на инпут, пишет, мол это не функцияhttp://prntscr.com/k22ijs

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

list.addEventListener('click', function(event) {
  if(event.target.tagName === "BUTTON") {
    var div = event.target.parentNode;
    var target = event ? event.target : window.event.srcElement;
    var input = document.createElement('input');
    input.className = 'data';
    input.value = div.firstChild.data;
    div.replaceChild(input, div.firstChild);
    if (div == target) input.focus();

  }
}, false);


var input = document.getElementsByClassName('.data');
    input.addEventListener('keyup', function(event) {

      if (event.keyCode === 13) {
        
        var div = event.target.parentNode;
        var span = document.createElement('span');
        span.data = div.firstChild.value;
        div.replaceChild(span, div.firstChild);
      };


  }, false);

рони 03.07.2018 17:54

Setraiser,
сделайте минимальный макет

Setraiser 03.07.2018 18:21

Великоват конечно будет...
Последний кусок кода, который должен менять обратно текстовую часть, закомментирован, т.к. он вызовет ошибку....
<!DOCTYPE html>
<html lang='ru'>
<head>
    <meta charset="utf-8" />
    
    <title>ToDoList</title>
    
    <style>
   
    .data{
   
    width: 70%;
    height: 50%;
    margin-top: -2%;
}

ul {

    margin: 0;
    padding: 0;
    list-style: none;
}

ul li {
    position: relative;
    
    background: #eee;
    font-size: 18px;
    
}

ul li.checked {
    background: #888;
    color: #fff;
    text-decoration: line-through;
}
ul li.checked::before {
    content: '';
    position: absolute;
    border-color: #fff;
    border-style: solid;
    border-width: 0 2px 2px 0;
    top: 10px;
    left: 16px;
    transform: rotate(45deg);
    height: 15px;
    width: 7px;
}
    </style>

    
</head>
<body>
    <div class="wrapper">
    <div class="header">
        <h1>ToDoList</h1>
    </div>
    <div class="string">
         <input type="text" placeholder="Type your task..." id="toDoEl" >
    </div>
    <ul id="list">

    </ul>
    <button id="remove" class="remove" onclick="remove()" >
        Clear list
    </button>
</div>
</div>
<script>
    var list = document.querySelector('ul');  
    list.addEventListener('click', function (ev) {  
    if(ev.target.tagName === "LI") {  
       ev.target.classList.toggle('checked'); 
    } else if(ev.target.tagName === "SPAN") {  
       var div = ev.target.parentNode; 
       div.remove(); 
    }
}, false);

var reg = /^([\.\?\!\-\_\s\d]{0,}[a-zа-я]{1,})$/gim

list.addEventListener('click', function(event) {
  if(event.target.tagName === "BUTTON") {
   
    var div = event.target.parentNode;
    var target = event ? event.target : window.event.srcElement;
    var input = document.createElement('input');
    input.className = 'data';
    input.value = div.firstChild.data;
    div.replaceChild(input, div.firstChild);

    if (div == target) input.focus();
                 
  }
}, false);

function newElement() { 

    var li = document.createElement('li'); 
    var inputValue = document.getElementById('toDoEl').value; 
    var t = document.createTextNode(inputValue); 

    li.appendChild(t);  t
    if(reg.test(inputValue) === false) { 
       alert("Type your task!");
    } else {
       document.getElementById('list').appendChild(li);
    }
    document.getElementById('toDoEl').value = "";
    var span = document.createElement('span');
    var txt = document.createTextNode("X"); 
    span.className = "close";
    span.appendChild(txt); 
    var button = document.createElement('button');
    var name = document.createTextNode('Edit');
    
    button.className = 'edit';
    button.appendChild(name);
    li.appendChild(button);
   ;
    li.appendChild(span);
}


var text = document.getElementById("toDoEl");

text.addEventListener("keyup", function(event) {
    
    event.preventDefault();
    if (event.keyCode === 13) newElement();
        
    
});

var remove = function(){

 var liel = document.getElementById('list');
if (document.querySelector('li') === null){
      alert('The List is empty');
    } else {
while (liel.firstChild) {
     
      liel.removeChild(liel.firstChild);
    
        }  
    }
}

/*var input = document.querySelectorAll('.data');
    input.addEventListener('keyup', function(event) {

      if (event.keyCode === 13) {
        
        var div = event.target.parentNode;
        var span = document.createElement('span');
        span.data = div.firstChild.value;
        div.replaceChild(span, div.firstChild);
      };


  }, false);*/
    </script>
</body>
</html>

Dilettante_Pro 03.07.2018 18:38

С использованием технологии j0hnik
Добавляете, меняете...
<ul class="list">
</ul>
<button  id = "add">Добавить</button >
<button  id = "stop">Хватит</button >
<script>
   var list = document.querySelector('.list');
   document.querySelector('#add').onclick = function() {
        document.querySelectorAll("li").forEach(el=>el.contentEditable = false);
        var el = document.createElement('li');
        el.innerHTML = "Type your task...";
        el.setAttribute("contenteditable",true);
        list.appendChild(el);
   }
    document.querySelector('#stop').onclick = function() {
        list.querySelectorAll("li").forEach(el=>el.contentEditable = false);
        this.style.display = "none";
        document.querySelector('#add').style.display = "none";
        list.querySelectorAll('li').forEach(el=>el.onclick = function(){
            alert(this.innerHTML)
        });
    }
 
</script>

Setraiser 03.07.2018 18:50

Я пробовал использовать contentEditable, но оно действует на весь элемент списка. В моем случает мне нужно, чтобы оно работало только на li.firstChild, но оно так работать не хочет, у меня ошибка выскакивала, что li.firstChild.setAttribute("contenteditable",true) ; - не функция.
А нужно это все, т.к. в li у меня лежат теги. И при этом, оно выглядит так - http://prntscr.com/k23if1

Поэтому, замена firstChild элемента li на input выглядит лучше, правда пока без обратного скрипта...

http://prntscr.com/k23jq7

Dilettante_Pro 03.07.2018 18:56

Setraiser,
Вы запускали мой пример (Кнопка Посмотреть) ?

Setraiser 03.07.2018 19:05

Да, запускал. У вас создается элемент списка с именем и при этом ему дается атрибут "contenteditable",true, нажав "хватит", атрибут становится false и кнопки скрываются. Тут все понятно, но у вас же просто пустой li, имеется в виду, что там ничего нет, кроме присвоенного текста. Если делать также у меня, то вы видели, наверное, что у меня происходит взглянув на скриншот, оставленный выше.

Dilettante_Pro 04.07.2018 10:10

Цитата:

Сообщение от Setraiser
у вас же просто пустой li, имеется в виду, что там ничего нет, кроме присвоенного текста

Вместо этого текста можно ввести руками все, что вам угодно. Или вам что-то другое нужно? Не понимаю:-?

Setraiser 04.07.2018 12:08

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

Dilettante_Pro 04.07.2018 12:50

Setraiser,
Покажите пример, что у вас в li должно лежать в итоге

Setraiser 04.07.2018 15:43

<li>Text<button class="edit">Edit</button><span class="close">X</span></li>

Manyasha 04.07.2018 16:25

в последнем примере от Рони заменила 2 момента (см. комменты). Код добавления новых элементов Ваш.
<!DOCTYPE html>
<html lang='ru'>
<head>
    <meta charset="utf-8" />
     
    <title>ToDoList</title>
     
    <style>
    
    .data{
    
    width: 70%;
    height: 50%;
    margin-top: -2%;
}
 
ul {
 
    margin: 0;
    padding: 0;
    list-style: none;
}
 
ul li {
    position: relative;
     
    background: #eee;
    font-size: 18px;
     
}
 
ul li.checked {
    background: #888;
    color: #fff;
    text-decoration: line-through;
}
ul li.checked::before {
    content: '';
    position: absolute;
    border-color: #fff;
    border-style: solid;
    border-width: 0 2px 2px 0;
    top: 10px;
    left: 16px;
    transform: rotate(45deg);
    height: 15px;
    width: 7px;
}
    </style>
	
     
</head>
<body>
    <div class="wrapper">
    <div class="header">
        <h1>ToDoList</h1>
    </div>
    <div class="string">
         <input type="text" placeholder="Type your task..." id="toDoEl" >
    </div>
    <ul id="list">
 
    </ul>
    <button id="remove" class="remove">
        Clear list
    </button>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
    var input = document.createElement("input"),
        title = ["Edit", "Ok"],
        list = document.querySelector("#list"),//#list вместо .list
        edit = 0,
        li;
 
    function replaceNode(elem) {
        var first = elem.firstChild,
            button = elem.querySelector("button");
            edit ^= 1;
        edit ? input.value = first.data : input.data = first.value;
        input = elem.replaceChild(input, first);
        button.textContent = title[edit];
        edit ? elem.firstChild.focus() : li = void 0
    }
    list.addEventListener("click", function(event) {
        var target = event.target,
            parent = target.parentNode;
        if (target.closest(".edit")) {
            if (li && li != parent) replaceNode(li);
            li = parent;
            replaceNode(li)
        }
		
		//.close, вместо .del
        if (target.closest(".close")) {
            if (li && li == parent) replaceNode(li);
            list.removeChild(parent)
        }
    })
	
	document.getElementById("remove").addEventListener("click", function() {
        [].forEach.call(document.querySelectorAll("#list li"),function(elem){ 
			list.removeChild(elem)
		});
    })
	
	function newElement() {
 
		var li = document.createElement('li');
		var inputValue = document.getElementById('toDoEl').value;
		var t = document.createTextNode(inputValue);
	 
		li.appendChild(t);
		
		var reg = /^([\.\?\!\-\_\s\d]{0,}[a-zа-я]{1,})$/gim
		if(reg.test(inputValue) === false) {
		   alert("Type your task!");
		} else {
		   document.getElementById('list').appendChild(li);
		}
		document.getElementById('toDoEl').value = "";
		var span = document.createElement('span');
		var txt = document.createTextNode("X");
		span.className = "close";
		span.appendChild(txt);
		var button = document.createElement('button');
		var name = document.createTextNode('Edit');
		 
		button.className = 'edit';
		button.appendChild(name);
		li.appendChild(button);
		li.appendChild(span);
	}
	
	var text = document.getElementById("toDoEl");
 
	text.addEventListener("keyup", function(event) {
		event.preventDefault();
		if (event.keyCode === 13) newElement(); 
	});
	
	var remove = function(){
		var liel = document.getElementById('list');
		if (document.querySelector('li') === null){
			  alert('The List is empty');
		} else {
			while (liel.firstChild) {
				liel.removeChild(liel.firstChild);
			} 
		}
	}

});
    </script>
</body>
</html>

Manyasha 04.07.2018 17:09

Забыла про кнопку remove, добавила выше.

Setraiser 05.07.2018 10:19

Спасибо большое) Работает) Всем спасибо за помощь и плюсики)


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