# Bei Klick jetzigen Text durch <input> ersetzen?



## multimolti (13. Juli 2007)

Hallo!

Ich bastel mir gerade einen MySQL Manager mit PHP. Man kann schon schön Tabellen anzeigen und neue Datensätze hinzufügen, aber alte bearbeiten geht noch nicht. Jetzt möchte ich, das wenn ich auf einen Wert klicke, dort anstatt dem Wert ein <input>-Feld ist, indem der jetzige Wert ist, und dahinter ein "Speichern" Button. Das mit dem Button ist soweit kein Problem, habe dafür eine Funktion:

```
function TextAnzeigen(das)
{
	if(document.getElementById(das).style.display==\'none\') 
   		document.getElementById(das).style.display=\'block\'; 
	else document.getElementById(das).style.display=\'none\';
}
```
Aber ich weiß nicht, wie ich schon vorhandenen Text ersetzen kann, bin nicht wirklich erfahren mit JS. Kann mir jemand einen Tipp/eine Funktion/einen Suchbegriff geben, hab bisher nichts gefunden!

Danke


----------



## Master of Chess (13. Juli 2007)

Du könntest etwas in der Art machen, um den Text durch ein Input-Feld zu ersetzen:


```
<script>
function toggle_text(obj) {
  var i = 0;
  var obj2 = null;
  var nextobj = obj.nextSibling;
  while(i<15) {
    if(nextobj != null && nextobj.nodeName == "INPUT") {
      obj2 = nextobj;
      break;
    }
    nextobj = nextobj.nextSibling;
    i++;
  }
  obj.style.display = "none";
  obj2.style.display = "";
  obj2.value = obj.innerHTML;
  
}
</script>
```


```
<p id="text" onclick="toggle_text(this)" style="margin:0px;">Das ist der Text...</p>
<input type="text" id="textfeld" style="display:none; margin:0px;">
```

Ich hoffe, ich konnte dir helfen.
MoC


----------



## multimolti (13. Juli 2007)

klingt gut, baue ich gleich mal ein!
Wenn es noch fragen gibt, schreibe ich hier wieder


----------



## multimolti (15. Juli 2007)

Soo, doch noch mal eine Frage:
Jetzt möchte ich noch einen Abbrechen-Button einbauen, der die in <input>-Felder umgewandelten Texte wieder zurück in Texte umwandelt. Habe den einfach mal mit 
onClick="toggle_text(document.getElementsByTagName("input"))
geladen, das geht leider nicht. Liegt das daran, das ich der Funktion jetzt ein Array übergebe, die aber nur mit Objekten arbeiten kann? Oder kann die das gar nicht rückgängig togglen?

Brauche eure Hilfe!

Habs so versucht, aber das will nicht:

```
function Abbrechen(allefelder)
{
	for (var i=0; i<allefelder.length; i++) 
	{
		toggle_text(allefelder[i]);
	}
}
```


----------



## Master of Chess (16. Juli 2007)

Für das Zurückverwandeln brauchen wir eine völlig neue Funktion. Denn in der ursprüngliche toggle_text(obj) wird mit der Eigenschaft .nextSibling solange nach INPUT-Elementen gesucht, bis eins gefunden wird. Dieses wird dann sichtbar und das ursprüngliche P-Element unsichtbar gemacht.

Nun liegen für das Zurücktogglen die Ziel-Elemente (<p>) aber *vor* und nicht *nach* dem Ursprungselement (<input>). Die Suche wird deshalb für jedes Element rückwärts durchgeführt - mit der Eigenschaft .previousSibling. Wiederum suchen wir solange nach P-Elementen vor dem Input-Element bis bwir eins finden, und die Sichtbarkeit tauschen. Es ergibt sich also folgende Funktion für das "Zurückverwandeln":

```
function toggle_back() { // verwandelt ALLE <input>-Felder zurück
	var inputs = document.getElementsByTagName("input");
	for(var i=0;i<inputs.length;i++) {  // Für jedes Input auf der ganzen Seite
		if(inputs[i].type != "text")  // (edit) verhindert, dass auch andere Input-
			continue;                   // Elemente wie Buttons entfernt werden
		var obj = inputs[i];
		var j = 0;
		var obj2 = null;
		var lastobj = obj.previousSibling;
		while(j<15) {
			if(lastobj != null && lastobj.nodeName == "P") {
				obj2 = lastobj;
				break;
			}
			lastobj = lastobj.previousSibling;
			j++;
		}
		obj.style.display = "none";  // Input wird ausgeblendet
		obj2.style.display = "";     // P-Element wird wieder eingeblendet
	}
}
```
Das HTML-Dokument könnte so aussehen:

```
<p id="text" onclick="toggle_text(this)" style="margin:0px;">Das ist der Text...</p>
<input type="text" id="textfeld" style="display:none; margin:0px;">
<br><br>
<a href="" onclick="toggle_back(); return false;">Alle Felder "zurücktogglen"</a>
```

Ich hoffe, das beantwortet deine Frage
Master of Chess


----------



## multimolti (16. Juli 2007)

Klappt irgendwie nicht, weiß auch nicht warum. Hab diesen Button:
<input type="button" value="Abbrechen" onClick="toggle_back()">
aber es passiert nichts. Weil Javascript keine Fehler ausgibt, kann ich leider auch nicht sagen warum es nicht geht.

Noch ein paar Fragen:
1. Gibt es irgendein Tool, mit dem man sehen kann, warum ein JS Script nicht funktioniert?
2. Sucht diese Funktion (document.getElementsByTagName("input")) alle Inputs im ganzen HTML-Dokument oder nur in der aktuellen <form>? Weil wenn es die im ganzen Dokument nehmen würde, wären auch meine anderen weg.
3. Warum hier while(j<15) die 15? Woher kommt die, ist die willkürlich festgelegt oder wie kommt man auf den Wert?


----------



## Master of Chess (16. Juli 2007)

Funktioniert es denn, wenn du den Link im Beispiel nimmst? Bei mir funktioniert es mit IE und Firefox...

zu 1: Ja, für Firefox gibt's zum Beispiel "Firebug"
zu 2: Die Funktion sucht alle Input auf der Seite, aber sie werden nur entfernt, wenn auch ein P-Element gefunden wird.
zu 3: Da JS ja eigentlich nicht weiß, welche Input- und P-Element zusammengehören, sucht das Skript die am nächsten zusammenliegenden. Die 15 bedeutet, dass das jeweils zugehörige Objekt maximal 15 Elemente im Objektbaum entfernt sein darf. Wenn es nämlich weiter weg ist, ist es unwahrscheinlich, dass wirklich dieses Objekt gemeint ist. Mann könnte aber auch einen anderen Wert (z.B. 10) nehmen.

Schönen Tag noch
Master of Chess


----------



## multimolti (16. Juli 2007)

Ok, Firebug habe ich, 2. ist gut und 3. ergibt Sinn.

Wenn ich den Link aus dem Beispiel nehme, geht es, also ich sage jetzt mal: es geht soweit, das wenn man klickt, die <p>-Felder wieder angezeigt werden. Aber dazu nimmt der nicht die JS-Funktion, sondern läd durch das href="" einfach die Seite neu, und dann sind ja alle <input>-Felder wieder weg. Also ist so auch eine Methode, zwar nicht die, die ich wollte, aber es funktioniert ja.


----------



## Master of Chess (16. Juli 2007)

Du musst darauf achten, dass wie im Beispiel nach dem toggle_back(); noch ein return false; kommt! Dann wird der Link nicht ausgeführt!


----------



## multimolti (16. Juli 2007)

Das return false steht da, ich habe exakt dies da stehen:

```
<a href="" onclick="toggle_back(); return false;">Abbrechen</a>
```
und trotzdem läd er die Seite neu!

Und mit 

```
<a href="javascript:toggle_back();">Abbrechen</a>
```
geht es leider auch nicht (also es passiert gar nichts)!


----------



## Master of Chess (16. Juli 2007)

Welchen Browser nutzt du denn eigentlich?


----------



## multimolti (16. Juli 2007)

Firefox 2.0, könnte man daraus auch schliessen:


multimolti hat gesagt.:


> Ok, Firebug habe ich, 2. ist gut und 3. ergibt Sinn.


----------



## Master of Chess (16. Juli 2007)

Eigenartig, bei mir funktioniert alles...


----------



## multimolti (17. Juli 2007)

Hmm, also ich poste jetzt einfach mal einen Teil des ausgegebenen Quellcodes, dann kannst du den mal kopieren und sehen woran der Fehler liegt:


```
<form name="tabelle" action="" method="post">
<table border="0"><tbody>
<tr>
  <td><input type="checkbox" name="Datensatz[]" value="37"></td>
  <td><p id="text" onclick="toggle_text(this)" style="margin:0px;">37</p>  <input type="text" name="aendernfeld_name[]" value="37"   	style="display:none; margin:0px;">
  <input type="hidden" name="aendernfeld_name_id[]" id="textfeld" value="37">
  </td>  <td><p id="text" onclick="toggle_text(this)" style="margin:0px;">Admin</p>  <input type="text" name="aendernfeld_name[]" value="Admin"   	style="display:none; margin:0px;">
  <input type="hidden" name="aendernfeld_name_id[]" id="textfeld" value="37">
  </td>  <td><p id="text" onclick="toggle_text(this)" style="margin:0px;">1</p>  <input type="text" name="aendernfeld_name[]" value="1"   	style="display:none; margin:0px;">

  <input type="hidden" name="aendernfeld_name_id[]" id="textfeld" value="37">
  </td>  <td><p id="text" onclick="toggle_text(this)" style="margin:0px;">Admin</p>  <input type="text" name="aendernfeld_name[]" value="Admin"   	style="display:none; margin:0px;">
  <input type="hidden" name="aendernfeld_name_id[]" id="textfeld" value="37">
  </td>
</tr>
</tbody></table>
<input type="submit" name="aendern" value="Änderungen speichern">
<input type="button" name="abbrechen" value="Abbrechen" onClick="toggle_back()">
<a href="javascript:toggle_back();">Abbrechen</a></form>
```

und noch mal das Javascript:

```
function toggle_back()
{
	var inputs = document.getElementsByTagName("input");
	for(var i=0;i<inputs.length;i++)
	{
		var obj = inputs[i];
		var j = 0;
		var obj2 = null;
		var lastobj = obj.previousSibling;
		while(j<15)
		{
			if(lastobj != null && lastobj.nodeName == "P")
			{
				obj2 = lastobj;
				break;
			}
		lastobj = lastobj.previousSibling;
		j++;
		}
	obj.style.display = "none";  // Input wird ausgeblendet
	obj2.style.display = "";     // P-Element wird wieder eingeblendet
	}
}
```


----------



## Gumbo (17. Juli 2007)

Hier eine Nur-JavaScript-Variante:
	
	
	



```
<script type="text/javascript" charset="utf-8">
window.onload = function() {
	var elems = document.getElementsByTagName("*");
	for( var i=0; i<elems.length; i++ ) {
		if( !elems[i].className.match(/(?:^|\s+)editable\(([A-Za-z][A-Za-z0-9-_:.]+)\)(?:\s+|$)/) ) {
			continue;
		}
		elems[i].ondblclick = new Function("startEditing(this, '"+RegExp.$1+"')");
	}
}
	function startEditing( obj, name )
	{
		var input = document.createElement("input");
		input.type = "text";
		input.name = name;
		input.value = obj.firstChild.nodeValue;
		input.onblur = new Function("stopEditing(this.parentNode)");
		obj.ondblclick = null;
		obj.replaceChild(input, obj.firstChild);
		input.focus();
	}
	function stopEditing( obj )
	{
		var text = document.createTextNode(obj.firstChild.value);
		obj.ondblclick = new Function("startEditing(this, '"+obj.firstChild.name+"')");
		obj.replaceChild(text, obj.firstChild);
	}
</script>

<p class="editable(foobar)">foobar</p>
```


----------



## Master of Chess (17. Juli 2007)

Das ist natürlich die beste Lösung.

@multimolti: Könnte es daran liegen, dass mehrere Elementer bei dir die selbe ID haben? IDs müssen im ganzen Dokument *einmalig* sein.


----------



## multimolti (17. Juli 2007)

Habe das mal versucht, aber da passiert einfach gar nichts. Was sollte denn passieren? Soll sich das wieder in eine Input-Feld verwandeln oder was?



Master of Chess hat gesagt.:


> Das ist natürlich die beste Lösung.
> 
> @multimolti: Könnte es daran liegen, dass mehrere Elementer bei dir die selbe ID haben? IDs müssen im ganzen Dokument *einmalig* sein.


Ja, es haben viele Elemente die gleiche ID, aber die ist nur drin, weil das in dem Post vorher auch gemacht war. Ich kann die einfach rausnehmen, ich brauche die nicht. Und warum dürfen die nur einmalig sein? Wenn ich mit CSS etwas formatiere, dann kann ich das ja auch über die class oder die id zuweisen, und da benutze ich die id mehrmals!

EDIT:
Mein Firebug sagt bei jedem klick auf den Abbrechen-Button:
"lastobj has no properties, [Break on this error] lastobj = lastobj.previousSibling;"


----------



## Master of Chess (18. Juli 2007)

IDs dürfen nur einmalig sein, da das die Regeln und Definitionen von HTML so vorschreiben!! Welches Objekt sollte sonst denn auch die Funktion getElementById zurückliefern? Es heißt ja auch nicht getElement*s*ById(). Wenn du bei CSS mehrere identische IDs verwendest, ist das genauso falsch - dafür ist das Attribut _class_ gedacht. Und wie man sieht, verursacht das mehrfache Verwenden von IDs durchaus Fehler und sollte somit auf jeden Fall vermieden werden.

Schönen Tag noch
Master of Chess


----------



## coder shawnie (17. November 2008)

Gumbo hat gesagt.:


> Hier eine Nur-JavaScript-Variante:
> 
> 
> 
> ...



Der Beitrag ist nun zwar schon etwas länger her, aber ich suche seit fast einer Woche nach einer Lösung für mein Problem, wo ich nicht weiter kam und fand sie in dem Vorschlag von Gumbo. Danke an dieser Stelle ;o)

Nun geht's weiter mit meinen Problemen:

Mit der Funktion kreiere ich zwar Inputfelder aber ich habe selbst bei selfhtml nichts gefunden, womit ich die beiden Attribute size und maxlength für die Inputfelder, respektive cols & rows für Textarea, definiere. (
...oder diesen wenigstens eine CSS-Klasse zuweisen.

Um zwischen Inputfeldern und Textareas zu unterscheiden - ich möchte gern beide nutzen - macht sich eine erweiterte RegExp im Klassennamen, die bspw. den letzten Buchstaben abfragt, welcher Input und Textarea definiert, am sinnvollsten, oder gibt's da noch eine einfachere Variante?

Grüße,
Shawnie


----------



## Sven Mintel (17. November 2008)

coder shawnie hat gesagt.:


> Mit der Funktion kreiere ich zwar Inputfelder aber ich habe selbst bei selfhtml nichts gefunden, womit ich die beiden Attribute size und maxlength für die Inputfelder, respektive cols & rows für Textarea, definiere. (
> ...oder diesen wenigstens eine CSS-Klasse zuweisen.



Attribute kannst du per setAttribute() zuweisen:
	
	
	



```
input.setAttribute('size',40)
```

Mit dem class-Attribut geht das theoretisch genauso, da es dort aber ein paar Unterschiede in den Browsern gibt, tu es besser so:

```
input.className='Klassenname'
```


----------



## coder shawnie (17. November 2008)

Super...
Danke für die ultraschnelle Antwort 

Grüße,
Shawnie


----------

