0

i'm relatively new to learning Angular and have followed some instructions from a PluralSight demo on setting up a basic service, component and HTML page.

When I run my service and debug, I can see that the service is successful in retrieving the data I need. However, part of the HTML doesn't seem to go through change detection. The date attribute I display does this successfully, however my array just gets ignored.

I've tried explicitly creating a separate array and assigning to a different variable, which also didn't work. Is there something around the ngModel and change detection I am missing?

Service:

@Injectable({
  providedIn: 'root'
})
export class RankingService {
  private rankingUrl = 'https://localhost:44381/api/Ranking'

  constructor(private http: HttpClient) { }

  getRanking(): Observable<IRanking> {
    return this.http.get<IRanking>(this.rankingUrl)
      .pipe(
        tap(data => console.log('All: ' + JSON.stringify(data))),
        catchError(this.handleError)
      );
  }

HTML:

<div class='row'>
  {{'Last Updated: ' + ranking?.startDateTime}}
</div>
<table class='table' *ngIf='ranking'>
  <thead>
    <tr>
      <th>Rank</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor='let position of ranking.rankpositions?.slice(0,30)'>
      <td>
        {{ position.Rank }}
      </td>
    </tr>
  </tbody>
</table>

Component:

export class RankingListComponent implements OnInit {
  errorMessage = '';
  ranking: IRanking;

  constructor(private rankingService: RankingService) { }

  ngOnInit(): void {
    this.rankingService.getRanking().subscribe({
      next: ranking => {
        this.ranking = ranking;
      },
      error: err => this.errorMessage = err
    });
  }

}

IRanking is an interface, with an array of rankPositions (Which represents another Interface).

As an output I get this (I've removed some HTML elements, to make the code segment smaller):

enter image description here

In the console, I clearly have the rankpositions array populated: enter image description here

5
  • Please try this.ranking = JSON.parse(JSON.stringify(ranking)). Commented Sep 3, 2020 at 13:24
  • Tried, but no joy. From watching this.ranking in debug mode, it gets mapped without any issues. Commented Sep 3, 2020 at 13:41
  • Instead of subscribing in the component, try to use async pipe. That should most probably solve the issue. Looks like the references aren't updated. Commented Sep 3, 2020 at 13:49
  • Could you share the console log, code appears to be okay, and from the Last Updated value, it seems to be working. The problem might be the line let position of ranking.rankpositions. Commented Sep 3, 2020 at 16:29
  • The only console error is: sockjs.js:1684 WebSocket connection to 'wss://localhost:44381/sockjs-node/148/mj40ffub/websocket' failed: Error during WebSocket handshake: 'Connection' header is missing Commented Sep 3, 2020 at 16:52

2 Answers 2

1

Please change rankpositions to rankPositions

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Wasn't aware Angular was case sensitive.
1

you've got a typo, so this should be closed.

but beyond that, running functions like that in template is pretty much always going to cause you change detection problems. use the slice pipe instead here for a quick fix:

<tr *ngFor='let position of ranking.rankPositions | slice:0:30'>

a better fix IMO would be switching to async pipe and using rx operators to run your slice.

a general angular best practice is to not run functions in templates, use pipes when appropriate, but generally your functions should be running in your component controller.

1 Comment

Thanks for the advice

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.