WebComponents(lit-element) und Server-Side-Events



  • Hallo Leute,

    ich experimentiere gerade bissel mit WebComponents in Kombination mit dem Lit-Element Framework.

    Habe dafür in C# eine kleines Backend mit SSE (Server-Side-Events) welches auch soweit alle funktioniert.

    Das Problem ist dass in meiner experimentiere Web Komponente die SEE-Events das lit-element rendering aktualisieren? (Bitte seid nicht so streng spiele erst seit heute damit rum:) )

    import { html, css, LitElement } from 'https://unpkg.com/lit-element?module';
    
    export class FooBar extends LitElement {
      static get styles() {
        return css`
          :host {
            display: block;
            padding: 25px;
            color: var(--foo-bar-text-color, #000);
          }
        `;
      }
    
      static get properties() {
        return {
          title: { type: String },
          _data: { type: String }
        };
      }
    
      get data() {
        return this._data;
      }
    
      set data(data) {
        this._data = data;
      }
    
      onServerUpdate(event) {
        console.log("SSE: " + event.data.toString()); 
        this._data = event.data.toString(); // CHANGE PROPERTY FROM SSE EVENT
        if (event.id == "CLOSE") {
          source.close();
        }
      }
    
      updated(changedProperties) {
        changedProperties.forEach((oldValue, propName) => {
          console.log(`${propName} changed. oldValue: ${oldValue}`); // ONLY CALLED WheN PROPERTY IS SET e.g. Button click
        });
      }
    
      connectedCallback() {
        super.connectedCallback()
    
        console.log('connected')
    
        /* Server side events */
        var eventSource = new EventSource("/updates");
        eventSource.onmessage = this.onServerUpdate;
        eventSource.onopen = function () { console.log('*** Connected ***'); };
        eventSource.onerror = function () { console.log('*** Error ***'); };
      }
    
      constructor()
      {
        super();
        this.title = 'Hey there';
      }
      
      render() {
        return html`
          <h2>${this.title} Nr. ${this.counter}!</h2>
          <p>${this._data}!</p>
          <button @click=${(e) => { this._data = "set property by button clicked"; }}}>setProp</button>
        `;
      }
    }
    
    

    Wenn ich via Button clicken event das _data property aktualisiere geht das. aber das EventSource onmessage event nicht (ich sehe im browser log, dass Daten ankommen nur das _data Property wird nicht aktualisiert ).

    P.S.: Ist SSE überhaupt der richtige Weg um Server update zu bekommen?

    Danke und Schönens WE euch



  • Moin,

    zu Deinem Experiment ein paar Anmerkungen.

    Du hast eine Eigenschaft mit dem Bezeichner "counter" in Zeile 63 aufgerufen, welche sonst nirgends Logik beheimatet.

    Ich würde direkt oben im Code

    return {
        title: {type: String},
        counter: {type: Number},
        _data: {type: String}
    }
    

    ergänzen, damit diese als Eigenschaft und dem vorgesehen Typ direkt ersichtlich ist, wobei in JavaScript ohnehin der Wilde Westen der Datentypen herrscht.

    Zum eigentlichen Thema des Neuladens deines Komponenten bei Server-Updates:

    Ich würde direkt einen EventListener für das Data-Event spezifizieren.
    Also anstatt "eventSource.onmessage usw." würde ich

    eventSource.addEventListener( 'data', event => this.onServerUpdate(event, eventSource) );
    

    schreiben und die Methode "onServerUpdate" entsprechend anpassen, sodass eventSource (Dein SSE-Objekt) in dieser auch korrekt referenziert wird, was bisher nicht der Fall ist.

    Ggf. müssen noch die Streams vom Server korrekt konvertiert werden, wobei ich ohne Deine genaue Implementierung im Backend zu kennen, dazu nichts schreiben kann.

    P.S.: Ist SSE überhaupt der richtige Weg um Server update zu bekommen?

    Es gibt für sowas mehrere "richtige" Wege. SSE finde ich zu stiefmütterlich implementiert und im Vergleich zu bspw. WebSockets zu unflexibel.



  • @patrik-kuehl sagte in WebComponents(lit-element) und Server-Side-Events:

    eventSource.addEventListener( 'data', event => this.onServerUpdate(event, eventSource) );

    vielen dank , das habe ich soweit angepasst (das mit dem counter auch). aber troztdem verstehe ich nicht dass in Zeile 64 der inhalt nich neu gerendert wird weil ich ja das property _data in Zeile 31 zyklisch ändere . woran liegt das?



  • @SoIntMan sagte in WebComponents(lit-element) und Server-Side-Events:

    troztdem verstehe ich nicht dass in Zeile 64 der inhalt nich neu gerendert wird weil ich ja das property _data in Zeile 31 zyklisch ändere . woran liegt das?

    Wie schauen Deine SSE-Streams aus, welche vom C#-Backend kommen?
    Das Frontend sollte soweit funktionieren (.s https://codepen.io/patrik-kuehl/pen/zYBPjMY). Welches Event hast Du spezifiziert? Du schreibst, die Daten kommen an, sind diese auch im korrekten Format, bzw. werden die Eigenschaften korrekt aufgerufen (ggf. ein JSON-String)?



  • @SoIntMan sagte in WebComponents(lit-element) und Server-Side-Events:

    eventSource.onmessage = this.onServerUpdate;

    hier muss das hin: (bind)

    eventSource.onmessage = this.onServerUpdate.bind(this);
    

    mir war nich klar dass der this context etwas anders in js is:)



  • @SoIntMan sagte in WebComponents(lit-element) und Server-Side-Events:

    @SoIntMan sagte in WebComponents(lit-element) und Server-Side-Events:

    eventSource.onmessage = this.onServerUpdate;

    hier muss das hin: (bind)

    eventSource.onmessage = this.onServerUpdate.bind(this);
    

    mir war nich klar dass der this context etwas anders in js is:)

    Das ist im Grunde der Sinn und Zweck meiner Arrow Function gewesen, aber immerhin klappt es nun.

    Bzgl. der Nutzung von "bind" kann ich noch das nahelegen: https://google.github.io/styleguide/jsguide.html#features-functions-arrow-functions


Anmelden zum Antworten