Setzen des type-Attributs in jQuery: .attr() versus .prop()

Eigentlich eine simple Aufgabe: Ändere das type-Attribut eines <input>-Tags zur Laufzeit. Anhand eines kleinen Beispiels lässt sich einiges über jQuery, Attribute und Eigenschaften lernen.

In Pocket speichern vorlesen Druckansicht 4 Kommentare lesen
Lesezeit: 3 Min.
Von
  • Kai König

Vor einigen Tagen wollte ich eine auf den ersten Blick einfache Interaktion mit HTML und jQuery erstellen. Es handelte sich um ein Formular innerhalb eines mobilen Interfaces (mit jQuery Mobile), bestehend aus zwei Eingabefeldern für Betreff und Text einer zu versendenden Nachricht.

Die Anforderung war: Wenn das Senden erfolgreich war, wir uns im success-Handler des AJAX-Aufrufs befinden, soll die versendete Nachricht ins DOM aufgenommen, gleichzeitig das Betreff-Feld von einem <input type="text"...> in ein <input type="hidden"> geändert und mit dem existierenden und versandten Wert des Betreff-Feldes belegt werden.

Das ist auch alles ganz einfach – bis auf die Tatsache, dass der Aufruf von .attr("type", "hidden") zu einer JavaScript-Exception auf der Konsole mit der Meldung "type property can't be changed" führt. Die hier betroffene Anwendung nutzt jQuery 1.6.4, und eine kurze Suche im Quelltext der Bibliothek führt zu:

// We can't allow the type property to be changed (since it causes problems in IE)
if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error( "type property can't be changed" );
} ...

Aha, Problem erkannt – IE-Kompatibilität. Die hier entwickelte Anwendung (bzw. ihr View) wird allerdings niemals auf IE laufen, sondern mehr oder weniger exklusiv auf iOS-Geräten. Man kann nun dieser jQuery-Einschränkung auf mehrere Arten ausweichen:

  1. Man nutzt "klassisches" JavaScript zur Manipulation des DOMs.
  2. Man arbeitet mit zwei Eingabefeldern (einem "echten" und dem verborgenen) und schaltet die Sichtbarkeit des eigentlichen Feldes je nach Bedürfnissen ein oder aus und kopiert die benötigten Daten mit ein wenig jQuery-Code hin und her.
  3. Man benutzt die jQuery .detach()-Funktion, um das betreffende Element kurzfristig aus dem DOM zu entfernen, ändert das type-Attribut und fügt das Element wieder ein. Zusammen mit dem benötigten Code, um eine temporäre Markierung in das DOM einzufügen, sieht das ungefähr wie folgt aus:
    marker = $"('<span />').insertBefore($subject);
    $subject.detach().attr('type','hidden').insertAfter(marker);

    marker.remove();
  4. Man benutzt .prop() an Stelle von .attr(): $subject.prop("type","hidden");.

Ich habe mich am Ende für die dritte Option entschieden – letztlich weil sie mir am saubersten erschien. Das Änderen des type-Attributs im Zustand "detached" ist auf jeden Fall auch schon mit jQuery 1.4.2 möglich – mit älteren Versionen habe ich das Verhalten nicht getestet (.prop() aus Option 4 wird übrigens seit jQuery 1.6 unterstützt).

Warum aber nicht Option 4? Von einem rein funktionalen Standpunkt aus gesehen spricht nichts dagegen – sie scheint tadellos den Anforderungen zu genügen. Das Problem ist, dass .attr() und .prop() eine deutlich unterschiedliche Semantik haben. Kurz gefasst: .attr() sollte verwendet werden, um auf Tag-Attribute zuzugreifen, .prop(), um auf DOM-Eigenschaften zuzugreifen, die kein äquivalentes Tag-Attribut haben. Die oben verlinkten API-Dokumentationen beider Funktionen erklären den Unterschied (und damit ggf, verbundene Probleme) anhand einiger Beispiele genauer. ()