Angular: Trong đó vòng đời hook là dữ liệu đầu vào có sẵn cho Thành phần


82

Tôi có một thành phần nhận một mảng các imageđối tượng dưới dạng Inputdữ liệu.

export class ImageGalleryComponent {
  @Input() images: Image[];
  selectedImage: Image;
}

Tôi muốn khi thành phần tải selectedImagegiá trị được đặt thành đối tượng đầu tiên của imagesmảng. Tôi đã cố gắng làm điều này trong OnInitmóc vòng đời như thế này:

export class ImageGalleryComponent implements OnInit {
  @Input() images: Image[];
  selectedImage: Image;
  ngOnInit() {
    this.selectedImage = this.images[0];
  }
}

điều này mang lại cho tôi một lỗi Cannot read property '0' of undefinedcó nghĩa là imagesgiá trị không được đặt trong giai đoạn này. Tôi cũng đã thử OnChangeshook nhưng tôi bị mắc kẹt vì tôi không thể lấy thông tin về cách quan sát các thay đổi của một mảng. Làm thế nào tôi có thể đạt được kết quả mong đợi?

Thành phần mẹ trông giống như sau:

@Component({
  selector: 'profile-detail',
  templateUrl: '...',
  styleUrls: [...],
  directives: [ImageGalleryComponent]
})

export class ProfileDetailComponent implements OnInit {
  profile: Profile;
  errorMessage: string;
  images: Image[];
  constructor(private profileService: ProfileService, private   routeParams: RouteParams){}

  ngOnInit() {
    this.getProfile();
  }

  getProfile() {
    let profileId = this.routeParams.get('id');
    this.profileService.getProfile(profileId).subscribe(
    profile => {
     this.profile = profile;
     this.images = profile.images;
     for (var album of profile.albums) {
       this.images = this.images.concat(album.images);
     }
    }, error => this.errorMessage = <any>error
   );
 }
}

Mẫu của thành phần mẹ có cái này

...
<image-gallery [images]="images"></image-gallery>
...

1
imagesDữ liệu được điền như thế nào trong thành phần chính? Tức là nó thông qua (các) yêu cầu http? Nếu vậy, tốt hơn hết bạn nên đăng ký ImageGalleryComponent () vào http có thể quan sát được.
Mark Rajcok

@MarkRajcok imageschỉ là một phần của dữ liệu được sử dụng bởi phụ huynh như thế này {profile: {firstName: "abc", lastName: "xyz", images: [ ... ]}}mà có nghĩa là nếu tôi đăng ký vào đứa trẻ, tôi vẫn sẽ phải đăng ký cho mẹ và tôi muốn tránh sự lặp lại
Optimus Pette

Nếu mảng hình ảnh trong thành phần mẹ được điền khi thành phần con được tạo, thì thuộc tính đầu vào hình ảnh phải được điền trước khi gọi ngOnInit (). Bạn sẽ cần cung cấp thêm thông tin về cách mảng hình ảnh được điền trong thành phần mẹ để bất kỳ ai có thể giúp bạn thêm (hoặc tạo một Plunker tối thiểu hiển thị sự cố).
Mark Rajcok

@MarkRajcok Tôi đã thêm thành phần chính và cách hình ảnh được điền vào đó.
Optimus Pette

2
Vì vậy, có, có vẻ như thành phần mẹ của bạn đang sử dụng http (vì nó đang sử dụng một dịch vụ) để điền thuộc tính hình ảnh của nó. Vì đây là hoạt động không đồng bộ, thuộc tính đầu vào của thành phần con sẽ không được điền vào thời điểm phương thức ngOnInit () của nó được gọi. Di chuyển mã của bạn từ ngOnInit () sang ngOnChanges () và nó sẽ hoạt động.
Mark Rajcok

Câu trả lời:


84

Thuộc tính đầu vào được điền trước khi ngOnInit()được gọi. Tuy nhiên, điều này giả sử thuộc tính mẹ cung cấp thuộc tính đầu vào đã được điền khi thành phần con được tạo.

Trong trường hợp của bạn, đây không phải là trường hợp - dữ liệu hình ảnh đang được điền không đồng bộ từ một dịch vụ (do đó là một yêu cầu http). Do đó, thuộc tính đầu vào sẽ không được điền khi ngOnInit()được gọi.

Để giải quyết vấn đề của bạn, khi dữ liệu được trả về từ máy chủ, hãy gán một mảng mới cho thuộc tính mẹ. Thực hiện ngOnChanges()ở trẻ. ngOnChanges()sẽ được gọi khi phát hiện thay đổi Angular truyền giá trị mảng mới xuống con.


1
Tôi đồng ý với bạn vì bản thân tôi cũng gặp phải vấn đề tương tự. Ngay cả sau khi tôi thực hiện ngOnchanges()trong đứa trẻ, lỗi vẫn xảy Cannot read property '0' of undefinedra. Tuy nhiên, ứng dụng có thể tiếp tục mà không có vấn đề gì. Lỗi này xảy ra vì ban đầu, thuộc tính đầu vào chưa được điền. Nó được điền bởi cuộc gọi lần thứ hai ngOnChanges()khi dữ liệu từ cuộc gọi không đồng bộ được nhận. Đối với trường hợp của tôi, bổ sung cho giải pháp này, tôi đã thêm bảo vệ chống lại toán tử null trong html. Nó rõ ràng đã giải quyết được lỗi.
Thilina Samiddhi

5

Bạn cũng có thể thêm bộ định vị cho hình ảnh của mình, bộ định vị này sẽ được gọi bất cứ khi nào giá trị thay đổi và bạn có thể đặt bộ định vị mặc định trong chính bộ định vị:

export class ImageGalleryComponent {
  private _images: Image[];

  @Input()
  set images(value: Image[]) {
      if (value) { //null check
          this._images = value;
          this.selectedImage = value[0]; //setting default selected image
      }
  }
  get images(): Image[] {
      return this._images;
  }

  selectedImage: Image;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.