0

I'm new in programming especially in Angular and I'd appreciate it if someone help me with my code, please.

I'm trying to get some images from a web API in the angular project.

  • ASP.NET Framework Web API 4.7
  • Angular CLI: 13.3.7
  • Angular: 13.3.11

Web API side:

Controller:

[EnableCors(origins: "*", headers: "*", methods: "*")]
public class HomeController : ApiController
{
    private NavEcommerceDBfirstEntities db = new NavEcommerceDBfirstEntities();
    public HomeModel Get()
    {
        var streetBikes = db.Motorcycles
            .Where(m => m.Category.MotoCategory == "Street")
            .Select(m => new MotorcycleImgDTO
            {
                Image = m.Image
            });
        var sportBikes = db.Motorcycles
            .Where(m => m.Category.MotoCategory == "Sport")
            .Select(m => new MotorcycleImgDTO
            {
                Image = m.Image
            });
        var adventureBikes = db.Motorcycles
            .Where(m => m.Category.MotoCategory == "Adventure")
            .Select(m => new MotorcycleImgDTO
            {
                Image = m.Image
            });
        var scooterBikes = db.Motorcycles
            .Where(m => m.Category.MotoCategory == "Scooter")
            .Select(m => new MotorcycleImgDTO
            {
                Image = m.Image
            });
        var homeModel = new HomeModel
        {
            SportBikes = sportBikes,
            StreetBikes = streetBikes,
            AdventureBikes = adventureBikes,
            ScooterBikes = scooterBikes
        };

        return homeModel;
    }

}

Models:

HomeModel class:

public class HomeModel
{
    public IEnumerable<MotorcycleImgDTO> StreetBikes { get; set; }
    public IEnumerable<MotorcycleImgDTO> SportBikes { get; set; }
    public IEnumerable<MotorcycleImgDTO> AdventureBikes { get; set; }
    public IEnumerable<MotorcycleImgDTO> ScooterBikes { get; set; }

}

Motorcycle class:

//Database First Approach and Created by ADO.NET 
public partial class Motorcycle
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Motorcycle()
    {
        this.Carts = new HashSet<Cart>();
        this.OrderDetails = new HashSet<OrderDetail>();
        this.Dealers = new HashSet<Dealer>();
    }

    public int MotorcycleId { get; set; }
    public string Model { get; set; }
    public double Price { get; set; }
    public Nullable<int> BrandId { get; set; }
    public byte[] Image { get; set; }
    public Nullable<int> CategoryId { get; set; }

    public virtual Brand Brand { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Cart> Carts { get; set; }
    public virtual Category Category { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<OrderDetail> OrderDetails { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Dealer> Dealers { get; set; }
}

DTO class:

public class MotorcycleImgDTO
{
    public byte[] Image { get; set; }
}

Angular side:

Model:

home-categorised-bikes.model.ts:

export interface FromDTOImgs{
    image: Byte[];
}

export interface HomeModel{
  sportBikes: FromDTOImgs[];
  streetBikes: FromDTOImgs[]; 
  adventureBikes: FromDTOImgs[];
  scooterBikes: FromDTOImgs[];
}

Service:

home-categorised-bikes.service.ts:

@Injectable({
  providedIn: 'root'
})
export class HomeCategorisedBikesService {

  imageUrl = 'https://localhost:44377/api/Home';

  constructor(private http: HttpClient) { }

  getImg(): Observable<HomeModel[]> {
    return this.http.get<HomeModel[]>(this.imageUrl);
  }
}

app.component.ts:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'angular-UI';

  constructor(private homeCategorisedBikesService: HomeCategorisedBikesService) {}

  ngOnInit(): void {
    this.getAllBikesImgs();
  }

  getAllBikesImgs() {
    this.homeCategorisedBikesService.getImg().subscribe(
      Response => {
        this.onHomeBikesImgsResponse(Response);
        console.log(Response);
      }  
    )
  }

  public bikesImgs: string[] = [];
  private onHomeBikesImgsResponse(Response: HomeModel[]): void {
    Response.forEach((img: HomeModel) => {
      this.bikesImgs.push(`data:image/png;base64,${img.sportBikes}`);
      this.bikesImgs.push(`data:image/png;base64,${img.streetBikes}`);
      this.bikesImgs.push(`data:image/png;base64,${img.adventureBikes}`);
      this.bikesImgs.push(`data:image/png;base64,${img.scooterBikes}`);
    });
  }
}

app.component.html:

<div class="container">
    <h4>{{title}}</h4>

    <div *ngFor="let bikeImg of bikesImgs">
        <img [src]="bikeImg">
    </div>

Swagger:

Swagger response

Error:

Response.forEach is not a function at AppComponent.onHomeBikesImgsResponse (app.component.ts)

Thank you in advance.

Yong Shun
  • 35,286
  • 4
  • 24
  • 46
Navid
  • 45
  • 6
  • 2
    Please consider working to provide a self-contained [mre] that clearly demonstrates the issue you are facing when pasted into a standalone IDE. Presumably the actual response from `imgUrl` is not an array, but it's very hard or maybe impossible for anyone other than you to determine that. If you provide a [mre] then others can help more. Good luck! – jcalz Jul 05 '22 at 12:54
  • 1
    For debugging reasons it is important to know what value `Response` contains. Presumably, as already noted, it might not actually be an array. –  Jul 05 '22 at 12:57

2 Answers2

1

Your API returns response with HomeModel type, but not HomeModel array.

home-categorised-bikes.service.ts:

export class HomeCategorisedBikesService {

  imageUrl = 'https://localhost:44377/api/Home';

  constructor(private http: HttpClient) { }

  getImg(): Observable<HomeModel> {
    return this.http.get<HomeModel>(this.imageUrl);
  }
}

app.component.ts:

private onHomeBikesImgsResponse(Response: HomeModel): void {
  Response.sportBikes.forEach((img: FromDTOImgs) => {
    this.bikesImgs.push(`data:image/png;base64,${img.image}`);
  });

  Response.streetBikes.forEach((img: FromDTOImgs) => {
    this.bikesImgs.push(`data:image/png;base64,${img.image}`);
  });

  Response.adventureBikes.forEach((img: FromDTOImgs) => {
    this.bikesImgs.push(`data:image/png;base64,${img.image}`);
  });

  Response.scooterBikes.forEach((img: FromDTOImgs) => {
    this.bikesImgs.push(`data:image/png;base64,${img.image}`);
  });
}
Yong Shun
  • 35,286
  • 4
  • 24
  • 46
  • Hi Yong Shun, Thank you for the code indeed. I have modified my project with your suggested code and it is working properly now, however, I would like to use a for loop instead of multiple forEach method. I have also tried Nehal's suggested code, however, I got an error which is: (parameter) Response: HomeModel Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HomeModel'. No index signature with a parameter of type 'string' was found on type 'HomeModel'. – Navid Jul 05 '22 at 16:28
  • For your new issue, I think this [question](https://stackoverflow.com/q/57438198/8017690) is what you need. – Yong Shun Jul 06 '22 at 01:05
1

As you can see in your own swagger screenshot, your response in not an array, it's a list of objects streetBikes, sportBikes.... Each of those objects are list of arrays.

To loop through each property and to create one single array of all bike images, you need something like this:

private onHomeBikesImgsResponse(Response: any): void {
  for (const prop in Response) {
    Response[prop].forEach((item: FromDTOImgs) => {
      this.bikesImgs.push(`data:image/png;base64,${item.image}`);
  });
}

Navid
  • 45
  • 6
Nehal
  • 13,130
  • 4
  • 43
  • 59
  • Hi Nehal, Thank you for your solution indeed. I have copied and pasted your code into my project and the error is gone, however, I am encountering a new error now. (parameter) Response: HomeModel Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HomeModel'. No index signature with a parameter of type 'string' was found on type 'HomeModel'. – Navid Jul 05 '22 at 16:20
  • 1
    Hi @Nehal, I solved the error by editing the Response type to any like this: (Response: any). Now I am getting the images to the browser. Thank you. – Navid Jul 06 '22 at 01:09
  • Thanks, I have updated the answer per your feedback. – Nehal Jul 06 '22 at 11:13