question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dynamic standalone component can not resolve FormsModule (probably others from @angular/*)

See original GitHub issue

Which @angular/* package(s) are the source of the bug?

core

Is this a regression?

No

Description

I have a standalone component defined like this:

import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

export const componentMetadata : Component = {
	jit: true,
	standalone: true,
	selector: '<dynamic-component>',
	imports: [
		FormsModule, CommonModule
	],
};
export class DynamicComponent {
	
	public constructor() {}
....
}

Then I have component that should create dynamically, as a child, this component, with template that is coming from DB. Sample code:

import ....

@Component({
	standalone: true,
	selector: '<container-component>',
	template: '<ng-container #content></ng-container>',
	providers: [ {
		provide: NG_VALUE_ACCESSOR,
		useExisting: forwardRef(() => ContainerComponent),
		multi: true
	}],
})

export class ContainerComponent implements OnInit, OnDestroy, ControlValueAccessor {
.....
    @ViewChild('content', { read: ViewContainerRef, static: true })
    contentContainer: ViewContainerRef;
.....
    private async createContent() {
	this.cleanComponentRef();
	const component = await this.setupContentComponent(this.content); // we have content when we reach this method
	this.componentRef = this.contentContainer.createComponent(component, {
		injector: this.contentContainer.injector,
	});
    }

    private async setupContentComponent(content: string = '') {
	const defs = await import('./dynamic.component');
	const currentMeta = { ...defs.componentMetadata };
	currentMeta.template = content;

	return Component(currentMeta)(defs.DynamicComponent);
    }

    private cleanComponentRef() {
	if (this.componentRef) {
	    this.componentRef.destroy();
	    delete this.componentRef;
        }
    }
}

The content is angular template with directives like ngModel. The problem is that i get a lot of Can't bind to 'ngModel' since it isn't a known property of...., but Forms module is imported in the dynamic component and should be compiled properly (IMO)

During investigation I reached a function in core.mjs function getStandaloneDefFunctions(type, imports) { when checking for exported directives in this code:

if (!!getNgModuleDef(dep)) {
  const scope = transitiveScopesFor(dep);
  for (const dir of scope.exported.directives) {

dep (FormsModule) doesn’t have any exported members

scope { “schemas”: null, “compilation”: { “directives”: {}, “pipes”: {} }, “exported”: { “directives”: {}, “pipes”: {} } }

Please provide a link to a minimal reproduction of the bug

StackBlitz

Please provide the exception or error you saw

NG0303: Can't bind to 'ngModel' since it isn't a known property of

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.2.9
Node: 19.0.1 (Unsupported)
Package Manager: npm 8.19.2 
OS: linux x64

Angular: 14.2.10
... animations, common, compiler, compiler-cli, core, forms
... localize, platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1402.9
@angular-devkit/build-angular   14.2.9
@angular-devkit/core            14.2.9
@angular-devkit/schematics      14.2.9
@angular/cdk                    14.2.7
@angular/cli                    14.2.9
@schematics/angular             14.2.9
rxjs                            7.5.7
typescript                      4.7.4

Anything else?

This is happening when aot: true in angular.json When aot: false, then all is working but then template translations (all tags in .html files having i18n attribute) are not expanded, but all @localize'text' messages are. Probably this is for another issue / discussion

Issue Analytics

  • State:closed
  • Created 10 months ago
  • Comments:17 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
ghost81commented, Nov 22, 2022

I finally succeeded to get hybrid model working.
For our personal case we need not so much - just NgModel, NgIf and NgFor
I created a module with following code (we are at angular 15 where NgIf and NgFor are standalone, may be for older versions it should be tuned)

import { NgFor, NgIf } from "@angular/common";
import { NgModule } from "@angular/core";
import { NgModel } from "@angular/forms";

@NgModule({
	jit: true,
	imports: [ NgIf, NgFor ],
	declarations: [
		NgModel
	],
	exports: [
		NgModel, NgIf, NgFor
	]
})
export class JitModule {
}

Our project now is compiled with aot: true, dynamic components have jit: true and all they import the JitModule
I don’t know how long this will work and if it will change in the future versions, but it is a live-saver for the time of writing

0reactions
angular-automatic-lock-bot[bot]commented, Dec 23, 2022

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can't bind to 'ngModel' since it isn't a known property of 'input ...
It appears that the real answer was that you need to import the FormsModule in the same NgModule that you have declared your...
Read more >
Getting started with standalone components - Angular
Components, directives, and pipes can now be marked as standalone: true . Angular classes marked as standalone do not need to be declared...
Read more >
NgModule FAQ - Angular
Components that are only loaded dynamically by the router or by bootstrapping. Such entry components can never be selected in another component's template....
Read more >
Launching your app with a root module - Angular
You must declare every component in exactly one NgModule class. If you use a component without declaring it, Angular returns an error message....
Read more >
Component testing scenarios - Angular
detectChanges() manually to trigger another cycle of change detection. Rather than wonder when the test fixture will or won't perform change detection, the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found