1

I need to create a parent component, which encapsulates some ui-logic (in component.ts) as well as some template logic (component.html) for some child components.

For template inheritance we use ng-content, and the htmls look like this:

app.component.html:

<parent [parentsInput]='X'>
   <child1></child1>
</parent>

<parent [parentsInput]='Y'>
   <child2></child2>
</parent>

<parent [parentsInput]='Z'>
   <child3></child3>
</parent>

parent.component.html

<div>
  ... {{parentsInput}}
</div>

<ng-content></ng-content>   <!-- dynamic content where child templates are injected -->

<div>
  ... {{parentsInput}}
</div>

child.component.html

<div>
   ... {{parentsInput}}
</div>

And i also define the parentComponent as "parent" of child like this:

export class ChildComponent extends ParentComponent

So, what I have now: The html is rendered correctly, so i really see in browser that the child template is contained within the parents template in correct position.

But the problem is: Child component cannot access the parent's attributes (i.e. parentsInput). In Webstorm it actually looks good, you click on the attribute name from child component, and you are navigated to parent component where the attribute is actually defined. But it somehow does not work in Browser. How can we achieve this, so that the child components can use the parents attributes as their own attributes?

PS: i have figured out that we can inject the parent component as a dependency (sth. like @Inject(ParentComponent) parent: ParentComponent in constructor) and access the attributes, but this is not what i want since our child components may read & modify many attribute, i do not want to read all attributes separately. I would like to have an "inheritance".

2 Answers 2

2

This is not as simple as it looks. There is NO WAY(according to my knowledge) that you can implement what you want.

If I have understood it correctly then probably you want to access parent instance within child component without using @Inject(ParentComponent).

Since you are using ng-content or content project concept, I can think of following way,

Parent.component.ts

 export class ParentComponent  {
    
        @ContentChild (ChildComponent) child: ChildComponent;  // access child in parent using ContentChild
        
        @Input() parentsInput;
        
        ngAfterContentInit(){
           this.child.accessParent(this);                      // calling child function and passing parent's `this` context
        }
    
    }

child.component.ts

 export class ChildComponent{

       parentInstance: ParentComponent;

       // This is the main area or magical area

       accessParent(instance:any){

          this.parentInstance = instance;

       }
   
    }

child.component.html

{{parentInstance.parentsInput}}

DEMO


This way you'll be able to access parent's context in child component. Now, you can access all the objects or properties of the parent component in child.

In DEMO, I'm using only child component but of course you can use child1, child2 & so on.

I hope this will be helpful.

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

3 Comments

thank you. Do you think this is better in any way than my first approach with "@Inject(ParentComponent)"? The real reason why i didn't want to use dependency was the effort of reading/writing values separately instead of having them in the same context. But in your approach don't I have the same problem?
Btw. i don't need to access child attributes from parent, it is just one way from child to parent. So i think the approach with constructor(public parent: ParentComponent) gives me the same endresult, with fewer code..
Both are valid scenarios. Through @Inject, you are injecting parent into child forcefully to read it (using DI-Dependency Injection). My approach does the same gracefully (without DI, using contentChild API). You just have to check which is smooth and convenient for your scenarios. Good Luck !
0

I think you were on the right track with the inject, but you should probably use some javascript ...spread magic to make life easier if you intend to manipulate lots of values:

If you want to set the values you could do something along the lines of myChildComponentValue = {...parentComponent} (assuming you wanted them to vary, but I assume you would want them to stay up to date with the parent component).

Here is a stackblitz I spun up https://stackblitz.com/edit/angular-ivy-42q7yq using the @inject to get the instance combined with the spread operator is pretty powerful. If you wanted to make things somewhat less verbose in a larger context you could have an appay of properties that you modify and push to a method that would do the update, and set the array on init.

Hope this helps some, Keep us posted!

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.