1

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: enter image description 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

1 Answer 1

2

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:

  • when your IDE/task runner lints your code
  • when you build your code

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 @Inputs 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.

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

7 Comments

Thank you for the answer, you're totally right about the private variables. However, about the question itself, I'm trying to identify all variables ( even the undefined ones ) in order to add the correspondent values, but I want to avoid creating new variables if they do not exist in the component. In order to do that I have to check that they exist and right now an undefined variable just does not exist in the instance or I don't know how to access it.
If by "creating" new variables you mean just randomly assigning a new property to the component instance - the TypeScript compiler/linter won't allow you to do that. If you want to somehow get a list of all class properties that have not been assigned any values after component initialization, you can manually traverse all public properties on ngOnInit() and add them to a public class list if they have no values. After that, you will be able to access that list and you can reference those properties.
Also, if you want to make sure that you can assign a value to a property only once, you can make use of getters and setters - when you define the set function, you can assign the value to a private variable only if hasn't been assigned one yet.
Basically I have a dynamic component loader which renders components after runtime and when I assign the input values I want to check if they are present, so you can't add new properties to the rendered component. I can edit the question and add more info if you want, anyways you're being so helpful and i want to thank you :)
Could you please edit your question with more details?
|

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.