Ajax holt Daten, JQUERY erkennt ID nicht?
Hallo
Ich hoffe, dass Ihr mir auf die Sprünge helfen könnt.
Mittels Button wird per JQUERY Ajax aufgerufen. Von der Datenbank werden Bilder ausgegeben.
Nun habe ich vorher schon einige Funktion gebastelt, die mir erlauben das Bild zu bearbeiten, z.B. mittels keyUP die Positionen vom Bild zu verändern, Größe und Co.
Da es mehrere Bilder sind, wird in der PHP Datei eine For-schleife erstellt, wo die Inputs und Buttons mit classen (und Id->testzweck) versehen werden (echo-ausgabe).
Nun lassen sich weder die Buttons noch mit Inputs steuern, weder mit this bzw Klassen noch mit der Id.
Hat vielleicht jemand eine Idee woran es liegen könnte?
$('#load_image').click( function (event) {
event.preventDefault();
$.ajax({
type: 'POST',
url: 'ajax/home.php',
data: $(this).serialize(),
success: function (title_image) {
$('#title_image').html(title_image);
}
});
});
<button id="load_image" type="submit" name="load_image" class="btn btn-primary start"> <span><i class="glyphicon glyphicon-picture"></i>Bilder Laden</span> </button>
<div id="title_image" class="margin">
<!-- DIVS vom PHP AJAX -->
</div>
Ajax PHP datei
if (!$title->execute()) {
echo "Fehler";
} else {
$name = array();
while ($data = $title->fetch()) {
$name[] = $data['name'];
}
$count = count($name);
for ($i=0; $i < $count; $i++) {
echo $name[$i];
/* DIVS */
echo ' <input type="number" id="image_horizontal_edit1" value="" placeholder="Horizontal">';
echo ' <input type="number" id="image_vertical_edit1" value="" placeholder="Vertical"><br><br>';
echo ' <input type="number" id="image_zoom_edit1" value="" placeholder="Zoom"><br><br>';
4 Antworten
Nun verstehe ich das richtig, dir geht es um die Controls, die du innerhalb der AJAX Datei nach lädst, sprich in dem Beispiel:
<input type="number" id="image_horizontal_edit1" value="" placeholder="Horizontal">
<input type="number" id="image_vertical_edit1" value="" placeholder="Vertical"><br><br>
<input type="number" id="image_zoom_edit1" value="" placeholder="Zoom"><br><br>
In den Code, den du uns da zeigst sehen wir nix von EventHandlern für diese Controls, also können die auch nix machen. Diese EventHandler müssten ja gebindet werden, nachdem du die Elemente erstellt hast. Sprich in deiner success Funktion kommen, nachdem du sie in den DOM eingefügt hast.
Wenn ich mir deinen unten geposteten Code anschaue, fällt mir sofort ein Fehler auf: Du vergibst IDs mehrmals, obwohl sie eindeutig sein sollten. Je Iteration solltest du eine neue ID generieren:
for ($i = 0; $i < $count; ++$i) {
echo $name[$i];
echo "<input type=\"number\" id=\"image_horizontal_edit{$i}\" placeholder=\"Horizontal\">";
echo "<input type=\"number\" id=\"image_vertical_edit{$i}\" placeholder=\"Vertical\"><br><br>";
echo "<input type=\"number\" id=\"image_zoom_edit{$i}\" placeholder=\"Zoom\"><br><br>";
}
Das value-Attribut brauchst du im Übrigen nicht zu definieren, so lange es keinen eigenen (nicht leeren) Startwert hat.
Bei deinem zweiten Code-Abschnitt (ab /* ===c Bilder Laden === */) weiß ich nun nicht, ob dieser den direkten Anschluss zum obigen Code hat oder wie das zu interpretieren ist. Der JavaScript-Code steht in keinem script-Tag und wird nicht herausgerendert. Das sollte dir als Fehler doch auch schon aufgefallen sein?
Bezüglich deines letzten Code-Abschnitts wäre das zu prüfen, was Dory1 schon geschrieben hat.
Ich schreibe einmal wieder alles auf, was mir zunächst so auffällt.
1) script-Tags gehören in head- oder body-Element. Außerhalb derer dürfen sie nicht stehen. Den jQuery-Include würde ich von daher in den head schieben, das Skript darunter für Slider etc. entweder ebenso oder vor das Ende des body-Körpers. Am besten kommt dessen JS-Code in eine externe Datei, auf die das script-Tag nur verweist.
2) In dem ersten großen Script-Block (den ich eben bereits erwähnt habe), sehe ich immer wieder mehrere aufeinanderfolgende Blöcke mit nahezu gleichem Code - nur der Selektor ändert sich etwas. Da sind bspw. die keyup-Listener, die du definierst. Dazu könntest du dir eine Funktion schreiben, in der alle Vorgänge generalisiert werden.
Ein Beispiel (vgl. mit Zeile 108-117 aus deinem 3. pastebin):
function setImageAndTextKeyUpListener(area) {
$("#title_" + area + "_inp1").keyup(function () {
let value = $(this).val();
$("#ff_home_image_" + area + "1").html(value);
$("#ff_home_image_" + area + "_editor1").html(value);
});
}
setImageAndTextKeyUpListener("header");
setImageAndTextKeyUpListener("text");
Das einzige, was sich in deinen beiden Blöcken ändert, sind die IDs - und das sogar jeweils nur an einer Stelle. Auf das Element selbst, an welches der Listener gehängt wird, kann man mit jQuery übrigens via $(this) zugreifen.
Mache also zunächst aus - welche Code-Blöcke haben viele Gemeinsamkeiten bzw. tun dasselbe, nur halt an individuellen Elementen. Schreibe dazu ruhig eine Funktion. Individuelle Stellen werden mit einem Platzhalter (Parameter) belegt, welcher später bei Aufruf der Funktion gesetzt wird.
3) Lasse leere HTML-Attribute (wie z.B. class="") raus. Es sind nur Daten, die zusätzlich an den Client übermittelt werden müssen, obwohl es nicht notwendig wäre. Zudem blähen sie das Markup auf.
4) Da du im head die Zeichenkodierung UTF-8 gewählt hast, kannst du Umlaute normal schreiben, du musst sie nicht mehr maskieren.
5) Vermeide Inline-Styles (Zeile 776, 786). Stattdessen kannst du die Elemente bspw. mit dem Pseudoselektor nth-child in CSS ansprechen.
/* not tested */
#row_main2 li:last-child {
margin-bottom: .5rem;
}
6) Weiterhin gibt es wieder sehr sehr viel Markup, welches mit PHP verkürzt werden könnte. Bspw. eine Navigation, in der sich nur URL und Title je Listenpunkt ändern: Pack diese Daten in ein assoziatives Array und iteriere über dieses.
Ein simples Beispiel:
$links = array("point a" => "some url", "point b" => "other url", // ...
foreach ($links as $linkTitle => $link): ?>
<li>
<a href="<?= $link $?>"><?= $linkTitle ?></a>
</li>
<?php endforeach; ?>
Zu deinem Problem: Ich glaube, ich habe es nun (so wie auch apachy) verstanden. Du fügst dynamisch HTML-Elemente zu deinem Dokument und möchtest dann auf Events reagieren, die auf ihnen ausgelöst werden können. Das ist aber derzeit noch nicht möglich, da die neuen Elemente zu dem Zeitpunkt, an dem du deine Listener bindest, noch nicht vorhanden sind.
Du musst die Listener also im AJAX Callback binden.
Ich habe einmal ein simples Beispiel geschrieben, welches zeigt, wie es geht.
index.php
<!doctype html>
<head>
<title>Bind event listener to dynamic loaded HTML</title>
<script shttps://code.jquery.com/jquery-latest.jst.js"></script>
</head>
<body>
<button id="load" type="button">Click me</button>
<div id="output"></div>
<script>
$("#load").click(function (event) {
$.post("getParagraphs.php", function (data) {
let output = $("#output");
output.html(data);
$("p", output).click(function () {
$(this).css("background-color", "yellow");
});
});
});
</script>
</body>
getParagraphs.php:
<?php
for ($i = 0; $i < 5; ++$i) {
print "<p id=\"paragraph{$i}\">{$i}</p>";
}
Vielleicht steckst du einfach alle Zeilen, in denen du die neu geladenen Elemente mit Listenern ausstattest, in eine Funktion setup und rufst diese im Callback auf.
Danke, so wie immer, der beste
2. Auf eine Funktion habe ich auch schon gedacht, nur weiß/wusste ich nicht ganz wie ich das schreiben soll, da mein Ansatz nicht wirklich funktionierte.
$('#title_header_inp1').keyUP(function() { headertext(this); });
function headertext(inp) {
if ($(inp).attr('class').includes('header')) {
inputtext = inp.val();
title = $(inp).attr('class').substr(5,6); //So ungefähr glaube ich
$('#ff_home_image_'+title+'1}.html(inptext);
} else if {
..... TEXT ....
}
3. Dachte eigentlich, das es ziemlich egal sein wird ob es jetzt nun da steht oder nicht, da es für sowieso leer ist.
6. Oky, werde ich ausprobieren
Ich hatte zwar etwas Probleme beim nachkonstruierten beim code, aber ich verstehe denn sinn dahinter.
Bei deinem Code-Versuch hättest du ein Problem gehabt: Du hättest für jede Variante des Selektors, einen else-if-Zweig einbauen müssen. Angenommen, da käme nun noch ein title_footer_inp1 hinzu, wären es wieder mehrere Zeilen Code, die eigentlich redundant wären.
Abläufe zu generalisieren, erfordert etwas Übung, aber genügend Fälle hast du bei deinem Code ja gegeben. 😁 Manchmal - das denke ich, sollte ich noch erwähnen, kann es aber auch besser sein, Code zu belassen, wenn die verschiedenen Blöcke, die man zusammenfassen wollen würde, doch zu viele Eigenheiten aufweisen. Da gilt es abzuwägen und zu schauen, ob nicht stattdessen Teilbereiche aufsplitten / auslagern könnte.
Eine generelle Annäherung an die OOP bzw. eine Nutzung dieser, wäre das letztendliche Ziel.
sry wenn ich das jetzt sage, aber jetzt verstehe ich gerade nur bahnhof
Else if versteh ich ja, aber dass andere
In kurz: Schau einfach, ob es Sinn macht, Code über Funktionen zu generalisieren.
Beispiel:
firstRectangle.color = "red";
firstRectangle.innerText = "hello";
firstRectangle.border = "2px solid";
secondRectangle.color = "red";
secondRectangle.border = "2px solid";
secondRectangle.position.x = 50;
thirdRectangle.color = "red";
thirdRectangle.position.y = 5;
thirdRectangle.innerText = "world";
Hier ließen sich z.B. kaum Gemeinsamkeiten finden, bis auf die Zeile, in der die Farbe gesetzt wird. Ob man das wirklich herauszieht, ist Abwägungssache.
let rectangles = [ firstRectangle, secondRectangle, thirdRectangle ];
rectangles[0].innerText = "hello";
rectangles[0].border = "2px solid";
rectangles[1].border = "2px solid";
rectangles[1].position.x = 50;
rectangles[2].position.y = 5;
rectangles[2].innerText = "world";
for (let i = 0; i < rectangles.length; ++i) {
rectangles[i].color = "red";
}
Das lohnt sich vielleicht, wenn man mehrere Properties hat, die zudem immer den gleichen Wert bekommen.
Ok, ja da fällt mir was ein.
Dann hätte ich gleich dazu eine frage
Wie kann ich transform-origin splitten?
Das problem ist, ich habe kein Beistrich als Anhaltspunkt, nur ein Leerzeichen
Möchtest du den Wert dieses Properties in einzelne Worte splitten oder meinst du etwas anderes?
Ein Leerzeichen kann ebenso als Trennzeichen verwendet werden. Beispiel mit JavaScript:
let text = "What a nice day";
let words = text.split(" ");
Hab ich mir schon gedacht
horizontal = $('.header_text_transform').css('transform-origin');
test = parseInt(horizontal.split(' ')[0]);
$('#testss').html(test);
Nur leider bekomme ich garkein ausgabe
Weder bei [0] noch [1]
sryy, ich hab eine Zeile zuweit unten den code eingefügt, da wurde bereits der code etwas gesplittet
Ein Beispiel: https://jsfiddle.net/pbdyxk6L/
Lasse dir einmal den Wert von horizontal ausgeben und prüfe über den Webinspektor, welche Werte für das CSS-Property bei den betroffenen Elementen wirklich angegeben sind.
EDIT: Ah, ok.
Sorry, auch wenn es jetzt schon 5 Tage her ist, zu jQuery, was ich jetzt mit $(document).on('load') gelöst habe. Wie funktioniert es dann bei der einfachen function? Weil das Img was per Ajax hinzugefügt wird, existiert ja eigentlich nicht. Der onclick wird dennoch ausgeführt(hinzugefügten IMG) aber es wird immer das letzte existierende img aufgerufen "currentSlide(6)"
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
<img onclick="currentSlide(7)" class="slideshow-demo slideshow-cursor ff-test-image" alt="Mountains and fjords">
Sorry, auch wenn es jetzt schon 5 Tage her ist, zu jQuery, was ich jetzt mit $(document).on('load') gelöst habe. Wie funktioniert es dann bei der einfachen function? Weil das Img was per Ajax hinzugefügt wird, existiert ja eigentlich nicht. Der onclick wird dennoch ausgeführt(hinzugefügten IMG) aber es wird immer das letzte existierende img aufgerufen "currentSlide(6)"
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
<img onclick="currentSlide(7)" class="slideshow-demo slideshow-cursor ff-test-image" alt="Mountains and fjords">
In dem Moment, in dem das neue img-Element vom Browser gerendert wird, werden natürlich auch die jeweiligen Attribute interpretiert und in diesem Fall, die Funktion currentSlide an das onclick-Property des img-Elements gebunden. Ob die Funktion überhaupt existiert, wird erst zur Laufzeit auffällig, wenn man auf das Bild klickt. Da die Funktion jedoch bereits definiert ist, wird es kein Problem diesbezüglich geben.
(...) aber es wird immer das letzte existierende img aufgerufen "currentSlide(6)"
Dazu kann ich nichts sagen. Die 7 sollte auf jeden Fall an die Funktion übergeben werden. In dieser könntest du n eigentlich gleich durchreichen, eine neue explizite Variable brauchst du gar nicht. Um nun noch einen besseren Bezeichner zu haben, wäre dies ausreichend:
function currentSlide(slideIndex) {
showSlides(slideIndex);
}
Was in showSlides nun durchgeführt wird, müsstest du überprüfen.
OK, ich habe es mal so gelöst
Attribute beim img hinzugefügt, dadurch wurde currentSlide geschichte.
$(document).on('click', '.slideshow-demo', function () {
var slide = $(this).parents('.slideshow-column').attr('data-slideshow');
slideIndex = slide++;
slideIndex = slide++;
showSlides(slideIndex);
});
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("slideshow-mySlides");
var dots = document.getElementsByClassName("slideshow-demo");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" slideshow-active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " slideshow-active";
}
Doch, tag ist vorhanden, davor noch $(document).ready...
Du versuchst deine Event-Handler zu registrieren bevor die tatsächlichen Elemente im Dokument existieren. Zum Zeitpunkt der Ausführung ist noch keines der Elemente vorhanden, somit kann auch nichts registriert werden.
Anstatt die Event-Handler direkt am Element zu erzeugen:
$('.title-edit').click(function () {
...
kannst du das Click-Ereignis an ein höher liegendes Element delegieren, dass zum Zeitpunkt der Ausführung bereits existiert (Event-Delegation):
$(document).on('click', '.title-edit', function () {
...
Bei so einer Lösung ist allerdings mit zu beachten, dass das Elternelement, welches künftig die Events abfängt, eine größere Klickfläche zur Verfügung stellen könnte, die nicht einmal eines der Elemente enthalten muss. Das tatsächlich geklickte Element holt man sich dann am besten über das Event-Objekt.
$(document).on("click", ".title-edit", function (evt) {
let element = evt.target;
// ...
});
Danke, dass habe ich bemerkt.
Ich habe jetzt eine frage noch. Die Inputs die ich mit php(ajax) erzeuge, werden mittels button more ein ausgeblendet.
Da ich jetzt das script etwas umschreiben musste sieht das jetzt so aus
$(document).on('click', '.editor_more', function () {
$(this).next().toggle(); // header_text_horizontal
$(this).next().next().toggle(); // header_text_vertical
$(this).next().next().next().toggle(); // header_text_reset
$(this).parents('.title-editor-style').next().nextUntil('.image-editor-position').toggle();
});
Das funktioniert ja auch, nur ist es blöd wenn jetzt zum Beispiel irgendwo zwischen drinen ein weiteres div hinzukommt, was garnicht ausgeblendet werden soll. Ich müsste dann immer das Script mit ein weiteren next oder prev umändern.
Gibt es auch hierfür eine Lösung?
Die 2 gingen leider nicht
$(this).next('.header_text_horizontal').toggle();
$(this).next('.header_text_vertical').toggle();
$(this).next('.header_text_reset').toggle();
$(this).nextUntil('.header_text_horizontal').toggle();
$(this).nextUntil('.header_text_vertical').toggle();
$(this).nextUntil('.header_text_reset').toggle();
Wie sollen wir das beurteilen ohne deinen Code zu sehen? Bitte poste zumindest den relevanten HTML-Abschnitt und dein JavaScript.
Sry, da war ja was
Ajax PHP Datei
if (!$title->execute()) {
echo "Fehler";
} else {
$name = array();
while ($data = $title->fetch()) {
$name[] = $data['name'];
}
$count = count($name);
for ($i=0; $i < $count; $i++) {
echo $name[$i];
echo ' <input type="number" id="image_horizontal_edit1" value="" placeholder="Horizontal">';
echo ' <input type="number" id="image_vertical_edit1" value="" placeholder="Vertical"><br><br>';
echo ' <input type="number" id="image_zoom_edit1" value="" placeholder="Zoom"><br><br>';
/* ===c Bilder Laden === */
$('#load_image').click( function (event) {
event.preventDefault();
$.ajax({
type: 'POST',
url: 'ajax/home.php',
data: $(this).serialize(),
success: function (title_image) {
$('#title_image').html(title_image);
}
});
echo ' <a id="editor_more1" class="btn btn-info editor_more"><span class="glyphicon glyphicon-plus"></span> MORE</a>';
<button id="load_image" type="submit" name="load_image" class="btn btn-primary start"> <span><i class="glyphicon glyphicon-picture"></i>Bilder Laden</span> </button>
<div id="title_image" class="margin">
<!-- DIVS vom PHP AJAX -->
</div>
Leider kommt funktioniert die abfrage nicht
$('.editor_more').on('click',function () {
$('#testss').html("test");
});
Existiert denn ein Element mit der ID "testss"? In deinem HTML sehe ich keins.
Werden dir JS-Fehler in der Browserkonsole angezeigt?
testss existiert im HTML, <p></p>
In der konsole wird nichts ausgegeben.
Die Bilder, buttons, inputs werden zwar geladen und angezeigt aber führen keinen event aus
Sry, nur ich weiß jetzt echt nicht mehr weiter. Ich hab nocheinmal dutzend mal mit Klassen probiert. Verschiedene IDs mit fortlaufende zahlen (for-schleife.). Ich habe nur 1 einziges Bild heruntergeladen und nochmals alles von vorne. Ich steh echt vor einem fragezeichen.
Ich habe jetzt nocheinmal nur das nötigste hochgeladen
HTML: https://pastebin.com/4Z4cGz0s
PHP Ajax: https://pastebin.com/n7YEKWhX
Komplettes HTML https://pastebin.com/sapiVhe4