Chrillewoodz
Chrillewoodz

Reputation: 28368

How to access parent component value from child component without passing it via an input?

I'm making an email modal but I'm having problems actually making the http.post request. The problem is that post() is being executed in a child component which means that this.postUrl is undefined when the function actually runs. How can I make sure that the child component has access to this.postUrl without passing it to it as an input? The reason as to why I don't want to pass it with an input is that the child component is also used in other places, making the postUrl too specific to use as an input since it will only be used in this scenario.

@Component({
  selector: 'modal-email',
  templateUrl: './app/assets/scripts/modules/modal/templates/modal-email/modal-email.component.html',
  styleUrls: ['./app/assets/scripts/modules/modal/templates/modal-email/modal-email.component.css'],
  inputs: [
    'model',
    'postUrl',
    'header',
    'text'
  ],
  directives: [FormInputWithButtonComponent],
  providers: [Http, HTTP_PROVIDERS]
})

export class ModalEmailComponent {

  constructor(private _http: Http) {

  }

  post() {

    // this.postUrl becomes undefined, this.model is defined since it also lives in the child component
    console.log(this.postUrl, this.model);

    this._http.post(this.postUrl, {email: this.model})
      .map(res => res.json())
      .subscribe(
        data => this.data = data,
        err => console.log(err)
      )
  }
}

ModalEmailComponent is being used like this:

<modal-email postUrl="localhost:3000/email"></modal-email>

Inside the modal-email lies form-input-with-button> component:

<form-input-with-button [(model)]="email" type="email" [onSubmit]="post"></form-input-with-button>

Child component:

@Component({
  selector: 'form-input-with-button',
  templateUrl: './app/assets/scripts/modules/form-controls/form-input-with-button/form-input-with-button.component.html',
  styleUrls: ['./app/assets/scripts/modules/form-controls/form-input-with-button/form-input-with-button.component.css'],
  inputs: [
    'model',
    'onSubmit' // onSubmit is what calls the post function from ModalEmailComponent
  ],
  host: {
    '(input)': 'modelChange.emit($event.target.value)'
  }
})

export class FormInputWithButtonComponent {
  @Input() model: string;
  @Output() modelChange: EventEmitter = new EventEmitter();
}

FormInputWithButtonComponent template:

<input [(ngModel)]="model" class="form-input-with-button">
<button (click)="onSubmit()" class="form-input-button">Submit</button>

EDIT: Can you extend components? Something like:

export class FormInputWithButtonComponent extends ModalEmailComponent

When I tried it said Cannot read property prototype of undefined which makes me think that this is not possible.

Upvotes: 1

Views: 2461

Answers (2)

Turdaliev Nursultan
Turdaliev Nursultan

Reputation: 2576

Actually, you can inject parent component properties, values from your child component without using any services or inputs.

First, you need to inject Injector from a constructor in a child component:

    export class ChildComponent implements OnInit {

        constructor(public injector:Injector) {
        }

        ngOnInit() {
            let parentComponent = this.injector.get(ParentComponent);
            this.postUrl = parentComponent.
        }
    }

Imports

import {Injector} from "angular2/core";
import {OnInit} from "angular2/core";

Upvotes: 5

uksz
uksz

Reputation: 18719

What I suggest you to do, is to create one Service, where you would store the value of the postUrl, so that it would be accessible in the child. On the other hand, you can use Event Emitter, and set it as follows:

In ChildComponent:

onSubmit(){
  EventEmit.emit('get')    
}

EventEmit.subscribe(msg=>{
  http.post(msg)
})

And in the parent:

EventEmit.subscribe(msg=>

if (msg == 'get') EventEmit.emit(this.postUrl)

);

Of course, thats just pseudo code, so you would need to adjust it to your needs.

Upvotes: 0

Related Questions