Don P: Eigene DOM-Events feuern und verarbeiten

Hallo,

Mich beschäftigt ein ganz ähnliches Problem wie dieses, d.h. ich möchte, dass bestimmte Bedienelemente auf einen Event reagieren, der von sonstwo gefeuert wird, ohne dass das feuernde Element überhaupt von der Existenz der reagierenden Elemente "weiß".

Eine gute Demo für viele Arten von Events findet man hier, im dortigen Test 10 wird auch ein selbstdefinierter (custom) Event gefeuert, Code siehe unten.

Das Problem dabei ist, dass man den Event direkt auf das gewünschte Zielelement feuern muss. Aber wenn dieses bekannt ist und angegeben werden *muss*, dann kann ich ja komplett auf so einen Event verzichten und die gewünschte Aktion direkt starten, z.B. das Zielelement auf disabled setzen oder was immer. Das ist es aber gerade, was ich vermeiden will. Die Zielelemente sollen einfach auf den Event "lauschen" und ggf. darauf reagieren.

Ein funktionierender Code aus der genannten Demo:

	<div id="test10">  
		<h2>10) Fire custom event on demand</h2>  
  
		<script type="text/javascript">  
[code lang=javascript]			function onTest10ButtonPoked(evt) {  
				//make second button listen for custom event:  
				var btn = document.getElementById("test10_2");  
				btn.addEventListener("thisisnotarealevent",onTest10CustomEventFired,false);  
  
				var newEvt = document.createEvent("Events");  
				newEvt.initEvent("thisisnotarealevent",true,true);  
  
				btn.dispatchEvent(newEvt); // <-- hier wird auf's Zielelement gefeuert  
			}  
			function onTest10CustomEventFired(evt) {  
				output("custom 'thisisnotarealevent' event fired; test #10 passed.");  
				showProps(evt);  
			}  
		</script>  
  

~~~		<p>The second button below listens for a custom "thisisnotarealevent" event. The first button creates a custom event of that type and dispatches it to the second.</p>  
		<p>  
  
			<button id="test10\_1" onclick="onTest10ButtonPoked(event);">click to fire custom event</button>  
			<button id="test10\_2">handles "thisisnotarealevent"</button>  
		</p>  
	</div>  
[/code]  
  
Wie soll man nun aber den Event feuern, wenn das Zielelement nicht bekannt ist? Man kann ihm einen Eventlistener wie im obigen Beispiel zuweisen, aber es reagiert nicht, wenn man statt btn.dispatchEvent(newEvt); z.B. einfach `document.body.dispatchEvent(newEvt);`{:.language-javascript} schreibt, um den Event zu feuern.  
  
In [einem anderen Tutorial](http://www.howtocreate.co.uk/tutorials/javascript/domevents) steht zum Thema "custom events":  
Zitat:  
"Fake event objects are created using the document.createEvent method [...]. They are then prepared [...] and finally they are then fired on the desired target element using the element.dispatchEvent method."  
  
Also wieder "fired on the desired target element" :-(. Wie gesagt, wenn man das gewünschte target element kennt, dann braucht man doch keinen solchen Event zu feuern, sondern kann die Aktion gleich direkt ausführen.  
  
DOM-Event-mäßig bin ich leider überhaupt nicht bewandert, habe bis jetzt immer nur mit den normalen onclick-, onchange- usw. Attribut-Events gearbeitet.  
  
Kann mir da jemand weiterhelfen?  
  
Gruß, Don P  

  1. Hi,

    Mich beschäftigt ein ganz ähnliches Problem wie dieses, d.h. ich möchte, dass bestimmte Bedienelemente auf einen Event reagieren, der von sonstwo gefeuert wird, ohne dass das feuernde Element überhaupt von der Existenz der reagierenden Elemente "weiß".

    Ich kann den Sinn und Zweck dahinter nicht ganz erkennen.

    Wie soll man nun aber den Event feuern, wenn das Zielelement nicht bekannt ist?

    Wieso ist es nicht bekannt, bzw. soll nicht bekannt sein?

    Wie gesagt, wenn man das gewünschte target element kennt, dann braucht man doch keinen solchen Event zu feuern, sondern kann die Aktion gleich direkt ausführen.

    Und wenn man das Element "nicht kennt", wieso will man dann überhaupt irgendwas mit ihm machen?

    Kann mir da jemand weiterhelfen?

    Kannst du mal ein praxisnahes Anwendungsbeispiel konstruieren, auf was für einem Element du worauf reagieren willst, und wer dabei wen nicht kennen soll und warum?

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    1. Hallo,

      Kannst du mal ein praxisnahes Anwendungsbeispiel konstruieren, auf was für einem Element du worauf reagieren willst, und wer dabei wen nicht kennen soll und warum?

      Ok, ich versuch's mal:

      Es gibt ein Eingabefeld für Text und eine Select-Box, beide sind anfangs leer. Dann gibt es noch jede Menge Klickbuttons und sonstige Divs etc., die dazu dienen, gewisse Einstellungen zu machen.

      Solange nichts in das Eingabefeld eingeben wird, macht es keinen Sinn, die Selectbox zu benutzen, weil deren Optionen nur mit dem Text des Eingabefelds gefüllt werden können, was dann die Erzeugung von weiteren Objekten zur Folge hat, die man mit den anderen Klickbuttons etc. konfigurieren kann.

      Alle Elemente außer dem Eingabefeld müssen also anfangs deaktiviert sein. Das Eingabefeld hat einen onchange-Handler, der dafür sorgt, dass jede neue Eingabe als Option im Select-Feld landet. Dieses hat ebenfalls Methoden die weiters notwendigen Objekte zu erzeugen. Aber weder die Handler des Eingabefelds noch die des Selectfelds "wissen" von der Existenz der andern Klickbuttons etc., die aber ebenfalls aktiviert werden müssen, sobald die mit ihnen zu konfigurierenden Objekte erzeugt sind.

      Auch diese Objekte "wissen" nicht, durch welche Buttons sie konfiguriert werden. Die Buttons und sonstigen Bedienelemente wissen aber von den Objekten, und setzen einfach deren Eigenschaften entsprechend, wenn sie z.B. geklickt werden.

      Wenn man ein Objekt über einen Button wieder entfernt, gibt es einen Eintrag weiger im Select-Feld, und wenn dieses ganz leer wird, müssen wieder sämtliche anderen Bedienelemente für die Objekte deaktiviert werden, weil sie ja nicht mehr existieren. Aber wie soll ein Handler des Selectfelds das bewerkstelligen, wenn es entsprechenden Buttons etc. nicht "kennt"?

      Lösung: Es könnte einfach blind einen Event in die Welt feuern, auf den alle Buttons hören, die dafür konfiguriert sind.

      Auch bestimmte andere Programmzustände verlangen das vorübergehende Deaktivieren bzw. Ein/Ausblenden von Bedienelementen, ohne dass die einzelne Routine (in der der Zustand auftritt) wissen muss, welche das genau sind.

      Ist es jetzt deutlicher?

      Gruß, Don P

    2. Hallo,

      Im Grunde geht es darum, ein modular aufgebautes Programm zu erstellen, bei dem die eigentlich arbeitenden Teile weitgehend von den Bedien- und Anzeigeelementen getrennt sind.

      Beispiel Taschenrechner: Die Recheneinheit hat etwas ausgerechnet und das Ergebnis steht in einer Eigenschaft namens "ergebnis". Natürlich soll das Ergebnis auch angezeigt werden. Anstatt jetzt im Rechnermodul zu notieren

      anzeigeModul.ergebnisElement.value = this.ergebnis;  
      
      

      löst man nur einen Event namens "Ergebnis_fertig" aus. Das Rechnermodul kennt nämlich das "anzeigemodul" gar nicht, und weiß natürlich auch nicht, dass es dort ein "ergebniselement" (DOM-Element) gibt.

      Sondern es funktioniert umgekehrt: Das "ergebniselement" im Anzeigemodul holt einfach bei Bedarf das Ergebnis vom Rechnermodul ab, sobald es zur Verfügung steht, d.h. wenn der Event gefeuert ist. Der entsprechende Eventhandler weiß von der Eigenschaft "rechnermodul.ergebnis" und führt einfach

      this.value = rechnermodul.ergebnis;

      aus.

      Gruß, Don P

      1. Hi,

        Im Grunde geht es darum, ein modular aufgebautes Programm zu erstellen, bei dem die eigentlich arbeitenden Teile weitgehend von den Bedien- und Anzeigeelementen getrennt sind.

        "Weitgehend" sollte das Stichwort sein - nicht *zu* weit.

        Beispiel Taschenrechner: Die Recheneinheit hat etwas ausgerechnet und das Ergebnis steht in einer Eigenschaft namens "ergebnis". Natürlich soll das Ergebnis auch angezeigt werden. Anstatt jetzt im Rechnermodul zu notieren

        anzeigeModul.ergebnisElement.value = this.ergebnis;

        
        > löst man nur einen Event namens "Ergebnis\_fertig" aus.  
          
        Aber wenn es den Event einfach nur in die Luft bläst, ohne dass ihn irgend jemand zur Kenntnis nimmt, hat keiner was davon.  
          
        Das Anzeigemodul muss sich auch "zuständig" fühlen - also kommst du m.E. nicht darum herum, die beiden miteinander bekannt zu machen.  
          
        Bleiben wir beim einfachen Taschenrechner-Beispiel:  
        Beim erzeugen eines neuen Taschenrechner-Objektes kannst du doch eine Methode eines konkreten Anzeigemodul-Objektes per Referenz übergeben - diese Methode ist (später, immer wieder) aufzurufen, wenn das Taschenrechner-Objekt etwas ausgerechnet hat. Dabei ist dieses Ergebnis als Parameter zu übergeben.  
          
        Das sollte doch ausreichend flexibel sein. Das Anzeigemodul kann aus was immer es möchte bestehen, kann mit dem Ergebnis machen, was es möchte - als Text anzeigen, eine Grafik erstellen, in ein Cookie speichern, etc.  
        \*Alles\*, was den Taschenrechner von ihm interessiert ist, dass ihm eine Methode benannt wurde, der er sein Ergebnis zu übergeben hat, fertig.  
          
        
        > Das Rechnermodul kennt nämlich das "anzeigemodul" gar nicht, und weiß natürlich auch nicht, dass es dort ein "ergebniselement" (DOM-Element) gibt.  
          
        Das "Ergebniselement" interessiert den Taschenrechner überhaupt nicht.  
        Er hat über eine definierte Schnittstelle (Methode einer konkreten Objektinstanz) sein Ergebnis übergeben - alles, was danach mit diesem gemacht wird, ist für ihn uninteressant.  
          
        
        > Sondern es funktioniert umgekehrt: Das "ergebniselement" im Anzeigemodul holt einfach bei Bedarf das Ergebnis vom Rechnermodul ab, sobald es zur Verfügung steht, d.h. wenn der Event gefeuert ist.  
          
        Warum soll das Anzeigemodul irgendetwas "abholen"?  
        Das Anzeigemodul sehe ich hier als "Empfänger" - es bekommt etwas übergeben, und führt damit seinen Teil der Aufgabe, nämlich es irgendwo irgendwie darzustellen, aus.  
          
        
        > Der entsprechende Eventhandler weiß von der Eigenschaft "rechnermodul.ergebnis" und führt einfach  
        > `this.value = rechnermodul.ergebnis;`{:.language-javascript}  
        > aus.  
          
        Wenn du "Eventhandler" hier durch Methode des Anzeigemoduls ersetzt, dann "fehlt" doch eigentlich gar nichts mehr.  
          
          
        Das ist im Rahmen von OO alles gut abbildbar, wenn man die Elemente in dem minimalen Rahmen "miteinander bekannt macht", den ich oben skizziert habe.  
        Das Anzeigemodul braucht noch nicht mal unbedingt das Taschenrechner-Objekt zu kennen; es könnte auch die Ergebnisse mehrerer Taschenrechner darstellen, wenn das gewünscht wäre.  
        Lediglich der Taschenrechner ist hier der jenige, der ein Anzeigemodul kennen "muss" - er ist der jenige, der etwas berechnet hat, das er jetzt irgendwie "loswerden" möchte; damit sich jemand anderes um die Darstellung/Auswertung/Speicherung/sonstwas kümmert.  
          
          
        Es geht hier im Grunde lediglich um Interaktion/Datenaustausch zwischen Objekten.  
        Eine Notwendigkeit, das über "Events" zu realisieren, sehe ich aber nicht.  
          
        Im DOM \*hast\* du eine Beziehung zwischen Elementen - sie sind Vor- oder Nachfahren von anderen; das ist in dem Umfeld das Maß, in dem sich die Elemente "kennen". Und zwischen denen können dann Events auf- und absteigen, bis sich irgend jemand in der Kette für zuständig befindet.  
          
        Diese Beziehung zwischen Elementen, die im DOM nahezu "natürlich" vorhanden ist, hast du beim Taschenrechner/Anzeigemodul erst mal nicht - also musst du sie irgendwie herstellen. Und genau dagegen scheinst du dich im Moment ein bisschen zu sträuben, und anzunehmen, dass "Events" dir diese Herstellung eines Bezugs zwischen den Objekten abnehmen würden oder könnten - tun sie m.E. aber nicht.  
          
        MfG ChrisB  
          
        
        -- 
        Light travels faster than sound - that's why most people appear bright until you hear them speak.
        
        1. Hallo,

          Das Anzeigemodul muss sich auch "zuständig" fühlen - also kommst du m.E. nicht darum herum, die beiden miteinander bekannt zu machen.

          Ja, leider. Deshalb bin ich eben auf den Gedanken gekommen, dass es doch eigentlich ausreichen müsste, wenn einer den anderen kennt, und sich nicht unbedingt beide gegenseitig kennen müssen.

          Wenn z.B. viele Leute Briefe schreiben, dann reicht es völlig, wenn die Briefe durch die Post aus den Briefkästen eingesammelt und ausgeliefert werden. Das Einwefen eines Briefes ist ein Event, und der Briefkasten des Empfängers, wo der Brief schließlich landet, ist sein persönlicher Eventhandler. Der Brief des Nachbarn landet dagegen bei dessen Eventhandler. Dafür sorgt der Event-Mechanismus ganz von selbst.

          Der Absender muss den Brief nicht persönlich im Kasten des Empfängers deponieren, sondern wirft ihn einfach in den nächstbesten von der Post. Dabei ist es oft ganz unerheblich, wer den Brief gesendet hat, z.B. bei einer geheimen Breifwahl. Wichtig ist nur, dass entsprechend darauf reagiert wird.

          Bleiben wir beim einfachen Taschenrechner-Beispiel:
          Beim erzeugen eines neuen Taschenrechner-Objektes kannst du doch eine Methode eines konkreten Anzeigemodul-Objektes per Referenz übergeben

          Das ist eben nicht immer einfach. Während der Rechner noch rechnet, will er z.B. keine weiteren Eingaben engegennehmen, also müssen alle Bedienelemente des Eingabemoduls inzwischen deaktiviert sein.
          Die Ergebnistaste zum Starten der Berechnung müsste zunächst für diese Deaktivierung sorgen, und das Anzeigemodul müsste dann in der Anzeigemethode alle diese Bedienelemente wieder aktivieren. Also muss man alle entsprechenden Elemente in einer Art Liste bereithalten und jedes Mal durchlaufen, bevor etwas ausgerechnet wird und auch nachher.

          Wenn man nun statt dessen jedem betreffenden Bedienelement einen Event mit sprechendem Namen zuordnet, z.B. "calculation" (=es wird gerade gerechnet) und einen weiteren wie "inputReady" (=es darf eingegeben werden), dann können diese sich selbst aktivieren/deaktivieren, und die Anzeigemethode muss keine Liste dieser Elemente bereithalten oder durchlaufen, sondern lediglich Events vom entsprechenden Typ feuern. Das Durchlaufen geschieht quasi von selbst durch den Event-Mechanismus.

          Warum soll das Anzeigemodul irgendetwas "abholen"?

          Weil der Befehl zum Anzeigen manchmal auch gar nicht vom Rechnermodul kommt, sondern von einem anderen, welches wiederum nichts vom Rechnermodul weiß. Also kann es auch nicht das Ergebnis des Rechners an die Schnittstelle im Anzeigemodul übergeben, lediglich das Anzeigemodul muss wissen, wo es das Anzuzeigende Ergebnis findet (im Rechner).

          Gruß, Don P

          1. Hi,

            Ja, leider. Deshalb bin ich eben auf den Gedanken gekommen, dass es doch eigentlich ausreichen müsste, wenn einer den anderen kennt, und sich nicht unbedingt beide gegenseitig kennen müssen.

            Tut's ja auch, wenn nur der eine vom anderen was will.

            Der Absender muss den Brief nicht persönlich im Kasten des Empfängers deponieren, sondern wirft ihn einfach in den nächstbesten von der Post.

            Das ändert aber noch nichts daran, dass der Absender den Empfänger "kennen" muss - denn wenn du dessen Namen und Adresse nicht auf den Umschlag schreibst, dann wird die gute alte Post Schwierigkeiten haben, ihn zuzustellen.

            Dabei ist es oft ganz unerheblich, wer den Brief gesendet hat, z.B. bei einer geheimen Breifwahl. Wichtig ist nur, dass entsprechend darauf reagiert wird.

            Gut, also ein Event newLetterRecieved tritt ein - und zwar beim Empfänger, bzw. dessen Briefkasten (ersterer "kennt" zweiteren hoffentlich).
            Der Handler für diesen Event wäre aber noch wie vor bei Empfänger bzw. Briefkasten zu definieren.

            Nehmen wir an, die Methode Empfaenger.checkYourMail wäre dafür aufzurufen.
            Wenn es keinen Event gibt, den wir feuern könnten, dann müssen wir sie beim einfliefern des Briefes halt selber aufrufen.
            Ob das jetzt du als Absender des Briefes, oder der Postbote als Zusteller macht, ist unerheblich.
            Auf jeden Fall muss jemand die Instanz Empfaenger kennen. Denn wenn nicht, und wir würden einfach einen Event everybodyCheckYourMail feuern - dann würden alle potentiellen Empfänger zum Briefkasten rennen (also jeder, der einen Briefkasten hat) - und alle bis auf den einen, der tatsächlich gerade einen Brief bekommen hat, würden dies umsonst tun.

            Bleiben wir beim einfachen Taschenrechner-Beispiel:
            [...]
            Das ist eben nicht immer einfach. Während der Rechner noch rechnet, will er z.B. keine weiteren Eingaben engegennehmen, also müssen alle Bedienelemente des Eingabemoduls inzwischen deaktiviert sein.

            Sie müssen entweder beim Rechner anfragen, ob er schon wieder bereit ist, neue Eingaben anzunehmen; oder der Rechner muss ihnen Bescheid sagen, dass er es jetzt wieder ist.

            Die Ergebnistaste zum Starten der Berechnung müsste zunächst für diese Deaktivierung sorgen, und das Anzeigemodul müsste dann in der Anzeigemethode alle diese Bedienelemente wieder aktivieren. Also muss man alle entsprechenden Elemente in einer Art Liste bereithalten und jedes Mal durchlaufen, bevor etwas ausgerechnet wird und auch nachher.

            Möglich, ja.

            Wenn man nun statt dessen jedem betreffenden Bedienelement einen Event mit sprechendem Namen zuordnet, z.B. "calculation" (=es wird gerade gerechnet)

            Der wäre auf dem Bedienelement m.E. fehl am Platze - das Taschenrechner-Objekt selber ist es, das Berechnungen durchführt.

            Analog zu einem Formular in HTML - die einzelnen Bedienelemente mögen auf sie selber betreffende Events wie click reagieren - auf das Abschicken des ganzen (Event submit) reagiert aber das Formular selber.

            und einen weiteren wie "inputReady" (=es darf eingegeben werden), dann können diese sich selbst aktivieren/deaktivieren,

            Nein, können sie nicht.
            Sie müssen vom Taschenrechner "benachrichtigt" werden, wenn dieser mit der Berechnung fertig ist.

            und die Anzeigemethode muss keine Liste dieser Elemente bereithalten oder durchlaufen, sondern lediglich Events vom entsprechenden Typ feuern. Das Durchlaufen geschieht quasi von selbst durch den Event-Mechanismus.

            Und woher wissen jetzt "alle" vorhandenen Bedienelemente (die ggf. zu ganz anderen Taschenrechner-Objekten gehören), ob sie sich von diesem "Event", der einfach ziellos in die Gegend gefeuert wird, angesprochen fühlen sollen oder nicht?
            Dazu müssten sie selber wieder wissen, zu welchem Objekt sie eigentlich gehören.

            Darum, die Elemente, die ihre Zustände gegenseitig bedingen sollen, einander auch irgendwie "bekannt" zu machen, kommst du m.E. nicht herum. Das ist aber auch im OO-Umfeld gang und gäbe. Du scheinst aber anzunehmen, ein Event-Modell wäre eine "Wunderwaffe", die einem das abnimmt?
            Wenn du sowas haben willst, musst du es m.E. selbst implementieren.

            Warum soll das Anzeigemodul irgendetwas "abholen"?

            Weil der Befehl zum Anzeigen manchmal auch gar nicht vom Rechnermodul kommt, sondern von einem anderen, welches wiederum nichts vom Rechnermodul weiß. Also kann es auch nicht das Ergebnis des Rechners an die Schnittstelle im Anzeigemodul übergeben, lediglich das Anzeigemodul muss wissen, wo es das Anzuzeigende Ergebnis findet (im Rechner).

            Damit widersprichst du dir selber - du sagst doch gerade, dass das Anzeigemodul die berechneten Ergebnisse mehrerer Rechner anzeigen können soll (nacheinander). Dann aber ist der einzig logische Weg, dass ein Taschenrechner-Objekt selber aktiv wird, und dem Anzeigemodul Bescheid gibt, "hey, ich hab hier was für dich zum anzeigen".

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
            1. Hallo,

              Der Absender muss den Brief nicht persönlich im Kasten des Empfängers deponieren, sondern wirft ihn einfach in den nächstbesten von der Post.

              Das ändert aber noch nichts daran, dass der Absender den Empfänger "kennen" muss - denn wenn du dessen Namen und Adresse nicht auf den Umschlag schreibst, dann wird die gute alte Post Schwierigkeiten haben, ihn zuzustellen.

              Nicht unbedingt. Wenn ich nur draufschreibe "An den deutschen Bundestag", dann kommt der Brief möglicherweise trotzdem an, selbst wenn ich glaube, dass der vielleicht noch in Bonn tagt.

              Gut, also ein Event newLetterRecieved tritt ein - und zwar beim Empfänger, bzw. dessen Briefkasten (ersterer "kennt" zweiteren hoffentlich).

              Der Empfänger den Briefkasten? Ja, letzterer ist ja eine Methode von ersterem (sein Eventhandler).

              Der Handler für diesen Event wäre aber noch wie vor bei Empfänger bzw. Briefkasten zu definieren.

              Das ist richtig. Er muss einmalig für jeden Empfänger hardcodiert werden bzw. mindestens in einer Schleife zugewiesen werden. Das kann beim initialisieren eines Moduls geschehen, wo noch nichts zeitkritisches passiert.

              Nehmen wir an, die Methode Empfaenger.checkYourMail wäre dafür aufzurufen.
              Wenn es keinen Event gibt, den wir feuern könnten, dann müssen wir sie beim einfliefern des Briefes halt selber aufrufen.
              Ob das jetzt du als Absender des Briefes, oder der Postbote als Zusteller macht, ist unerheblich.

              Ist es nicht. Als Absender müsste ich die genaue Adresse kennen zum Aufrufen. Ein Feldwebel geht ja auch nicht zu jedem einzelnen Soldaten und aktiviert dessen Methode "lausche.auf(Befehl)", sondern er brüllt einfach in die Runde.

              Auf jeden Fall muss jemand die Instanz Empfaenger kennen. Denn wenn nicht, und wir würden einfach einen Event everybodyCheckYourMail feuern - dann würden alle potentiellen Empfänger zum Briefkasten rennen (also jeder, der einen Briefkasten hat) - und alle bis auf den einen, der tatsächlich gerade einen Brief bekommen hat, würden dies umsonst tun.

              Das stimmt allerdings. Wenn die Hierarchie nicht zu verzweigt ist, dürfte das aber kein Problem sein. Sobald angekommen, kann man ja mit stopPropagation (oder so ähnlich) die unnötige Weiterverbreitung abstellen.

              Bleiben wir beim einfachen Taschenrechner-Beispiel:
              [...]
              Das ist eben nicht immer einfach. Während der Rechner noch rechnet, will er z.B. keine weiteren Eingaben engegennehmen, also müssen alle Bedienelemente des Eingabemoduls inzwischen deaktiviert sein.

              Sie müssen entweder beim Rechner anfragen, ob er schon wieder bereit ist, neue Eingaben anzunehmen;

              Ein Klickbuttton soll ständig beim Rechner fragen, ob der wieder bereit ist? Womöglich mit setInterval oder so?

              oder der Rechner muss ihnen Bescheid sagen, dass er es jetzt wieder ist.

              Genau, aber er brüllt es nur in die Runde und sagt es nicht jedem einzelnen. Auch sagt er es nicht einfach dem Anzeigemodul, welches dann wieder zu jedem einzelnen rennen und es ihm ins Ohr flüstern müsste.

              Wenn man nun statt dessen jedem betreffenden Bedienelement einen Event mit sprechendem Namen zuordnet, z.B. "calculation" (=es wird gerade gerechnet)

              Der wäre auf dem Bedienelement m.E. fehl am Platze - das Taschenrechner-Objekt selber ist es, das Berechnungen durchführt.

              Sicher, aber die Eingabeelemente müssen doch davon wissen.

              und einen weiteren wie "inputReady" (=es darf eingegeben werden), dann können diese sich selbst aktivieren/deaktivieren,

              Nein, können sie nicht.
              Sie müssen vom Taschenrechner "benachrichtigt" werden, wenn dieser mit der Berechnung fertig ist.

              Sag' ich doch, aber nicht *einzeln* vom Rechner direkt, sondern über einen Event, quasi ein gebrüllter Befehl vom Oberst. Den kann aber auch ein Oberfeld brüllen, das ist unerheblich; verstanden wird er in jedem Fall, und der Brüllende muss nicht jeden Soldaten beim Vornamen kennen.

              Und woher wissen jetzt "alle" vorhandenen Bedienelemente (die ggf. zu ganz anderen Taschenrechner-Objekten gehören), ob sie sich von diesem "Event", der einfach ziellos in die Gegend gefeuert wird, angesprochen fühlen sollen oder nicht?

              Naja, jeder Event ist doch eindeutig. Ein mouseover z.B. ist halt ein mouseover, und kein click. Ein selbstdefinierter inputReady ist ein inputReady, und kein fckYourself. Wenn ein entsprechender eventhandler "attached" ist, dann ist er zuständig, sonst eben nicht.

              Dazu müssten sie selber wieder wissen, zu welchem Objekt sie eigentlich gehören.

              Das aktuell zuständige Objekt kennen sie natürlich, falls nötig. Nur zum sich Aktivieren/Deaktivieren beispielsweise müssen sie es nicht kennen. Wenn der Feldwebel aber etwas brüllt wie "Erobern!", dann müssen sie natürlich wissen, wen oder was es zu erobern gilt. Das Objekt kann man in einer mehr oder weniger globalen Variablen zur Verfügung stellen.

              Darum, die Elemente, die ihre Zustände gegenseitig bedingen sollen, einander auch irgendwie "bekannt" zu machen, kommst du m.E. nicht herum. Das ist aber auch im OO-Umfeld gang und gäbe. Du scheinst aber anzunehmen, ein Event-Modell wäre eine "Wunderwaffe", die einem das abnimmt?

              In gewissem Sinne ja.

              Wenn du sowas haben willst, musst du es m.E. selbst implementieren.

              Bin gerade dabei, mit Hilfe von selbstdefinierten Events...

              Warum soll das Anzeigemodul irgendetwas "abholen"?

              Weil der Befehl zum Anzeigen manchmal auch gar nicht vom Rechnermodul kommt, sondern von einem anderen, welches wiederum nichts vom Rechnermodul weiß.
              Damit widersprichst du dir selber - du sagst doch gerade, dass das Anzeigemodul die berechneten Ergebnisse mehrerer Rechner anzeigen können soll (nacheinander).

              Nein, das hab' ich so nicht gesagt. Es geht ja nicht wirklich um einen Taschenrechner. So kommt es z.B. vor, dass u.a. eine Art Rechner bemüht wird, neben anderen Modulen, und wenn alles fertig ist, heißt es "Anzeigen!", und zwar alle Ergebnisse aus den einzelnen Modulen gleichzeitig. Die Routine, die schließlich die Anzeige initiiert, muss dazu – so ist es aktuell – die Schnittstellen aller Module kennen, die Daten daraus zusammenklauben und an die Methoden des Anzeigemoduls übergeben.

              Jetzt will ich aber das Anzeigemodul selber – oder besser gesagt die einzelnen anzeigenden DOM-Elemente – mit dem nötigen Wissen über die Modul-Schnittstellen ausstatten, die es anzuzeigen gilt, und ihr Verhalten ( d.h. neu anzeigen oder nicht, aktivieren oder deaktivieren, verschwinden oder erscheinen usw. usf.) über Events steuern. Das erscheint mir sinnvoll, weil oft mehrere gleichzeitig betroffen sind, und ich nicht für jeden Fall eine Liste der Betroffenen zusammenstellen und durchlaufen will.

              Mal sehen, vielleicht wird es auch ein Schuss in den Ofen. Dass evtl. zu viele von Events belästigt werden, die sie gar nichts angehen, könnte wirklich zum Performance-Problem werden, da hast du sicher recht.

              Gruß, Don P

          2. Noch ein P.S.:

            Einige Frameworks bieten die Möglichkeit, "Custom Events" zu definieren, an - möglicherweise lässt sich damit umsetzen, was du erreichen willst (weiss ich nicht sicher, habe mich damit noch nicht genauer beschäftigt).

            Vielleicht nehmen sie dir einen Teil der Arbeit ab, die Beziehungen unter deinen (JS-)Objekten abzubilden. Aber gemacht werden muss sie auf jeden Fall.
            Bei DOM Events nimmt dir das DOM diese Aufgabe quasi ab - die Elemente im DOM stehen bereits in Beziehungen zueinander. Da kann man also "irgendwo" einen Event feuern, und Bubbling/Capturing sorgen dann dafür, dass dieser an den Stellen, die sich für ihn interessieren könnten, ankommt.
            Aber wenn du noch gar nichts hast, was Beziehungen unter deinen Objekten abbildet - dann gibt es einfach keine "Richtung", in die sich ein irgendwo gefeuerter Event (sinnvoll) "verbreiten" könnte.

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
      2. gruss Don P,

        Du skizzierst gerade probleme und loesungsansaetze, die mit folgenden
        konzepten hinreichend genug abgedeckt sind:

        deutsche Wikipedia:

        englische Wikipedia:

        • [http://en.wikipedia.org/wiki/Observer_pattern@title=»Observer Pattern«]
        • [http://en.wikipedia.org/wiki/Publish/subscribe@title=»publish-subscribe«]
        • [http://en.wikipedia.org/wiki/Signals_and_slots@title=»Signals and Slots«]

        Du benoetigst also keineswegs »eigene DOM-Events«, sondern nur eine saubere
        und vernuenftig bedienbare umsetzung eines wie auch immer gearteten beobachter-
        entwurfsmusters.

        »Signals and Slots« und JavaScript, und für letzteres besonders die art
        und weise seines »event«-getriebenen (ereignisse der benutzeroberflaeche
        bzw. client/server-request/response-pingpong) einsatzes, sind fuereinander
        wie geschaffen.

        das sprachkonzept von JavaScript wiederum laesst implementierungen von
        Mixins/Traits/Behaviors/Roles (sucht Euch das wort raus, welches Euch am
        meisten zusagt) zu, so dass eine in meinen augen saubere und typsichere
        implementierung von »Signals and Slots« in der lage ist, jedem nativen
        JavaScript-objekt eine art [EventTarget]-schnittstelle zu verbacken, die
        diese objekte um die eigenschaften [addEventListener], [removeEventListener]
        und [dispatchEvent] anreichert.

        die gerade herbeitheoretisierte implementierung von »Signals and Slots«
        bekommt jetzt den konkreten namen [EventDispatcher]. [EventDispatcher] ist
        ein JavaScript-Singleton, welches intern konstruktoren fuer [EventTarget],
        [EventListener] und [Event] kapselt.
        jedes objekt »obj«, welches sich dort mit »EventDispatcher.register(obj)«
        anmeldet, hat sofort [EventTarget]-verhalten, ist also umgehend in der
        lage,  eigene events zu werfen und registrierungen bzw. abmeldungen fuer
        die zu diesen events gehoerenden event-listener entgegenzunehmen.

        das fuktioniert bereits problemlos auf bassis jeder instanz aller in
        JavScript eingebauten kernobjekte ("build in" objects) - ist aber noch
        ohne wirklich praktischen nutzen.

        wirklich interessant wird die ganze geschichte vor dem hintergrund
        selbstgetrickter objekttypen (konstruktor-funktionen) bzw. eigener
        Mixins/Traits/Behaviors/Roles (»funktionen als implementierte interfaces?«).

        einfaches sofort in der [jconsole] ueberpruefbares bsp.:

        //[http://dean.edwards.name/packer/]	-	shrinked						-	2945 bytes	:  
        var EventDispatcher=(function(){var g=Object.prototype.toString,stringify=(function(a){return((a&&a.toString&&a.toString())||"")}),isBoolean=(function(){var b=(/^\[object\s+Boolean\]$/);return(function(a){return b.test(g.call(a))})})(),isString=(function(){var b=(/^\[object\s+String\]$/);return(function(a){return b.test(g.call(a))})})(),isFunction=(function(a){return((typeof a=="function")&&(typeof a.call=="function")&&(typeof a.apply=="function"))}),Handler={indexOf:(function(a,b){var c=(a.length-1);while(c>-1){if(a[c]===b){break}--c}return c})},Event=(function(a,b){this.constructor=Event;this.target=a;this.type=b;this.timeStamp=new Date()}),EventListener=(function(b,c,d){this.constructor=EventListener;var e=new Event(b,c);this.handleEvent=(function(a){if((typeof a=="object")&&a){a.target=e.target;a.type=e.type;a.timeStamp=e.timeStamp}else{a={target:e.target,type:e.type,timeStamp:e.timeStamp}}d(a)});this.getType=(function(){return c});this.getHandler=(function(){return d})}),EventTarget=(function(){var f={},removeEventListener=(function(a,b){var c=f[a],successfully=false;if(c){var d=c.handlers,listeners=c.listeners,idx=Handler.indexOf(d,b);if(idx>=0){d.splice(idx,1);listeners.splice(idx,1);successfully=true}}return successfully});this.addEventListener=(function(a,b){var c;if(a&&isString(a)&&isFunction(b)){var d=f[a],listener=new EventListener(this,a,b);if(d){var e=d.handlers,listeners=d.listeners,idx=Handler.indexOf(e,b);if(idx==-1){e.push(listener.getHandler());listeners.push(listener);c=listener}else{c=listeners[idx]}}else{d=f[a]={};d.handlers=[listener.getHandler()];d.listeners=[listener];c=listener}}return c});this.removeEventListener=(function(a,b){return((isString(a)&&isFunction(b)&&removeEventListener(a,b))||((a instanceof EventListener)&&removeEventListener(a.getType(),a.getHandler()))||false)});this.dispatchEvent=(function(a){var b=false,type=(((typeof a=="object")&&(typeof a.type=="string")&&a.type)||((typeof a=="string")&&a)),event=(type&&f[type]);if(event){var c=(event&&event.listeners),len=((c&&c.length)||0),idx=0;if(len>=1){while(idx<len){c[idx++].handleEvent(a)}b=true}}return b})}),pseudoTarget=new EventTarget,CROSSCHECK_TARGET={addListenerString:pseudoTarget.addEventListener.toString(),removeListenerString:pseudoTarget.removeEventListener.toString(),dispatchEventString:pseudoTarget.dispatchEvent.toString()};delete pseudoTarget;return{register:(function(a){if((typeof a.addEventListener=="function")||a.attachEvent||(typeof a.removeEventListener=="function")||a.detachEvent||(typeof a.dispatchEvent=="function")||a.fireEvent){return}EventTarget.call(a)}),unsubscribe:(function(a){if(stringify(a.addEventListener)===CROSSCHECK_TARGET.addListenerString){delete a.addEventListener}if(stringify(a.removeEventListener)===CROSSCHECK_TARGET.removeListenerString){delete a.removeEventListener}if(stringify(a.dispatchEvent)===CROSSCHECK_TARGET.dispatchEventString){delete a.dispatchEvent}})}})();  
          
          
          
        var Queue = (function () { // [http://de.wikipedia.org/wiki/Datenstruktur#Warteschlange]  
          
          
        	EventDispatcher.register(this); // applying the [EventTarget] mixin/behavior/interface.  
          
          
        	var self = this, list = [],  
          
        	onEnqueue = (function (obj) {  
          
        	//self.dispatchEvent({target: self, type: "onEnqueue", elm: obj/*, even more key:value pairs */});  
        		self.dispatchEvent({type: "onEnqueue", elm: obj});  
        	//self.dispatchEvent("onEnqueue");  
        	}),  
        	onDequeue = (function (obj) {  
          
        	//self.dispatchEvent({target: self, type: "onDequeue", elm: obj/*, even more key:value pairs */});  
        		self.dispatchEvent({type: "onDequeue", elm: obj});  
        	//self.dispatchEvent("onDequeue");  
        	}),  
        	onEmpty = (function () {  
          
        	//self.dispatchEvent({target: self, type: "onEmpty"/*, even more key:value pairs */});  
        	//self.dispatchEvent({type: "onEmpty"/*, even more key:value pairs */});  
        		self.dispatchEvent("onEmpty");  
        	});  
          
          
        	this.constructor = arguments.callee;  
          
          
        	this.enqueue = (function (obj/*:[Object]*/) { /* enqueue | line up | [Array.push] */  
          
        		list.push(obj);  
        		this.length = list.length;  
          
        		onEnqueue(obj);  
        	});  
        	this.dequeue = (function () { /* dequeue | line up | [Array.shift] */  
          
        		var obj = list.shift();  
        		if (list.length === 0) {  
          
        			onEmpty();  
        		}  
        		onDequeue(obj);  
          
        		return obj;  
        	});  
          
        	this.length = 0;  
        });  
          
          
          
        var myQueue = new Queue;  
          
        myQueue.addEventListener("onEnqueue", (function (evt) {print("onEnqueue - evt : " + evt + " , evt.target : " + evt.target + " , evt.type : " + evt.type + " , evt.elm : " + evt.elm)}));myQueue.addEventListener("onDequeue", (function (evt) {print("onDequeue - evt : " + evt + " , evt.target : " + evt.target + " , evt.type : " + evt.type + " , evt.elm : " + evt.elm)}));  
        myQueue.addEventListener("onEmpty", (function (evt) {print("onEmpty - evt : " + evt + " , evt.target : " + evt.target + " , evt.type : " + evt.type + " , evt.elm : " + evt.elm)}));  
        print("\n");  
        print("\n");  
          
        myQueue.dequeue();  
        print("\n");  
        print("\n");  
          
        myQueue.enqueue("Signals");  
        print("\n");  
        myQueue.enqueue("and");  
        print("\n");  
        myQueue.enqueue("Slots");  
        print("\n");  
        print("\n");  
          
        myQueue.dequeue();  
        print("\n");  
        myQueue.dequeue();  
        print("\n");  
        myQueue.dequeue();  
        print("\n");
        

        ende - teil 1 ... teil 2 wird hier gleich im anschluss gepostet ...

        1. hallo again Don P,

          ... teil 2 ...

          komplexeres, an die fragestellung angelehntes, kostruiertes, schematisches bsp.:

          (function () {  
            
            
          //[http://dean.edwards.name/packer/]	-	shrinked + encoded	-	2144 bytes	:  
          	eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('4 1c=(2(){4 g=16.12.k,u=(2(a){3((a&&a.k&&a.k())||"")}),11=(2(){4 b=(/^\\[t\\s+Z\\]$/);3(2(a){3 b.O(g.w(a))})})(),B=(2(){4 b=(/^\\[t\\s+13\\]$/);3(2(a){3 b.O(g.w(a))})})(),C=(2(a){3((8 a=="2")&&(8 a.w=="2")&&(8 a.10=="2"))}),I={A:(2(a,b){4 c=(a.M-1);W(c>-1){5(a[c]===b){17}--c}3 c})},G=(2(a,b){6.L=G;6.o=a;6.9=b;6.m=x Y()}),v=(2(b,c,d){6.L=v;4 e=x G(b,c);6.X=(2(a){5((8 a=="t")&&a){a.o=e.o;a.9=e.9;a.m=e.m}H{a={o:e.o,9:e.9,m:e.m}}d(a)});6.Q=(2(){3 c});6.q=(2(){3 d})}),K=(2(){4 f={},i=(2(a,b){4 c=f[a],D=J;5(c){4 d=c.F,h=c.h,7=I.A(d,b);5(7>=0){d.V(7,1);h.V(7,1);D=N}}3 D});6.p=(2(a,b){4 c;5(a&&B(a)&&C(b)){4 d=f[a],j=x v(6,a,b);5(d){4 e=d.F,h=d.h,7=I.A(e,b);5(7==-1){e.U(j.q());h.U(j);c=j}H{c=h[7]}}H{d=f[a]={};d.F=[j.q()];d.h=[j];c=j}}3 c});6.i=(2(a,b){3((B(a)&&C(b)&&i(a,b))||((a 15 v)&&i(a.Q(),a.q()))||J)});6.l=(2(a){4 b=J,9=(((8 a=="t")&&(8 a.9=="T")&&a.9)||((8 a=="T")&&a)),y=(9&&f[9]);5(y){4 c=(y&&y.h),E=((c&&c.M)||0),7=0;5(E>=1){W(7<E){c[7++].X(a)}b=N}}3 b})}),n=x K,r={S:n.p.k(),P:n.i.k(),R:n.l.k()};z n;3{14:(2(a){5((8 a.p=="2")||a.18||(8 a.i=="2")||a.19||(8 a.l=="2")||a.1a){3}K.w(a)}),1b:(2(a){5(u(a.p)===r.S){z a.p}5(u(a.i)===r.P){z a.i}5(u(a.l)===r.R){z a.l}})}})();',62,75,'||function|return|var|if|this|idx|typeof|type||||||||listeners|removeEventListener|listener|toString|dispatchEvent|timeStamp|pseudoTarget|target|addEventListener|getHandler|CROSSCHECK_TARGET||object|stringify|EventListener|call|new|event|delete|indexOf|isString|isFunction|successfully|len|handlers|Event|else|Handler|false|EventTarget|constructor|length|true|test|removeListenerString|getType|dispatchEventString|addListenerString|string|push|splice|while|handleEvent|Date|Boolean|apply|isBoolean|prototype|String|register|instanceof|Object|break|attachEvent|detachEvent|fireEvent|unsubscribe|EventDispatcher'.split('|'),0,{}));  
            
            
            
          	var Processor = (function () {  
            
            
          		var xyz, abc, objStatistics, objAnotherStatistics,  
            
          		computeStatistics = (function () {/*  
            
          			... */  
          			Processor.dispatchEvent({type: "onStatisticsComputed", result: objStatistics/*, even more key:value pairs */});  
          		}),  
          		computeAnotherStatistics = (function () {/*  
            
          			... */  
          			Processor.dispatchEvent({type: "onAnotherStatisticsComputed", result: objAnotherStatistics/*, even more key:value pairs */});  
          		});  
            
            
          		return {  
            
          			initialize : (function (arg01, arg02/*, ...*/) {  
            
          				xyz = arg01;  
          				abc = arg02;  
          			}),  
          			getStatistics : (function () {  
            
          				computeStatistics();  
          			}),  
          			getAnotherStatistics : (function () {  
            
          				computeAnotherStatistics();  
          			})  
          		};  
          	})();  
            
            
          	EventDispatcher.register(Processor); // applying signal slot konzept onto [Processor] and all elements that will listen to its events.  
            
            
            
          	var ResultsController = (function () {  
            
            
          		var processor,  
            
          		displayStatistics = (function (evt) {/*  
            
          			... */  
          		}),  
          		displayAnotherStatistics = (function (evt) {/*  
            
          			... */  
          		});  
            
            
          		return {  
            
          			initialize : (function (arg01/*, ...*/) {  
            
          				processor = arg01;  
            
          				processor.addEventListener("onStatisticsComputed", displayStatistics);  
          				processor.addEventListener("onAnotherStatisticsComputed", displayAnotherStatistics);  
          			})  
          		};  
          	})();  
            
            
            
          	var Requestor = (function () {  
            
          		var processor;  
            
          		return {  
            
          			initialize : (function (arg01/*, ...*/) {  
            
          				processor = arg01;  
            
          				processor.getStatistics();  
          				processor.getAnotherStatistics();  
          			})  
          		};  
          	})();  
            
            
            
          	Processor.initialize("val01", "val02"/*, ...*/);  
            
          	ResultsController.initialize(Processor);  
          	Requestor.initialize(Processor);  
            
          })();
          

          der in den beispielen zur anwendung kommende aktuelle code findet sich auf [refactory.org]
          und traegt den sperrigen titel »[EventDispatcher] singleton - a core-API based Signals and Slots implementation«.

          historische links, die zum gerade verlinkten ergebnis beitrugen lauten:

          so long - peterS. - pseliger@gmx.net

          --
          »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
          Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
          ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
          1. ein letztes "hallo" in die runde fuer alle Geduldigen und Interessierten,

            [spam]: der zuletzt gepostete beispiel-code kommt hier nochmal
            mit *debug*-ausgabe, um das grundlegende zusammenspiel der
            komponenten besser nachvollziehbar zu machen ...

            ... bitte mit *copy and paste* auf die [jconsole] loslassen:

            (function () {  
              
              
            //[http://dean.edwards.name/packer/]  -  shrinked + encoded  -  2144 bytes  :  
              eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('4 1c=(2(){4 g=16.12.k,u=(2(a){3((a&&a.k&&a.k())||"")}),11=(2(){4 b=(/^\\[t\\s+Z\\]$/);3(2(a){3 b.O(g.w(a))})})(),B=(2(){4 b=(/^\\[t\\s+13\\]$/);3(2(a){3 b.O(g.w(a))})})(),C=(2(a){3((8 a=="2")&&(8 a.w=="2")&&(8 a.10=="2"))}),I={A:(2(a,b){4 c=(a.M-1);W(c>-1){5(a[c]===b){17}--c}3 c})},G=(2(a,b){6.L=G;6.o=a;6.9=b;6.m=x Y()}),v=(2(b,c,d){6.L=v;4 e=x G(b,c);6.X=(2(a){5((8 a=="t")&&a){a.o=e.o;a.9=e.9;a.m=e.m}H{a={o:e.o,9:e.9,m:e.m}}d(a)});6.Q=(2(){3 c});6.q=(2(){3 d})}),K=(2(){4 f={},i=(2(a,b){4 c=f[a],D=J;5(c){4 d=c.F,h=c.h,7=I.A(d,b);5(7>=0){d.V(7,1);h.V(7,1);D=N}}3 D});6.p=(2(a,b){4 c;5(a&&B(a)&&C(b)){4 d=f[a],j=x v(6,a,b);5(d){4 e=d.F,h=d.h,7=I.A(e,b);5(7==-1){e.U(j.q());h.U(j);c=j}H{c=h[7]}}H{d=f[a]={};d.F=[j.q()];d.h=[j];c=j}}3 c});6.i=(2(a,b){3((B(a)&&C(b)&&i(a,b))||((a 15 v)&&i(a.Q(),a.q()))||J)});6.l=(2(a){4 b=J,9=(((8 a=="t")&&(8 a.9=="T")&&a.9)||((8 a=="T")&&a)),y=(9&&f[9]);5(y){4 c=(y&&y.h),E=((c&&c.M)||0),7=0;5(E>=1){W(7<E){c[7++].X(a)}b=N}}3 b})}),n=x K,r={S:n.p.k(),P:n.i.k(),R:n.l.k()};z n;3{14:(2(a){5((8 a.p=="2")||a.18||(8 a.i=="2")||a.19||(8 a.l=="2")||a.1a){3}K.w(a)}),1b:(2(a){5(u(a.p)===r.S){z a.p}5(u(a.i)===r.P){z a.i}5(u(a.l)===r.R){z a.l}})}})();',62,75,'||function|return|var|if|this|idx|typeof|type||||||||listeners|removeEventListener|listener|toString|dispatchEvent|timeStamp|pseudoTarget|target|addEventListener|getHandler|CROSSCHECK_TARGET||object|stringify|EventListener|call|new|event|delete|indexOf|isString|isFunction|successfully|len|handlers|Event|else|Handler|false|EventTarget|constructor|length|true|test|removeListenerString|getType|dispatchEventString|addListenerString|string|push|splice|while|handleEvent|Date|Boolean|apply|isBoolean|prototype|String|register|instanceof|Object|break|attachEvent|detachEvent|fireEvent|unsubscribe|EventDispatcher'.split('|'),0,{}));  
              
              
              
              var Processor = (function () {  
              
              
                var xyz, abc, objStatistics, objAnotherStatistics,  
              
                computeStatistics = (function () {/*  
              
                  ... */  
                  print("Processor - private function [computeStatistics] - dispatching \"onStatisticsComputed\"");  
              
                  Processor.dispatchEvent({type: "onStatisticsComputed", result: objStatistics/*, even more key:value pairs */});  
                }),  
                computeAnotherStatistics = (function () {/*  
              
                  ... */  
                  print("Processor - private function [computeAnotherStatistics] - dispatching \"onAnotherStatisticsComputed\"");  
              
                  Processor.dispatchEvent({type: "onAnotherStatisticsComputed", result: objAnotherStatistics/*, even more key:value pairs */});  
                });  
              
              
                return {  
              
                  initialize : (function (arg01, arg02/*, ...*/) {  
              
                    xyz = arg01;  
                    abc = arg02;  
                  }),  
                  getStatistics : (function () {  
              
                    computeStatistics();  
                  }),  
                  getAnotherStatistics : (function () {  
              
                    computeAnotherStatistics();  
                  })  
                };  
              })();  
              
              
              EventDispatcher.register(Processor); // applying signal slot konzept onto [Processor] and all elements that will listen to its events.  
              
              
              
              var ResultsController = (function () {  
              
              
                var processor,  
              
                displayStatistics = (function (evt) {/*  
              
                  ... */  
                  print("ResultsController - private function [displayStatistics] is handler for event \"onStatisticsComputed\" which it is listening for");  
                }),  
                displayAnotherStatistics = (function (evt) {/*  
              
                  ... */  
                  print("ResultsController - private function [displayAnotherStatistics] is handler for event \"onAnotherStatisticsComputed\" which it is listening for");  
                });  
              
              
                return {  
              
                  initialize : (function (arg01/*, ...*/) {  
              
                    processor = arg01;  
              
                    processor.addEventListener("onStatisticsComputed", displayStatistics);  
                    processor.addEventListener("onAnotherStatisticsComputed", displayAnotherStatistics);  
                  })  
                };  
              })();  
              
              
              
              var Requestor = (function () {  
              
                var processor;  
              
                return {  
              
                  initialize : (function (arg01/*, ...*/) {  
              
                    processor = arg01;  
              
                    processor.getStatistics();  
                    processor.getAnotherStatistics();  
                  })  
                };  
              })();  
              
              
              
              Processor.initialize("val01", "val02"/*, ...*/);  
              
              ResultsController.initialize(Processor);  
              Requestor.initialize(Processor);  
              
            })();
            

            viel spass - peterS. - pseliger@gmx.net

            --
            »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
            Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
            ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
            1. Hallo Peter,

              Wow, das ist ja viel Stoff. Vielen, vielen Dank!

              Habe es bis jetzt nur überflogen und was ich davon verstanden habe ist, dass man mit diesem Konzept wohl wirklich das umsetzen kann, was ich mir vorstelle.

              Auf den ersten Blick zwar ein bisschen viel Code (v.a. im komprimierten Teil), aber mal sehen, was sich damit anfangen lässt.

              Danke nochmal
              Don P

              1. gruss Don P,

                Habe es bis jetzt nur überflogen und was ich davon
                verstanden habe ist, dass man mit diesem Konzept wohl
                wirklich das umsetzen kann, was ich mir vorstelle.

                Auf den ersten Blick zwar ein bisschen viel Code (v.a.
                im komprimierten Teil), ...

                den musst Du ja auch nicht verstehen. unkomprimiert und
                lesbar gibt es den [EventDispatcher] ja auf der von mir
                verlinkten [refctory.org].

                viel wichtiger ist/sind das verhalten/die eigenschaften
                der [EventTarget]-schnittstelle.

                [addEventListener] gibt tatsaechlich die referenz auf das
                gerade intern erstellte [EventListener]-objekt zurueck,
                sodass man [removeEventListener] auch nur mit dieser
                einen referenz aufrufen kann, und nicht in jedem fall
                fuer eine abmeldung immer event-typ(:String) und
                event-handler(:Function)-referenz bemuehen muss.

                bei [dispatchEvent] ist es wichtig zu wissen, dass man
                im argument den event-typ sowohl als reinen string als
                auch als object-hash mit name-wert-paaren werfen kann.

                im ersten fall wird immer der nicht zu korrumpierende
                default-event geworfen, welcher beim anmelden eines
                event-listeners auf einem objekt automatisch fuer genau
                dieses objekt erstellt und innerhalb seines von ausssen
                nicht erreichbaren [EventTarget]-scopes gekapselt wird.

                ein default-event hat immer die gleichen drei und durch
                [dispatchEvent] argumente nicht ueberschreibbaren
                eigenschaften:

                • [target] die referenz auf das *dispatchende* objekt,
                • [type] den typ des events als string-value,
                • [timeStamp] ein date object, welches dem default-event
                    beim seiner erstellung zugewiesen wird (ich weiss aber
                    noch nicht, wann genau, ausser in einigen spezialfaellen,
                    man das wirklich braucht).

                im zweiten fall laesst sich auch eine objct-(hash) werfen,
                um den default-event um genau diese name-wert-paare
                anzureichern, z.b., wenn man alle angemeldeten event-handler
                mit diesen zusaetzlichen informationen versorgen will/muss.

                [animationReference].dispatchEvent({type: "onNextFrame", currentFrame: 4, amountOfFrames: 20, opacity: 0.2/*, even more key:value pairs */});]

                ... aber mal sehen, was sich damit
                anfangen lässt.

                ... native JavaScript-objekte miteinander lose koppeln.

                auf diese weise erobert man sich eine weitere facette,
                die einen im sprachkern elegant und effizient programmieren
                laesst.

                so long - peterS. - pseliger@gmx.net

                --
                »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
                Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
                ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
  2. Hallo,

    Habe mal meine Logik bemüht und bin jetzt zu dem Schluss gekommen, dass das, was mir da vorschwebt, schlicht unmöglich ist.

    Ein Event wird natürlich immer von einem bestimmten DOM-Element gefeuert, und solange es *betroffene* Kind-Elemente gibt, wird der Event auch nach unten weitergereicht ("capturing phase"), und steigt ggf. anschließend wieder nach oben zu den Eltern-Elementen in der "bubbling phase".

    Wenn also ein Event z.B. von document.body gefeuert wird, dann gibt es gar keine *betroffenen* Kindelemente, und auch nur wenige Eltern-Elemente. Das wäre z.B. der Fall für einen Klick irgendo im Dokument außerhalb von jedweden anderen Elementen (div, table, button oder was immer). Solche Elemente bekommen vom Klick natürlich nichts mit, und können daher auch nicht reagieren.

    Die einzige Möglichkeit, unbekannte Elemente durch einen gefeuerten Event zu erreichen ist die, dass man den Event auf die äußersten "Blätter" jedes "Astes" im DOM-Baums feuert, so dass der Event im Baum aufsteigen und von den lauschenden Elementen verarbeitet werden kann.

    Wenn man das obige Beispiel so umschreibt, dass nicht der 2.Button, sondern das umgebende div-Element den Event verarbeitet, dann funktioniert es nämlich auch.

    Man muss also notgrdrungen immer alle äußeren "Blätter" im DOM-Baum ermitteln und auf jedes feuern um sicherzustellen, dass der Event auch wirklich zu allen lauschenden DOM-Elementen gelangt. Das ist zwar nicht sonderlich bequem :-(, aber anders geht es wohl nicht...

    Gruß, Don P

    1. Hallo P,

      Ein Event wird natürlich immer von einem bestimmten DOM-Element gefeuert,...

      es ist richtig, in den englischen Texten heißt es immer "fire" oder "fired". Wenn man bedenkt wie sich ein Feuer ausbreitet, was Du ja auch im Durchreichen erklärst, trifft es auch das Wesen der Sache gut. Können wir uns aber dennoch darauf einigen, dass ein Event weder gefeuert wird noch abbrennt, sondern schlichtweg ausgelöst wird bzw. stattfindet oder eintritt? Danke!

      Wenn die Lösung für Dich das tut, was Du willst, ist es gut. Ich würde anders herangehen. Registriere die Referenzen aller Elemente, die bei einem bestimmten Ereignis bearbeitet werden sollen in einem Objekt (var myevent={};), bzw. lösche sie aus dem Objekt, wenn sie nicht mehr betroffen sein sollen. Statt document.body.dispatchEvent() brauchst Du dann nur noch Funktionen, die myevent als Register heranziehen - fertig.

      Gruß aus Berlin!
      eddi

      1. Hallo,

        es ist richtig, in den englischen Texten heißt es immer "fire" oder "fired". Wenn man bedenkt wie sich ein Feuer ausbreitet, was Du ja auch im Durchreichen erklärst, trifft es auch das Wesen der Sache gut. Können wir uns aber dennoch darauf einigen, dass ein Event weder gefeuert wird noch abbrennt, sondern schlichtweg ausgelöst wird bzw. stattfindet oder eintritt?

        Hmm, da ich erst jetzt anfange mich näher dem Auslösen von Events zu beschäftigen, bin noch umerziehbar. Mal sehen...

        Finde aber, dass das "feuern" die Sache wirklich sehr gut trifft. In der Biologie heißt es ja auch, dass ein Neuron "feuert", d.h. einen Impuls abgibt. In diesem Sinne passt das genau auf Events. Der Impuls breitet sich dann wie in einem Nervenstrang entlang des DOM aus.

        Die Ausbreitung eines wirkliches Feuers ist da schon etwas anders geartet. In englischen Texten wird sogar *auf* ein "Ziel"element gefeuert im Sinne von "geschossen", was die Sache auch gut "trifft". Englische Muttersprachler haben mit dem militärischen Vokabular anscheinend weniger Schwierigkeiten als deutsche...

        Registriere die Referenzen aller Elemente, die bei einem bestimmten Ereignis bearbeitet werden sollen in einem Objekt (var myevent={};), bzw. lösche sie aus dem Objekt, wenn sie nicht mehr betroffen sein sollen. Statt document.body.dispatchEvent() brauchst Du dann nur noch Funktionen, die myevent als Register heranziehen - fertig.

        Das "nur noch" ist der Knackpunkt. Zur Zeit habe ich fertige Methoden wie

        buttonsActive: function (bool) {  
          
          with(this) {  
          
            bla.disabled = blu.disabled = blubb.disabled =  
            ooo.disabled = iii.disabled = aaa.disabled =  
          
            /* und viele mehr... */  
          
            bing.disabled = bang.disabled = bong.diabled =  
          
            !bool;  
          }  
        }
        

        Das gefällt mir nicht wirklich. Wenn ich statt dessen für all diese DOM-Elemente Eventlistener registriere, die auf Events wie zustand1, zustandX, zustandY etc. hören, dann reicht das Auslösen entsprechender Events von irgendeinem Objekt aus – fertig.

        Das Problem ist dabei nur das Zielelement, das man beim Auslösen mit angeben muss. document.body taugt dafür leider nicht, es muss schon ein Endknoten im DOM-Baum (ohne weitere Kindelemente) sein, damit sich der Impuls im Baum ausbreiten kann. Das kann aber u.U. in ein wildes Feuern auf viele Endknoten, ein sog. Amokballern werden ;-)

        Mich reizt allein der Versuch, weil es anscheinenend ein ziemlich unüblicher Ansatz ist. Aber warum soll man nicht bereits vorhandene Infrastruktur wie das Verbreiten von Events nutzen, statt viele Zeilen JS Code zu erstellen und zu verwalten?

        Gruß, Don P

        1. Re:

          Wir scheinen uns wohl misszuverstehen:

          var myevent={};  
          function anzeige(){  
          	for(var i in myevent){  
          		document.getElementById(i).style.background='gray';  
          	}
          
          <button onclick="myevent['abc']=''">Registrierung</button>  
          <!--                      ^^^ -->  
          <button onclick="anzeige()">Anzeigeänderung</button>  
          <button onclick="delete(myevent['abc'])">Ausschmiss</button>  
          <!--                             ^^^ -->  
            
          <p id="abc">test</p>  
          <!--   ^^^  -->
          

          Gruß aus Berlin!
          eddi