I am trying to generate dynamic forms based on a set of questions I receive from an API.
When the app inits I will dispatch a state action that will call the mock API to get the questions and then the questions are stored in state (https://ngxs.io - however state seems to not work in stackblitz so I just had them set statically in app component).
Then I will give those questions to the Section component.
The Section component then turns the array of questions into a Custom Form Group and each question is turned into a Custom Form Control.
the Section component uses a @for loop to iterate over the controls of the form group and turns them into a Control Component.
The Control Component uses the ng-content tag to dynamically render each control.
The main thing that I'm trying to accomplish is to have dynamic Date Formats by dynamically injecting MAT_DATE_FORMATS into the component when we are rendering a Date Field. However I keep running into the following error:

What I've tried
To get the dynamic date formats I've tried updating the MAT_DATE_FORMATS in the Date Field component.
formats = inject(MAT_DATE_FORMATS);
constructor() {
super();
afterNextRender(() => {
const format = this.control().question.dateFormat;
if (format) {
this.formats.display.dateInput = format;
this.formats.parse.dateInput = format;
}
});
}
However, if there were multiple date fields in the Questions array then the last date field format would override all the other date fields. That is what led me to try and render the components dynamically using ng-content.
I have a stackblitz to re-create the issue (the README also has links to the places in the code that are important). https://stackblitz.com/~/github.com/shadow1349/dynamic-form-issue-recreation
EDIT: Sorry stackblitz is being weird, if you click the link it gives a 404 but if you copy/paste that link into the browser it should take you to the correct codebase.
Thank you!
Since you are using a method to get the injectorRef and the component directly on the HTML.
During each change detection cycle of Angular. The methods are evaluated again and again, hence you are getting this weird rendering problem.
Instead use computed to derive the component and injector based on the control passed, so that they can set on the HTML, just once.
@Component({
selector: 'app-control',
...
})
export class Control {
private injector = inject(Injector);
control = input.required<CustomFormControl>();
component = computed(() => this.getControl()); // <- changed here!
injectorRef = computed(() => this.getInjector()); // <- changed here!
Then use these value on the HTML.
@let formControl = control();
@let injectorRefVal = injectorRef();
@let componentRef = component();
@if(componentRef && injectorRefVal) {
<ng-content
*ngComponentOutlet="
componentRef;
inputs: { control: formControl };
injector: injectorRefVal
"
></ng-content>
}