Reputation: 1066
I was wondering if there is a way to identify undefined variables inside Angular components via the componentRef
Let me explain a bit. Assume we have a component called contentComponent with some defined variables like this:
export class ContentComponent {
public public_var_without_content: any;
public public_var_with_empty_string: string = "";
public public_var_with_content: any = { foo: 'bar', baz: ['foo', 'bar', 'baz']};
private private_var: any;
private private_var_with_content: string = "foobar";
constructor() { }
}
Basically we have several public and private variables defined, some of them have content and other are undefined.
Now we create dynamically ( or just get the instance of the component ) via the componentFactory API (https://angular.io/api/core/ComponentFactory) like this:
import { ContentComponent } from '.. the route .. ';
... Code
// This is where the component will be rendered in the template
const viewContainerRef = this.componentLoader.viewContainerRef;
viewContainerRef.clear();
var componentRef = viewContainerRef.createComponent<any>(ContentComponent);
const componentInstance = componentRef.instance;
... More code
For now we have generated the component and rendered in the html template, so we are able to see the generated template inside a different component.
However, what if you want to play a little bit with the component, and we want to check if some variable is present in the component, as we saw in the first block of code, we have five declared variables, what if I do a console.log(componentInstance)
?
I only get the variables which have any kind of content, even the private ones ( that is just another question :D ) as you can see here:
So we can see 3 of the 5 variables, I cannot see the undefined variables, and my question is:
Can we get a mapping or something of the defined variables of the component?
EDIT:
When I assign the input values for the component after creating it I want to be able to identify which ones really exists and which ones doesn't exists. So I have a code like this:
// this.component is an object with a reference to the imported
// component itself, to all the params i want to bind (inputs)
// and all the functions I want to trigger when some event is
// triggered ( ouput eventEmitters )
for ( let param of Object.keys(this.component.params) ) {
if (!componentRef.instance[param])
// Here all the variables that are undefined will pass this condition and I only want to pass those that are not defined in the created component
// throw new Error(`The input parameter '${param} does not exist in the component`);
componentRef.instance[param] = this.component.params[param];
}
So basically this is it, I have components ( child-components ) that are loaded by a dynamic component loader which is contained in another component ( component-container ). In base an array of components in the component-container i want to bind all child-component Input variables to the data which is in the component-container array.
And also, if someone knows why the private variables are visible from outside the component would be nice, but I think that's a whole new question.
Edit: Documentation about ComponentRef API: https://angular.io/api/core/ComponentRef
Upvotes: 1
Views: 1224
Reputation: 724
The reason why you don't see properties that don't have assigned values is because Chrome doesn't display them in the dev tools (I guess it's some sort of an optimization). You usually can see them if you expand the object prototype ([[Prototype]]
).
Secondly, the reason why you can inspect class properties marked as private
is because you're viewing the transpiled TypeScript code. The access modifier rules will be applied in two cases:
Both will result in errors if you try to modify private
class properties but this is always before runtime.
Since TypeScript transpiles to plain JavaScript after you build your application, the end result is just a JavaScript object which by default has no "concealed" properties.
Other than that, once you create your component instance, you can assign values to its public properties and/or call its public methods and Angular will reflect those changes.
Edit:
The way you iterate over the instantiated properties will not work, because you do not have a differentiation between @Input
properties and ordinary class members. You already know the type of the component you are creating (i.e, you are creating a new instance of the ChildComponent
class). You already know which properties are @Input
s in that child component - you only need to assign values to them after checking whether they have values.
Let's take this example child class with some @Input
props:
@Component({
//omitted
})
export class ExampleChildComponent {
@Input() input1;
@Input() input2;
@Input() input3 = 'value';
//rest of the code emitted
}
In your parent component where you instantiate ExampleChildComponent
:
if (!this.component.input1) {
this.component.input1 = 'some value';
}
The above check needs to be repeated for each of the inputs of ExampleChildComponent
.
If you need a dynamic list of all @Input
properties of ExampleChildComponent
, you can create one, as shown here: https://stackoverflow.com/a/38655925/17963017 and then you can access it through the parent and assign values accordingly.
Upvotes: 2