Forum: PC Hard- und Software html und javascript: wie realisiere ich einen schnelleren Slider


von klaus (Gast)


Lesenswert?

Hi

ich lerne gerade webapp development und bin neu in dem Bereich.
Ich versuche gerade einen Slider zu relaisiren. Aber der hackelt und ist 
recht langsam.

Liegt es an Javascript?
Oder sollte ich event handler benutzen?
Oder was anderes als oninput?

Vielen Dank,

<FORM action="/red.cgi" method="post" id="form1">
<input type="range" name="POT" min="0" max="100" value="{{ red_value }}" 
class="slider" id="myRange">
<p>Power: <span id="demo"></span>%</p><br>
</P>
</FORM>

<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;

slider.oninput = function() {
  document.getElementById("form1").submit();
  output.innerHTML = this.value;
}
</script>

von Marty (Gast)


Lesenswert?

Der Slider ansich ist so schon OK.
Das Problem, was Du Dir da eingebaut hast, ist das hier:
1
slider.oninput = function() {
2
  document.getElementById("form1").submit();

So wird bei jeder Änderung das Formular übertragen, was natürlich nicht 
besonders zielführend ist, da Du beim verschieben von 0 auf 100 auch 100 
Requests an Deinen Server sendest.

Besser wäre, wenn Du das mit einem Timeout versiehst oder für den Submit 
ein anderes Event verwendest...

von klaus (Gast)


Lesenswert?

Hi
>> da Du beim verschieben von 0 auf 100 auch 100 Requests an Deinen Server sendest

ich baue ja einen webapp was nur auf mein PC läuft. Und es ist eine 
Anförderung dass zwar nicht alle 100 Werte übertragen werden aber 
zumindest einige.

gehts auch dass ich jedes n'te Wert rausschicke?

Danke?

von klaus (Gast)


Lesenswert?

Ich sehe dass nur der letzte Wert submitted wird, keins der 
Zwichenwerte.

von Kenny (Gast)


Lesenswert?

klaus schrieb:
> Ich sehe dass nur der letzte Wert submitted wird, keins der
> Zwichenwerte.

Dann mach mal Deine Browserkonsole (F12) auf und schau dir an, wann das 
Formular submitted wird.

Entweder machst Du asynchron mit ajax/jquery oder dem bereits 
vorgeschlagenen Timeout. Alternativ kannst Du natürlich in Deinem 
EventHandler auch einen Zähler einbauen. Was hindert Dich?

klaus schrieb:
> ich baue ja einen webapp was nur auf mein PC läuft.

Dann ist Dein PC halt in diesem Moment der Server. Spielt ja keine 
Rolle. Es wird ein HTTP Request gesendet, die Anwendung muss reagieren 
und die Daten verarbeiten und dann gibt's eine Antwort an den Browser. 
Das kostet nunmal Zeit und darum wirds holprig...

von vn nn (Gast)


Lesenswert?

'oninput' triggert bei jeder Bewegung des Sliders und löst damit einen 
HTTP-Request aus (auch, wenn der nur lokal ist, benötigt er doch Zeit).
'onchange' triggert er beim loslassen des Sliders einmalig.
1
<!DOCTYPE html>
2
<html>
3
  <body>
4
    <h1>This slider fires an event on each change using 'oninput':</h1>
5
    <input type="range" class="slider" id="inputOnInput" value="0" min="0" max="100">
6
    <script>
7
      document.getElementById("inputOnInput").oninput = function() {     alert("'oninput' event fired.");
8
      };
9
    </script>
10
    <p>
11
        <code>
12
          &lt;input type="range" class="slider" id="inputOnInput" value="0" min="0" max="100"&gt;
13
          &lt;script&gt;
14
              document.getElementById("inputOnInput").oninput = function() {
15
                  alert("'oninput' event fired.");
16
              };
17
          &lt;/script&gt;
18
        </code>
19
    </p>
20
21
    <h1>This slider fires an event on each change using 'onchange':</h1>
22
    <input type="range" class="slider" id="inputOnChange" value="0" min="0" max="100">
23
    <script>
24
      document.getElementById("inputOnChange").onchange = function() {     alert("'onchange' event fired.");
25
      };
26
    </script>
27
    <p>
28
        <code>
29
          &lt;input type="range" class="slider" id="inputOnChange" value="0" min="0" max="100"&gt;
30
          &lt;script&gt;
31
              document.getElementById("inputOnChange").onchange = function() {
32
                  alert("'onchange' event fired.");
33
              };
34
          &lt;/script&gt;
35
        </code>
36
    </p>
37
  </body>
38
</html>

von klaus (Gast)


Lesenswert?

Vielen dank.

Bitte bedenkt dass ich der volle Anfänger bin.

Bevor ich die Lösung von VN nn probiere:
Mein Code sendet den Submit nur einmal. Das Problem ist dass der server 
(python flask) nach dem submit ja die html seite mit dem letzten wert 
zurück sendet, und der slider ist nicht mehr unterm mouse ;-)

wtf
jetzt probiere ich mal das was vn nn freundlicher weise geschickt hat 
;-)

von klaus (Gast)


Lesenswert?

Hi
Also wenn ich es richtig sehe, macht ja vn nn nichts anderes.

Wie löse ich das Problem, dass nach der ersten Übertragung der server 
die html Seite zurück schickt, und mit diesem refresh mein mouse den 
slider nicht mehr selektiert?

von Dirk K. (merciless)


Lesenswert?

Muss der Wert denn sofort übermittelt werden?
slider.oninput wird bei jeder Bewegung am Slider
aufgerufen, jede minimale Änderung submitted die
Form (du siehst das wahrscheinlich nur einmal,
weil der Browser noch die Rückantwort des Servers
verarbeiten muss). Ändere doch mal
1
document.getElementById("form1").submit();
in
1
console.log(this.value);

Ich würde den Wert entweder dediziert übermitteln
(separater Send-Button oder sowas) oder erst mit
einem Zeitversatz nach der letzten Änderung am
Slider.

merciless

von Mathias (Gast)


Lesenswert?

klaus schrieb:
> Wie löse ich das Problem, dass nach der ersten Übertragung der server
> die html Seite zurück schickt, und mit diesem refresh mein mouse den
> slider nicht mehr selektiert?

Mit Ajax. Wenn du nur moderne Browser unterstützen musst, reicht fetch. 
Wenn du auch IE9 oder so unterstützen willst, dann nimm am besten ne 
Library wie jQuery.

https://caniuse.com/#feat=fetch
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
z.B. (ungetestet)
1
slider.oninput = function() {
2
  fetch("/red.cgi",
3
   {method: "POST",
4
    body: JSON.stringify({name: this.value})}
5
  ).then(function(result){
6
    output.innerHTML = result
7
  });
8
}

von vn nn (Gast)


Lesenswert?

klaus schrieb:
> Bevor ich die Lösung von VN nn probiere:

Es ist keine Lösung, es ist eine Demo die dir den Unterschied zwischen 
onchange und oninput zeigt.

klaus schrieb:
> Mein Code sendet den Submit nur einmal.

Natürlich, weil du danach die Seite neu lädst. Ändert auch nix daran, 
dass 'oninput' bereits während der Bewegung triggert, und das ist für 
deine Anwendung halt zu früh.

klaus schrieb:
> Also wenn ich es richtig sehe, macht ja vn nn nichts anderes.

Hast du es ausprobiert? Hast du es angesehen? Hast du es verstanden?
Es sind zwei Slider, einer arbeitet mit 'oninput' wie du, der andere mit 
'onchange'.

klaus schrieb:
> Wie löse ich das Problem, dass nach der ersten Übertragung der server
> die html Seite zurück schickt, und mit diesem refresh mein mouse den
> slider nicht mehr selektiert?

Nein. Einfach nur nein. Dein Problem ist ganz, ganz was anderes.
Aber ja, du könntest natürlich auch mit AJAX die Daten ohne neu laden 
senden. Aber das löst dein Grundproblem nicht, nämlich dass du nicht 
verstehst was 'oninput' macht.

von vn nn (Gast)


Lesenswert?

Dirk K. schrieb:
> erst mit
> einem Zeitversatz nach der letzten Änderung am
> Slider.

Dafür hat man onchange erfunden.

Mathias schrieb:
> klaus schrieb:
>> Wie löse ich das Problem, dass nach der ersten Übertragung der server
>> die html Seite zurück schickt, und mit diesem refresh mein mouse den
>> slider nicht mehr selektiert?
>
> Mit Ajax.

Ändert nix daran, dass er oninput nicht verstanden hat. Aber ja, an den 
Symptomen herumdoktoren ist immer super.

Mathias schrieb:
> nimm am besten ne
> Library wie jQuery.

Natürlich. Lassen wir ihn jQuery gleich reinziehen ohne jeden Grund. 
Hilft sicher. Vielleicht noch zwei, drei Frameworks?

von klaus (Gast)


Lesenswert?

ja, der wert muss sofort ( alle 200 ms) übermittelt werden.
Kann man es irgendwie verhindern dass ein refresh stat findet?
Meine Flask funtion sieht ungefähr so aus: siehe unten.

"return render_template" refreshed die seite in firefox. Damit wird der 
Wert vom Slider auf den alten Wert zurück gesetzt

@app.route("/red.cgi", methods=['GET', 'POST'])
def red_cgi():
    if request.method == 'POST':
        red = int(request.form.get("RED_VALUE"))
        print("red value " + str(red))
    return render_template('bootloader.html', red_value=red)

von klaus (Gast)


Lesenswert?

vn nn schrieb:

>>Hast du es ausprobiert? Hast du es angesehen?
Ja vielen Dank. Ich habe es verstanden. Aber wie du es schon sagst dass 
löst mein Problem noch nicht.

Was schlägst du mir genau vor? (sorry, ich bin echt ein Anfänger in 
diesem bereich)

von Kenny (Gast)


Lesenswert?

klaus schrieb:
> Wie löse ich das Problem, dass nach der ersten Übertragung der server
> die html Seite zurück schickt, und mit diesem refresh mein mouse den
> slider nicht mehr selektiert?

Also ganz grundsätzlich würde ich Dir empfehlen, dass Du Dir mal die 
Funktionsweise von CGI zu Gemüte führst.

klaus schrieb:
> ich lerne gerade webapp development und bin neu in dem Bereich.

Wenn Du vorn anfangen würdest, stellte sich die Frage nämlich gar nicht.


Zu Deinem Problem:
Da müsstest Du mal ein bisschen ausholen, was dein red.cgi Skript 
eigentlich macht bzw. ob die Ausgabe des Skriptes von der Oberfläche 
irgendwie verwertet wird.

Im Prinzip gibt es mehrere Möglichkeiten. Zwei wären:

1) Wie oben beschrieben, den Request mit einem Timer hinauszögern.
Dabei bewegst Du den Schieberegler und erst wenn sich über eine Zeit X 
(hier 300ms) der Wert nicht mehr verändert hat, werden die Daten 
abgesendet.
1
<form action="/red.cgi" method="post" id="form1">
2
  <input type="range" name="POT" min="0" max="100" value="{{ red_value }}" class="slider" id="myRange">
3
  <p>Power: <span id="demo"></span>%</p>
4
</form>
5
6
<script>
7
  var slider = document.getElementById("myRange");
8
  var output = document.getElementById("demo");
9
  output.innerHTML = slider.value;
10
  var timeout;
11
12
  slider.oninput = function() {
13
    window.clearTimeout(timeout);
14
    output.innerHTML = this.value;
15
    timeout = window.setTimeout( function() {
16
      // Timer abgelaufen. Daten werden übertragen:
17
      document.getElementById("form1").submit();
18
    },300);
19
    
20
  }
21
</script>

Das ändert aber noch nichts an der Tatsache, dass der Browser das 
Formular absendet und anschließend die Ausgabe Deines red.cgi Skriptes 
wieder darstellt.

2) Daher wäre das Absenden des eingestellten Wertes per Ajax wesentlich 
sinnvoller, zum Beispiel mit jQuery, welches Du Dir vorher runterlädst 
und in deinem Webserververzeichnis ablegst.
1
<head>
2
  <script src="jquery-3.4.1.min.js"></script>
3
</head>
4
5
<body>
6
<form id="form1">
7
  <input type="range" name="POT" min="0" max="100" value="{{ red_value }}" class="slider" id="myRange">
8
  <p>Power: <span id="demo"></span>%</p>
9
</form>
10
11
<script>
12
  var slider = document.getElementById("myRange");
13
  var output = document.getElementById("demo");
14
  output.innerHTML = slider.value;
15
16
  slider.oninput = function() {
17
    window.clearTimeout(timeout);
18
    output.innerHTML = this.value;
19
20
    $.ajax({
21
      method: "POST",
22
      url: "red.cgi",
23
      data: { POT: slider.value }
24
    });
25
      
26
    
27
  }
28
</script>
29
</body>

Auch hier solltest Du evtl. das Timeout aus dem anderen Beispiel mit 
einbauen oder eben einen Zähler.

von vn nn (Gast)


Lesenswert?

klaus schrieb:
> Ja vielen Dank. Ich habe es verstanden. Aber wie du es schon sagst dass
> löst mein Problem noch nicht.

Du hast es nicht verstanden, denn genau das habe ich nicht geschrieben.

klaus schrieb:
> ja, der wert muss sofort ( alle 200 ms) übermittelt werden.

Warum kommst du mit der Anforderung erst jetzt her? Was genau möchtest 
du damit erreichen? Wo kommen diese 200ms her?
Salamitaktik hat noch niemanden weitergebracht.

klaus schrieb:
> Kann man es irgendwie verhindern dass ein refresh stat findet?

Mit AJAX z.B.
Aber dafür müsste man erstmal wissen, was du erreichen willst.

Kenny schrieb:
> Daher wäre das Absenden des eingestellten Wertes per Ajax wesentlich
> sinnvoller, zum Beispiel mit jQuery, welches Du Dir vorher runterlädst
> und in deinem Webserververzeichnis ablegst.

Warum sollte er sich für einen einfachen AJAX-Request eine fette, 
überladene jQuery-Library reinziehen?

von Mathias (Gast)


Lesenswert?

Wenn du das Formular absendest, wird die Seite immer neu geladen, das 
ist sicherlich nicht was du willst. Mit Ajax läd man nur ein paar Daten 
nach und muss die Webseite dann mit Javascript so verändern, wie du das 
willst.

Der Server muss dann eben nicht das ganze HTML Template neu ausgeben, 
sondern nur die Nutzdaten, z.B. als JSON Objekt. Ich kenne mich jetzt 0 
mit Flask aus. Probier mal im 'if ... == "POST":' Zweig einfach ein 
"return red". Evtl. klappt dann mein obiges Beispiel schon. Komplexere 
Daten dann aber als JSON ausliefern.

von Mathias (Gast)


Lesenswert?

vn nn schrieb:
> klaus schrieb:
>> ja, der wert muss sofort ( alle 200 ms) übermittelt werden.
>
> Warum kommst du mit der Anforderung erst jetzt her? Was genau möchtest

In seinem zweiten Post schreibt er das doch praktisch schon.


vn nn schrieb:
> Was genau möchtest du damit erreichen?
Ist doch klar, slider bewegt sich => Antwort vom Server wird angezeigt.

vn nn schrieb:
> Wo kommen diese 200ms her?
Die fallen vom Himmel. Ist das relevant, ob das jetzt 200 oder 20 sind? 
Was er wollte ist ab dem zweiten Post ziemlich klar.

...

von klaus (Gast)


Lesenswert?

> Wo kommen diese 200ms her?
ich wil paar LEDs Dimmen. LEDs sollen ganz smooth hoch dimmen wenn ich 
den slider hin und her schiebe.

Liege ich dann richtig dass ich mich mit ajax und json auseinander 
setzen muss um nur Teile der Seite zu refreshen?

von vn nn (Gast)


Lesenswert?

Mathias schrieb:
> In seinem zweiten Post schreibt er das doch praktisch schon.

Ach? Wo?

Mathias schrieb:
> vn nn schrieb:
>> Was genau möchtest du damit erreichen?
> Ist doch klar, slider bewegt sich => Antwort vom Server wird angezeigt.

Tja, nur stellt sich immer noch die Frage, ob das überhaupt notwendig 
ist, oder ob man das auch einfacher lösen könnte.
Aber dass kommt dir natürlich nicht in den Sinn.

Mathias schrieb:
> Die fallen vom Himmel. Ist das relevant, ob das jetzt 200 oder 20 sind?
> Was er wollte ist ab dem zweiten Post ziemlich klar.

Natürlich ist es relevant, und gerade bei einem Anfänger ist nicht 
zwingend sinnvoll, was er sich als Lösungsweg ausgedacht hat.
Wenn er schreibt, was er eigentlich erreichen will, kann man beurteilen 
ob seine Lösung so überhaupt Sinn macht. Siehe auch 
http://catb.org/~esr/faqs/smart-questions.html#symptoms
Aber scheinbar kommt das dir nicht in den Sinn.

von vn nn (Gast)


Lesenswert?

klaus schrieb:
> ich wil paar LEDs Dimmen. LEDs sollen ganz smooth hoch dimmen wenn ich
> den slider hin und her schiebe.
>
> Liege ich dann richtig dass ich mich mit ajax und json auseinander
> setzen muss um nur Teile der Seite zu refreshen?

Wenn sie das tun sollen, während du den Slider bewegst, ja.

Dafür ist natürlich kein fettes jQuery notwendig, sondern ein einfaches 
XMLHttpRequest reicht. fetch() wäre die modernere Variante, wird aber 
nicht von allen Browsern supported, ist also derzeit noch mit Vorsicht 
zu genießen.
https://caniuse.com/#search=XMLHttpRequest
https://caniuse.com/#search=fetch

Auf flask-Seite definierst du ein Ziel mit "methods=['POST']".
Z.B.:
1
@app.route('/dimmLed', methods=['POST'])
2
def signUpUser():
3
    color =  request.form['color']
4
    value = request.form['value']
5
    return json.dumps({'status':'OK','color ':color ,'value ':value })

von Kenny (Gast)


Lesenswert?

vn nn schrieb:
> Warum sollte er sich für einen einfachen AJAX-Request eine fette,
> überladene jQuery-Library reinziehen?

Weil ich mir ganz sicher nicht den Punk gebe und jemandem mit dem 
Kenntnisstand erkläre, wie er XHR requests erzeugt, die parameter 
kodiert und ein JSON objekt mit seinen Parametern übergibt.

Aber das kannst Du ja machen, wenn Du das für zielführender hälst. 
Vielleicht verrät er Dir ja auch noch, in welchen Browsern das alles so 
laufen soll. Dann kannst Du das bei Deinen Ausführungen gleich 
berücksichtigen.

klaus schrieb:
> Liege ich dann richtig dass ich mich mit ajax und json auseinander
> setzen muss um nur Teile der Seite zu refreshen?

Das wäre sinnvoll.

von Vn N. (wefwef_s)


Lesenswert?

Kenny schrieb:
> Weil ich mir ganz sicher nicht den Punk gebe und jemandem mit dem
> Kenntnisstand erkläre, wie er XHR requests erzeugt, die parameter
> kodiert und ein JSON objekt mit seinen Parametern übergibt.
>
> Aber das kannst Du ja machen, wenn Du das für zielführender hälst.
> Vielleicht verrät er Dir ja auch noch, in welchen Browsern das alles so
> laufen soll. Dann kannst Du das bei Deinen Ausführungen gleich
> berücksichtigen.

XMLHttpRequest  ist nun wirklich keine Hexerei. Gibt auch genügend 
Anleitungen und Beispiele dazu.
z.B. 
https://gist.github.com/KentaYamada/2eed4af1f6b2adac5cc7c9063acf8720

Und dann wundern wir uns, dass im Web nur noch Müll existiert, wenn wir 
Anfängern einfach mal pauschal sagen "nimm jQuery, wie es wirklich geht 
kapierst du es sowieso nicht".

von klaus (Gast)


Lesenswert?

Hi Leute

vielen Dank für eure Geduld.

Die Ajax Variante tut den Job für mein inhouse Projekt mehr als genug.

Es gibt nur noch ein kleines Problem, wie kann ich einen delay einbauen?
Aktuell wenn ich 2 Minuten den Slider hin und her bewege, scheint sich 
ein Stau auf zu bauen.
Wie löse ich das?

    $.ajax({
      method: "POST",
      url: "red.cgi",
      data: { POT: slider.value }
    });

von Εrnst B. (ernst)


Lesenswert?

Um bei jquery zu bleiben:

z.B. mit sowas

http://benalman.com/projects/jquery-throttle-debounce-plugin/

da kannst du dann angeben, dass z.B. max. alle 250 msec ein Post an den 
Server geht, auch wenn öfter change-events kommen.



Ach übrigens, wenig bekannt, aber auch vor AJAX gab's da eine 
Möglichkeit mit Post Daten ohne Seiten-Reload zu übermitteln:
Einfach das CGI mit dem HTTP-Status "204 No Content" antworten lassen.
Löst natürlich nicht das throttling-Problem.

: Bearbeitet durch User
von Mathias (Gast)


Lesenswert?

vn nn schrieb:
> Mathias schrieb:
>> In seinem zweiten Post schreibt er das doch praktisch schon.
>
> Ach? Wo?

Da:

klaus schrieb:
> Und es ist eine Anförderung dass zwar nicht alle 100 Werte übertragen werden 
aber zumindest einige.

Aber Mitdenken kommt dir natürlich nicht in den Sinn.

Ab dem zweiten Post war klar, dass sein Ansatz der falsche und AJAX der 
richtige ist und du nicht verstanden hast, was er wollte. Ihm dann 
beibringen zu wollen, dass er onChange nicht verstanden hätte ist auf 
jeden Fall falscher als seine Motivation nicht zu hinterfragen.

Dass ein simples onChange ohne limitierung Probleme bereitet hat er dann 
ja selber rausgefunden, nachdem er die passende (unvollständige) Lösung 
bekommen hat...

von Vn N. (wefwef_s)


Lesenswert?

Mathias schrieb:
> vn nn schrieb:
>> Mathias schrieb:
>>> In seinem zweiten Post schreibt er das doch praktisch schon.
>>
>> Ach? Wo?
>
> Da:
>
> klaus schrieb:
>> Und es ist eine Anförderung dass zwar nicht alle 100 Werte übertragen werden
> aber zumindest einige.
>
> Aber Mitdenken kommt dir natürlich nicht in den Sinn.

Von 200ms lese ich dort nix.

Mathias schrieb:
> Ihm dann
> beibringen zu wollen, dass er onChange nicht verstanden hätte ist auf
> jeden Fall falscher als seine Motivation nicht zu hinterfragen.

Nachdem er ziemlich lang der Meinung war, dass oninput (nicht onchange, 
das hat er nie verwendet) nur ein einziges Mal feuert, hat er es 
offensichtlich auch nicht verstanden.
Was allerdings auch nicht schlimm ist, immerhin ist er ja Anfänger. Dass 
du als Besserwisser 'onchange' und 'oninput' nicht auseinander halten 
kannst, ist hingegen mehr als peinlich.

Mathias schrieb:
> Dass ein simples onChange ohne limitierung Probleme bereitet hat er dann
> ja selber rausgefunden

Ich wage mal zu behaupten, dass onchange keine Limitierung braucht.
Lern, die beiden auseinander zu halten.

Εrnst B. schrieb:
> Um bei jquery zu bleiben:
>
> z.B. mit sowas
>
> http://benalman.com/projects/jquery-throttle-debounce-plugin/

Funktioniert btw auch ohne jQuery. Just for the record.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.