Marl
Marl

Reputation: 9

Angular: Eventhandling Problems with JS generated Code OR not being able to add classes to HTML generated Code with *ngfor

My problem is the following:

I have stations I want to display inside a modal window, whereas the already selected Stations should be coloured blue and the not selected ones should be gray. All stations are in an array called "allStations" and the already selected stations are in "currentStations".

However, I have multiple problems with this:

First off: I either generate this in HTML with a *for loop, then I have the problem, that I am not able to assign the classes that should colour each one.

<jw-modal id="ov_stations">
 <div id="allstationsdiv">
   <p *ngFor="let st of allStations" id="{{ st.id }}" class="notselected"(click)="onstationclick({{st.id}})"> 
       {{ st.name }}
   </p>
 </div>
 <span (click)="closemodal()"><img src="../../../../assets/icons/x.png" alt=""></span>
</jw-modal>

I tried to solve this by generating the HTML inside the openmodal() function, which opens the modal in the first place instead of directly in the HTML:

openmodal(){
    this.modalService.open("ov_stations");

    let output = document.getElementById("allstationsdiv");
    let dealtwith = [];

    if (output.childElementCount == 0){
      for (var i = 0; i < this.allStations.length; i++){
        if (this.currentStations.length == 0)
          output.innerHTML += "<p id='" + this.allStations[i].id + "' class='notselected' (click)='onstationclick(" + this.allStations[i].id + ")'>" + this.allStations[i].name + "</p>";
        else {
          // noch weiter testen
          for (var j = 0; j < this.currentStations.length; j++){
            if (this.currentStations[j].id == this.allStations[i].id){
              output.innerHTML += "<p id='" + this.allStations[i].id + "' class='selected' (click)='onstationclick(" + this.allStations[i].id + ")'>" + this.allStations[i].name + "</p>";
              dealtwith.push(this.allStations[i].id);
              // console.log("selected: " + this.allStations[i].id + " and dealt with: " + dealtwith[i]);
            } // && this.allStations[i].id != dealtwith[i]
            else if (this.currentStations[j].id != this.allStations[i].id){
              output.innerHTML += "<p id='" + this.allStations[i].id + "' class='notselected' (click)='onstationclick(" + this.allStations[i].id + ")'>" + this.allStations[i].name + "</p>";
              dealtwith.push(this.allStations[i].id);
              // console.log("notselected: " + this.allStations[i].id + " and dealt with: " + dealtwith[i]);
            }
            console.log(dealtwith);
            console.log(this.allStations[i].id);
          }
        }
      }
    }
  }

(I am aware that the loop doesn't work yet, but that is not my immediate concern)

However, now, when I try to click on a Station to access the function which would change it's class, it does not work anymore, the function is not called upon. I am guessing that this is because I now generate the code inside JS instead of from HTML.

How can I solve this problem? Is there a way to give the p's the correct class with the conditions above? Or is there a way to solve the problem of not being able to get a click function to work from JS?

I would prefer the latter, but if the first one is easier I am willing to try that too. Thank you very much for your time.

Upvotes: 0

Views: 45

Answers (1)

manos_ch
manos_ch

Reputation: 56

Using the ngClass directive (https://angular.io/api/common/NgClass) will get you the outcome you are looking for. For example: in your component.html

 <div id="allstationsdiv">
            <p *ngFor="let st of allStations" 
               [ngClass]="{
                            'selected':isStationSelected(st),
                            'notselected':!isStationSelected(st)
                          }" 
               (click)="onstationclick(st.id)"> 
               {{ st.name }}
           </p>
        </div>

in your component.ts file

export class MyComponent {

  allStations = [
    { id: 1, name: "station 1" },
    { id: 2, name: "station 2" },
    { id: 3, name: "station 3" },
    { id: 4, name: "station 4" },
    { id: 5, name: "station 5" }
  ];
  selStations = [{ id: 3, name: "station 3" }, { id: 4, name: "station 4" }];

  onstationclick(station): void {
    //do something here
  }

   // will check to see if the currentStations array contains the station id you 
   // are passing from the all stations array 
  isStationSelected(station): boolean {
    return this.currentStations.some(st=> st.id === station.id);
  }
}

in your component.css

.selected {
  color: blue
}

.notselected {
  color: grey
}

Generally you should avoid generating html code via js in angular, since you have angular itself to do that.

Upvotes: 1

Related Questions