Search code examples
angularviewchild

Angular 15: Pass data to child component from parent


I'm learning Angular, so forgive me if my terminology isn't quite accurate. I've provided a full version output at the bottom of this post.

This is what I have right now, and it successfully triggers a hard-coded modal. But what I want is for the modal to be an empty vessel such that I can click multiple icons, and the parent component will send the appropriate data object to the modal before it displays.

request-membership.component.html

<ng-container>
    ...
    <span (click)="toggleModal('itemOne')">Icon</div>
    ...
</ng-container>
<app-modal
  #contentModal
  *ngIf="showModal"
  title="This is the title"
  (canceled)="showModal = false">
Show the content to the user.
</app-modal>

request-membership.component.ts

...
@Component({
  selector: 'app-request-membership',
  templateUrl: './request-membership.component.html',
  styleUrls: ['./request-membership.component.scss']
})
export class RequestMembershipComponent implements OnInit {
  constructor(...) { }
  showModal = false;
  data = {
    itemOne: {
      title: 'This is the title for item one',
      content: 'This is the title for item one'
    },
    itemTwo: {
      title: 'This is the title for item one',
      content: 'This is the title for item one'
    },
  };
  ngOnInit() {...}
  toggleModal(element: string) {
    this.showModal = true;
  }
}

content-modal.component.ts

...
@Component({
  selector: 'app-modal',
  templateUrl: './content-modal.component.html',
  styleUrls: ['./content-modal.component.scss']
})
export class AppModalComponent {

  @Input() title: string;
  @Input() bulkContent;

  @Output() canceled = new EventEmitter();

  cancel_click() {
    this.canceled.emit({ canceled: true });
  }
}

I've read dozens of SO and blog posts about this topic. Most of them recommend the use of the ViewChild decorator to get a reference to the modal, then I can pump data into it. Something like this is what I might expect.

request-membership.component.ts

@ViewChild('contentModal') contentModal: ElementRef;

// then within the toggleModal method
this.contentModal.title = this.data[element].title
this.contentModal.content = this.data[element].content    

But when I drop a debugger statement in the toggleModal method I always get undefined when I try to reference this.contentModal.

I've tried referencing contentModal as the specific type of component:

@ViewChild('contentModal') contentModal: AppModalComponent;

I've tried adding {static: true} to the ViewChild declaration

@ViewChild('contentModal', {static: true}) contentModal: ElementRef;

I've tried direct references to the target component:

@ViewChild(AppModalComponent) contentModal: AppModalComponent;

But with all of these the this.contentModal variable is always null. I know I'm likely doing something wrong, but I'm still new enough that I can't figure it out.

Angular CLI: 15.2.9
Node: 21.5.0 (Unsupported)
Package Manager: npm 10.2.4
OS: darwin arm64

Angular: 15.2.2
... animations, cdk, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1502.9
@angular-devkit/build-angular   15.2.4
@angular-devkit/core            15.2.9
@angular-devkit/schematics      15.2.9
@angular/cli                    15.2.9
@schematics/angular             15.2.9
rxjs                            6.6.7
typescript                      4.8.4

Solution

  • when you click on the toggle button showModal set to true and it takes a time to build that modal and add that modal to dom. so your viewchild still is null if you check it immediately. you can see that is true with a settimeout.

    toggleModal(element: string) {
      this.showModal = true;
      setTimeout(() => {
        console.log(this.contentModal);
       }, 100);
    }