3

I'm using Github API to built a Repositories Viewer. I'm taking repo.name as an input for another variable and passing it as a parameter to a function which indeed calls to get the Languages used as in a repository.

The problem is that it not displaying individual set of languages for a repository, it's looping them all and running infinitely.

HTML File

 <div class="user-repos">
    <ul id="repos" *ngFor="let repo of repos | paginate:{ id:'listing_repos',itemsPerPage:10, currentPage:page, totalItems:totalRecords}">
      <li>
        <h4>{{ repo.name | uppercase}}</h4>
        <p>{{ repo.description }}</p>
          <ul *ngFor="let lang of languagesUsed(repo.name)">
              <li>{{lang}}</li>
          </ul>
      </li>
    </ul>
  </div>

Component.ts file for the same

export class UserComponentComponent implements OnInit {

  @Input() username:any;
  
  constructor(private githubUser:UserDataService) { }
  repos:Array<any> = [];
  avatar:any;
  name:String = '';
  location:String = '';
  bio:String = '';
  twitter:String = ''; 
  github:String = '';
  totalRecords = 0;
  page = 1;
  langs:Array<any> = [];
  

  getUser(){
    this.githubUser.getData(this.username).subscribe((data)=>{
        //console.log(data);

        this.avatar = data.avatar_url;
        this.name = data.name;
        this.location = data.location;
        this.bio = data.bio;
        this.twitter = `https://twitter.com/${data.twitter_username}`;
        this.github = `https://github.com/${data.login}`;
    })
  }

  getRepos(){
    this.githubUser.getRepositories(this.username).subscribe((repos)=>{
        this.repos = repos;
        this.totalRecords = repos?.length;
        // this.languagesUsed = Object.keys(repos.languages_url);
    })
  }

  languagesUsed(repoName:any){
      this.githubUser.getLanguages(this.username, repoName).subscribe((languages)=>{
        // console.log(Object.keys(languages));
        this.langs = Array.from(Object.keys(languages));
      })
      return this.langs;
    }

    ngOnInit(): any{
      this.getUser();
      this.getRepos();
    }

  }

Service.ts for fetching the API's

export class UserDataService {

  constructor(private http:HttpClient) {}

  getData(username:String):Observable<any>{

    let user = `https://api.github.com/users/${username}`;
    return this.http.get(user);
  }

  getRepositories(username:String):Observable<any>{
    let repos = `https://api.github.com/users/${username}/repos`;
    return this.http.get(repos);
  }

  getLanguages(username:String, repo:String):Observable<any>{
    let languages = `https://api.github.com/repos/${username}/${repo}/languages`;
    return this.http.get(languages);
  }
}
2
  • Can you please show us a code here? It is just unclear, to think about it in a theoretical perspective Commented Aug 13, 2022 at 5:41
  • @PankajParkar I have added the code, please have a check. Commented Aug 13, 2022 at 5:46

1 Answer 1

1

This issue is caused because of languagesUsed function, couple of problems with it

  1. Used as a binding languagesUsed()
  2. Due to the async call, returned value this.langs won't be the right value.
  3. On each iteration, it will make an ajax call. This is causing an infinite loop

To fix this, you move the fetch languages logic as a serial operation (switchMap) on the observable level. As soon as you received a specific repo, make another call to bring the languages for that user. Thereafter extend the repo object with the languages array received.

Something like below

// after receiving the repos, 
const allRepoWithLanguages = repos.map(repo => 
  // loop over them and make a `getLanguages` ajax call
  this.githubUser.getLanguages(this.username, repo.name)
  .pipe(
     // extend repo with languages
     map(languages => ({...repo, languages }))
  )
);

Let's extend the logic just we've seen into actual implementation.

TS

getRepos(){
    this.githubUser.getRepositories(this.username).pipe(
      switchMap(repos => {
         const allRepoWithLanguages = repos.map(repo => 
            this.githubUser.getLanguages(this.username, repo.name)
            .pipe(
               // amending repo with languages
               map(languages => ({...repo, languages }))
            )
         );
         return forkJoin(allRepoWithLanguages);
      }),
    ).subscribe((repos)=>{
        this.repos = repos;
        this.totalRecords = repos?.length;
    })
}

HTML

<div class="user-repos">
   <ul id="repos" *ngFor="let repo of repos | paginate:{ id:'listing_repos',itemsPerPage:10, currentPage:page, totalItems:totalRecords}">
      <li>
        <h4>{{ repo.name | uppercase}}</h4>
        <p>{{ repo.description }}</p>
          <ul *ngFor="let lang of repo.languages">
              <li>{{lang}}</li>
          </ul>
      </li>
   </ul>
</div>
Sign up to request clarification or add additional context in comments.

Comments

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.