ebody: Methode die ein Array/Objekt durchläuft - kann man auf jeden Loop zugreifen?

problematische Seite

Hallo,

Beispiel:

Diese eine Zeile würde ein Array durchlaufen und jedes Element mit einem p Tag drum rum in einem Array speichern.

const domArrValues = arrMovies.map(arrElement => `<p>${arrElement}</p>`);

Wenn man diese Zeile ausführlicher darstellt sieht man noch deutlicher, dass man auf jeden Loop reagieren kann. Man könnte eine Funktion aufrufen etc.

const domArrValues = arrMovies.map(
  function (arrElement){
   return `<p>${arrElement}</p>`;
  }
);

Wenn man eine Methode hat, die ein Array und/oder Objekt durchläuft, kann man dann auch auf jeden Loop zugreifen?

const objFilter = {
  Genres: ['Action', 'Adventure', 'Drama', 'Fantasy', 'Science-Fiction', 'Superheroes', 'Thriller'],
  Tags: ['Batman', 'Comic', 'Favorite', 'Marvel', 'New York', 'Space', 'War']
}

class Data{
  
  loopObjArrData(objData){

    for(let ObjKey in objData){

      return ObjKey;

      for(var arrElement of objData[ObjKey]){
        return arrElement;
      }

    }

  }  
} 

Wenn ja, wie? Ich habe schon einiges probiert, aber bekomme es nicht hin. U.a. so:

let movieData = new Data();


// Uncaught ReferenceError: Invalid left-hand side in assignment
movieData.loopObjArrData((objFilter)) =
  function(item){
    console.log(`<p>${item}</p>`);
  }

Gruß ebody

  1. problematische Seite

    @@ebody

    Wenn man eine Methode hat, die ein Array und/oder Objekt durchläuft, kann man dann auch auf jeden Loop zugreifen?

    map((element, index) => { ... })?

    MDN

    😷 LLAP

    --
    „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
    — Joachim Gauck über Impfgegner
  2. problematische Seite

    Hallo ebody,

    Am Rande gefragt: warum ist loopObjArrData Methode einer Klasse? Sie verwendet keine Daten aus dem this-Objekt. Es wäre - je nach Aufgabe der Klasse - zu erwarten, dass entweder das durchlaufene Array oder das Filter-Array unter this zu finden ist.

    Wenn Du eine Methode oder Funktion hast, die irgendeine Form von Collection durchläuft, und Du ihr etwas mitgeben möchtest, das pro Durchlauf aktiviert wird, benötigst Du einen eigenen Callback, den Du dann selbst aufrufst. Das geht mit einer for..of Schleife so:

    function loopy(collection, callback)
    {
       for (let entry of collection)
       {
          callback(entry);
       }
    }
    
    let coll = [ "x", "y", "z" ];
    loopy(coll, c => console.log(c));
                ===================   Callback als Pfeilfunktion
    

    Du kannst eigene Callbacks auch aus einem anderen Callback heraus aufrufen. Funktionen sind Funktionen...

    function gloopy(collection, callback)
    {
       collection.forEach(entry => callback(entry));
    }
    
    let coll = [ "x", "y", "z" ];
    gloopy(coll, c => console.log(c));
                ===================   Callback als Pfeilfunktion
    

    Und natürlich spricht auch nichts dagegen, wenn ein Callback einen Wert zurückgibt.

    function summeWenn(collection, filterCallback) {
       let summe = 0;
       for (let entry of collection) {
          if (filterCallback(entry))
             summe += entry;
       }
    }
    
    let werte = [ 1, 5, 9, 22, 12 ];
    let kleinSum = summeWenn(werte, w => w < 10);
    console.log(kleinSum);    // 15, Summe aller Werte unter 10
    

    Eine Pfeilfunktion wie w => w < 10, die hinter dem Pfeil nur einen einzelnen JavaScript-Ausdruck hat und keine geschweiften Klammern, gibt den Wert dieses Ausdrucks zurück. Für diesen Fall also true, wenn w < 10 ist und sonst false.

    Hat Dir das weitergeholfen?

    Rolf

    --
    sumpsi - posui - obstruxi
    1. problematische Seite

      Hallo Rolf,

      vielen Dank, das hat mir auf jeden Fall sehr weiter geholfen.

      const objFilter = {
        Genres: ['Action', 'Adventure', 'Drama', 'Fantasy', 'Science-Fiction', 'Superheroes', 'Thriller'],
        Tags: ['Batman', 'Comic', 'Favorite', 'Marvel', 'New York', 'Space', 'War']
      }
      
      class Data{
        
        loopObjArrData(objData,cbKey,cbArrValue){
      
          for(let ObjKey in objData){
      
            cbKey(ObjKey);
      
            for(var arrElement of objData[ObjKey]){
              cbArrValue(arrElement);
            }
      
          }
      
        }  
      }
      
      let movieData = new Data();
      
      movieData.loopObjArrData(objFilter, a => console.log(`<h2>${a}</h2>`), b => console.log(`<p>${b}</p>`));
      

      warum ist loopObjArrData Methode einer Klasse?

      Ich möchte die Methode, die das Array durchläuft in einer Klasse verwenden. Da kommt noch einiges hinzu, daher habe ich sie in diesem Beispiel einfach auch schon in eine Klasse gepackt.

      Ich versuche gerade Klasse(n) zu schreiben, um HTML Code für bestimmte Komponenten generieren zu lassen. Deren Templates haben Platzhalter. Die Platzhalter sollen mit Keys, deren Werten und/oder Werten aus Arrays ersetzt werden. Welcher Platzhalter mit welchem Wert ersetzt werden soll, kann man über klasseninstanzname.template = {} festgelegt werden.

      Das ist alles zur Zeit noch im Bau und wild. Weil ich verschiedenes probiere und auskommentiere. Die Möglichkeit aus dem Beispiel könnte die Sache aber evtl. deutlich einfacher und sauberer gestalten. https://codepen.io/ebody/pen/KKXwvXM

      Gruß ebody

      1. problematische Seite

        Hallo ebody,

        oh ja, das ist sehr wild…

        Mal unsortiert...

        UIFeed template - der getter liefert ein Objekt für parent- und child-layout, während der setter dazu da ist, eine Art "Konfigurationsobjekt" zu setzen, das (a) angibt, welches der 3 Layouts zu verwenden ist und (b), wie das Mapping von Platzhaltern auf das Datenmodell zu erfolgen hat. Die beiden Dinge haben miteinander nichts zu tun. Eine UiComponent, die ein variables Layout hat, sollte ein Property "layoutType" oder so haben, mit Werten wie 'default' oder 'threeItems'. Wird dieses Property falsch bestückt, ist das Werfen eines Errors durchaus angebracht, das ist ein Programmierfehler und kein Userfehler. Beim Mapping vermengst Du das Symbol aus dem Template mit der Art der Aufbereitung zu einem unheiligen Konglomerat. Als Key hast Du das Templatesymbol, ein _ und dann "key" oder "keyValue". Dein Mapping sollte mit Pfeilfunktionen arbeiten, die für jedes Symbol im Template die Aufbereitung liefern. Der replacePlaceHolder muss auch keine this-Eigenschaft sein, denn er wird pro Schleifendurchlauf neu erzeugt. Das kann eine anonyme Funktion werden.

        cFeed.template = {
           name:'default',
           title: o => o.Titel,
           item1: o => 'Genre' 
        };
        

        und

          readArrObjects(arrObjData){
            
            let generatedTemplate = '';
            
            for(let arrObjDataElement of arrObjData) {
              // Look Ma, it's a one-liner!
              let replacer = 
                 (match, p1, offset, string) => 
                     p1 in this.objTemplate ? (this.objTemplate[p1])(arrObjDataElement) : `??${p1}??`;
              
              let templateGetData = this.template.child.replace(/%([^%]*)%/g, replacer);
              
              generatedTemplate += templateGetData;
        
            }
            generatedTemplate = `<${this.template.parent}>${generatedTemplate}</${this.template.parent}>`; 
            this.render(generatedTemplate);
            console.log('generatedTemplate: ',generatedTemplate);
            return generatedTemplate;
          }
        

        Wenn Du hypermodern sein willst, kannst Du den Replacer-Callback mit Hilfe von optional chaining und nullish coalescing so umschreiben:

              let replacer = 
                 (match, p1, offset, string) => this.objTemplate[p1]?.(arrObjDataElement) ?? `##${p1}##`
        

        Aber das ist nur ein Schritt von vielen. Du bist ja schon darüber gestolpert, dass Du in arrMovies ein Array von Objekten mappen willst, und in objFilter ein Objekt, dessen Properties Werte enthalten. Das arrMovies Array hat einen entscheidenden Designfehler: Es enthält Properties, die eigentlich Arrays sein möchten (Genre, Tags), die Du aber als String mit Komma drin realisiert hast. Ein korrekter Mapper muss das lösen können, und nun bist Du auf dem Weg zum MVVM Prinzip (Model, View, ViewModel).

        Bevor Du viel weiterexperimentierst - schau Dir einmal knockout.js an. Zumindest, um Konzepte kennenzulernen. Ob Du dann bei knockout bleibst, eine andere MVVM Lib suchst oder deine eigene schreiben willst, ist Dir überlassen. Das schöne an knockout ist das Einstiegstutorial, dass dich Schritt für Schritt an die Ideen heranführt.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. problematische Seite

          Hallo Rolf,

          vielen Dank für die Tipps. Ich muss das nochmal in Ruhe nachvollziehen. Ich habe es gerade erst gelesen und in der Zwischenzeit weiter dran gearbeitet: https://codepen.io/ebody/pen/MWEwodg

          arrMovies[] passt so. Das sind Zelleninhalte aus einem Google Sheet. Genre und Tags könnten auch Sätze oder anderes enthalten.

          Die jeweilige Komponente liefert jeweils ihr eigenes Template/Layout. In dem Beispiel ist es nur eine Komponente. Aber nach dem Prinzip sollen weitere folgen.

          Gruß ebody

          1. problematische Seite

            Hallo ebody,

            arrMovies[] passt so. Das sind Zelleninhalte aus einem Google Sheet. Genre und Tags könnten auch Sätze oder anderes enthalten.

            Aus meiner Sicht passt das für ein Datenmodell überhaupt nicht. Genres und Tags sind Objekte, die in einer 1:N Beziehung zum Film stehen. Wie willst Du nach Genres filtern, wenn die Genres in einem kommaseparierten String stehen oder dort sogar "Sätze" geschrieben sein könnten? Einen kommaseparierten String kann man, wenn die Daten aus einem Spreadsheet kommen, mit der split-Methode und einer Regex als Delimter aufteilen:

            let arrGenres = genres.split(/\s*(?:,\s*)+/)
            

            "Sätze" sollten anderswo stehen. Eine Liste von Genres und Tags passt mit "Sätze" nicht zusammen. Sinnvolle Datenverarbeitung erfordert ein sinnvolles Datenmodell - was Du beschreibst, ist ein Notizzettel, der für einen Menschen problemlos zu verarbeiten ist, für eine Maschine aber kaum bis gar nicht.

            Die jeweilige Komponente liefert jeweils ihr eigenes Template/Layout.

            Ein HTML Template im JavaScript, so langsam klingt das nach React (womit ich keine eigene Erfahrung habe) und JSX. Statt Knockout solltest Du Dir vielleicht doch mal den großen Bruder angucken.

            Rolf

            --
            sumpsi - posui - obstruxi