0

i have a component named zoomdetails which contains the specific details of a product when i click on the product image the zoomdetails component displays and contains the details of the clicked product

so i m using route and adding the id of the product to the URL

the problem is :

when i load the products arraylist from the service and try to get the product by its id and looping the arraylist an error appears and indicates Cannot read property 'length' of undefined

here is the zoomdetails.component.ts code : (i ve added some log.console comments to see the results)

export class ZoomdetailsComponent implements OnInit {
  x: string="";
produitzoom:IProduct;
produits:IProduct[];
errormessage1 :string ;
currentId : number;

constructor(private _route:ActivatedRoute,private _router:Router,private _productServic:ProductdataService)
{ 
  console.log("Logging the route : " + JSON.stringify(_route.snapshot.params));
  this.currentId = +_route.snapshot.params['id'];
  console.log("Logging the current ID : " + this.currentId)
   this._productServic.getProducts()
    .subscribe(productss => this.produits=productss ,error=>this.errormessage1= <any>error);
    console.log("************************************************************************************")
 
  
}
  
Myspan(){
  
 this._router.navigate(['/']);


}

find (id:number,P:IProduct[]) :IProduct{
  console.log("+++++++DANS FIND ERROR +++++++++++++++++++++++++")
  
  for (let product of P )
   {
      if (product.idpr==id )
      { 
        return product;
      }
   }
}

ngOnInit() {
    console.log("-------------DANS NGONINITTT-------------------------------------------------------------")

    this.produitzoom=this.find(this.currentId,this.produits)
    console.log(this.produitzoom.productName)
    console.log("--------------------------------------------------------------------------")
  
  
}

and this is my zoomdetails component .html

<router-outlet></router-outlet>
<div id="zoom" class="modal">
  
    <!-- Modal content -->
    <div class="modal-content">
    <span class="close" (click)="Myspan()">&times;</span>
    <div class="container">
        <div class="row">
           <div  class="col-md-4 item-photo">
            
            <img  src={{produitzoom.imgUrl}} style="width:360px;height:650px;">
            
          </div>

          <div class="col-md-6" style="border:0px solid rgba(163, 152, 152, 0.856)">
            <span class="pull-right">
            <!-- Datos del vendedor y titulo del producto -->
            <h1>{{produitzoom.productName}}</h1>    
            <h4 style="color:#337ab7"> {{produitzoom.author}} <small style="color:#337ab7">(50 ventes)</small></h4>
      
            <!-- Precios -->
            <h2 class="title-price"><small>Price</small></h2>
            <h3 style="margin-top0px">{{produitzoom.price}} $</h3>
            <br> <br>
      
            <!-- Detalles especificos del producto -->
            <div class="section" style="background:rgb(222, 228, 222);">
              <h5 class="title-attr" >                  
              <div>
                <br>
               {{produitzoom.description}}
              <br> <br>
              </div>
            </h5>  
            </div>
            <br><br> 
            <!-- Botones de compra -->    	
                  <script>
                  console.log("Test of value : " + JSON.stringify(produitzoom))
                  </script>
                    <button class="btn  btn-success right" [routerLink]="['/Authentification',produitzoom]">
                      <span class="glyphicon glyphicon-shopping-cart"></span> Add to Cart
                    </button>	
          </span>                                      
          <br> <br>      <br> <br>                        
            <ul class="menu-items">
            
              <li class="active">Customers Reviews</li>
              
            </ul>
            <div style="width:100%;border-top:1px solid silver">
              <p style="padding:15px;">
                <small>
                Stay connected either on the phone or the Web with the Galaxy S4 I337 from Samsung. With 16 GB of memory and a 4G connection, this phone stores precious photos and video and lets you upload them to a cloud or social network at blinding-fast speed. With a 17-hour operating life from one charge, this phone allows you keep in touch even on the go. 
   
                With its built-in photo editor, the Galaxy S4 allows you to edit photos with the touch of a finger, eliminating extraneous background items. Usable with most carriers, this smartphone is the perfect companion for work or entertainment.
                </small>
              </p>
              
            </div>
          </div>		
        </div>
      </div> 
    </div>
  
    
  </div>

and these are the errors :

Logging the route : {"id":"1"} zoomdetails.component.ts:22 Logging the current ID : 1 zoomdetails.component.ts:25 ************************************************************************************ zoomdetails.component.ts:50 -------------DANS NGONINITTT------------------------------------------------------------- zoomdetails.component.ts:38 +++++++DANS FIND ERROR +++++++++++++++++++++++++ ZoomdetailsComponent_Host.html:1 ERROR TypeError: Cannot read property 'length' of undefined (from the find method )

ERROR TypeError: Cannot read property 'imgUrl' of undefined (from the html file produitzoom.imgurl)

what should i do !

2 Answers 2

1

first, about the imgUrl error, because of the fact that initially produitzoom is undefined, and it gets it's value after an async call, you can change the value of binding to this: [src]="produitzoom? produitzoom.imgUrl : null".

also about the other error, you are calling this.produitzoom=this.find(this.currentId,this.produits) inside your ngOnInit function, but again, bacuase of the fact that the produits is also undefined at the beginning of the component's lifecycle, and gets it's value after an async call. you should move that this.find() call over to the subscribtion's success. something like this:

productss => {
    this.produits=productss;
    this.produitzoom = this.find(this.currentId,this.produits)
}

Note!!

it's also very important and recommended that if you are subscribing to an observable, you unsubscribe it at the end of that component's Lifecycle (inside ngOnDestroy function). otherwise, this would cause memory leeks and untracable errors... you can do that by defining a property for subscription like: productsSubscription: Subscription; dont forget to import Subscription from rxjs/subscription. and then assign the subscription to this property like:

this.productsSubscription = this._productServic.getProducts()
    .subscribe(.....);

and inside ngOnDestroy:

ngOnDestroy(){
    if(this.productsSubscription){
        this.productsSubscription.unsubscribe();
    }
}

have that if there to prevent any undefined-related errors.

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

1 Comment

happy to help. also, you can accept/upvote answer if it's helpful ;)
0

The problem is that you are loading the products in your constructor, which is asynchronous. Then in your ngOnInit function that is called later on you're using the result of those loaded products, but unfortunately they seem to be not loaded yet. Therefore your P array is not existing yet and so you are using an undefined object in a for loop, which is not working.

ngOnInit() {
    console.log("-------------DANS NGONINITTT-------------------------------------------------------------")

    // --> here you use the products from the constructor
    // but they are not loaded yet, because the loading process takes time and is asynchronous
    this.produitzoom=this.find(this.currentId,this.produits)
    console.log(this.produitzoom.productName)
    console.log("--------------------------------------------------------------------------")


}

What you should do is place the loading of your products in the ngOnInit function as well. There you can wait for the result and then call the find function.

nOnInit(){
    // don't subscribe in the constructor, do it in the ngOnInit
    this._productServic.getProducts().subscribe(productss => {
            // now the results are here and you can use them
            this.produits = productss;
            // only then you can call the find function safely
            this.produitzoom = this.find(this.currentId, this.produits)
        }, error => this.errormessage1 = <any>error);
}

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.