I'm working with angular 8 i want to display a popup with angular material this is what i did :
In my Html :
<button (click)="myDia.open()">Open it</button>
Result: {{result | json}}
<my-dialog (result)="result = $event" #myDia>
<h1 mat-dialog-title>Dialog Title</h1>
<mat-dialog-content>
Content
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button (click)="myDia.close()">Cancel</button>
<button mat-button (click)="myDia.close({foo:'bar'})">Confirm</button>
</mat-dialog-actions>
</my-dialog>
And this is the Ts file :
#Component({
selector: 'my-dialog',
template: `
<ng-template>
<ng-content></ng-content>
</ng-template>
`
})
export class MyDialogComponent {
#ViewChild(TemplateRef)
private templateRef: TemplateRef<any>;
#Output()
result = new EventEmitter<boolean>();
private dialogRef: MatDialogRef<any>;
constructor(private dialog: MatDialog) {}
open() {
this.dialogRef = this.dialog.open(this.templateRef);
this.dialogRef.afterClosed().subscribe(val => {
this.result.emit(val);
});
}
close(val: any) {
this.dialogRef.close(val);
}
}
I have a problem in this line :
#ViewChild(TemplateRef)
The error is :
Expected 2 arguments, but got 1
An argument for 'opts' was not provided.
I have added in my app.module.ts :
import { MyDialogComponent } from './pages/interfacage/test/test.component';
So how can i solve this problem.
I'am using this tuto path
From Angular 8, you need to add { static: true } in ViewChild
Try:
#ViewChild('TemplateRef', { static: true }) TemplateRef: any;
Now it work in Angular8
#ViewChild(TemplateRef, {static: false})
private templateRef: TemplateRef<any>;
https://stackblitz.com/edit/angular-material2-issue-yqcfpj?file=app/app.component.html
Related
I'm creating a very simple button component in Angular and I was wondering if there was any difference in html semantic if I put the click event on the parent component.
Version 1:
<!-- template.html -->
<ui-button label="Try again" (click)="tryAgain()">
</ui-button>
// ui-button.component.ts
#Component({
selector: 'ui-button',
templateUrl: './ui-button.component.html',
})
export class ButtonComponent {
#Input() public label: string;
}
<!-- ui-button.component.html -->
<button>
{{ label }}
</button>
Version 2:
<!-- template.html -->
<ui-button label="Try again" (onClickEvent)="tryAgain()">
</ui-button>
// ui-button.component.ts
#Component({
selector: 'ui-button',
templateUrl: './ui-button.component.html',
})
export class ButtonComponent {
#Input() public label: string;
#Output() public onClickEvent = new EventEmitter()
public onClick(): void {
this.onClickEvent.emit();
}
}
<!-- ui-button.component.html -->
<button (click)="onClick()">
{{ label }}
</button>
I have a dialog box that is displaying a separate child component. The child component is below:
#Component({
selector: 'userEdit',
templateUrl: './edituser.component.html',
styleUrls: ['./edituser.component.css']
})
export class EditUserComponent implements OnInit {
public theName: string;
public theAddress: string;
constructor() {
this.theName = '';
this.theAddress = '';
}
ngOnInit() {
}
}
The dialog box code and template are below:
#Component({
selector: 'app-userdialog',
templateUrl: './userdialog.component.html',
styleUrls: ['./userdialog.component.css']
})
export class UserDialogComponent implements OnInit {
#ViewChild('userEdit', {static: false})
userEdit: EditUserComponent;
constructor(
public dlgRef: MatDialogRef<UserDialogComponent>,
#Inject(MAT_DIALOG_DATA) public theData: UsrStuff) { }
ngOnInit() {
}
ngAfterViewInit() {
console.log('Name: ' + this.userEdit.theName);
}
addUser() {
// TODO: implement adding a user
}
closeBox() {
this.dlgRef.close();
}
}
and
<div id="attribdlg">
<h3>Add New User</h3>
<userEdit theName="" theAddress=""></userEdit>
<mat-dialog-actions>
<button mat-raised-button color="primary" (click)="addUser()">Add User</button>
<button mat-raised-button color="primary" (click)="closeBox()">Done</button>
</mat-dialog-actions>
</div>
Based on the documentation and examples Ihave seen, this setup should enable me to print to the console the value pf userEdit's theName property in the ngAfterViewInit() function.
Unfortunately, this does not appear to be working.When the console log is called, I get the following failure message:
null: TypeError: Cannot read property 'theName' of undefined
Obviously, there is some kind of initialization of the child component that is supposed to happen, but I do not see this being done anywhere in the documentation! I am missing something.
How can I get this child component and its properties available to my dialog?
Two options:
Set an id to the component you wish to have with ViewChild():
TypeScript:
#ViewChild('userEdit', {static: false})
HTML:
<userEdit #userEdit theName="" theAddress=""></userEdit>
Select by directive or component:
TypeScript:
#import { EditUserComponent } from '...';
#ViewChild(EditUserComponent, {static: false})
HTML:
<userEdit theName="" theAddress=""></userEdit>
I highly recommend you to use app perfix for the component's selector!!!
#Component({
...
selector: 'app-user-edit',
...
})
I have a structural directive A nested inside another structural directive B.
Now i want to have access to B inside of A to use its templateRef.
I tried to use ContentChild, but it is always undefined.
Can somebody tell what I have to change to get access?
I recreated my constellation in a StackBlitz: https://stackblitz.com/edit/angular-b697ct?file=src%2Fapp%2Fhello.component.ts
Directive definition:
#Directive({selector: '[testChild]'})
export class B {
}
#Directive({selector: '[testParent]'})
export class A {
#ContentChild(B, {static: false}) contentTemplate: B;
constructor(public viewContainer: ViewContainerRef, public templateRef: TemplateRef<any>) {
}
ngAfterViewInit() {
console.log(this.contentTemplate); // logs undefined
}
}
#Directive({selector: '[tstOutlet]'})
export class TestOutlet {
constructor(public viewContainer: ViewContainerRef) {
}
}
#Component({
selector: 'tst',
template: `<ng-container tstOutlet></ng-container>`,
})
export class HelloComponent implements AfterViewInit {
#ContentChildren(A) parents: QueryList<A>;
#ViewChild(TestOutlet, {static: true}) outlet: TestOutlet;
ngAfterViewInit() {
this.parents.toArray().forEach((parent: A) => {
this.outlet.viewContainer.createEmbeddedView(parent.templateRef);
});
}
}
Template definition:
<tst>
<ng-container *testParent>
<span *testChild>Test</span>
</ng-container>
<ng-container *testParent>
<span *testChild>Second Test</span>
</ng-container>
</tst>
Recently I start to work with Angular 2, so I have some doubts about how to fill a p-dataTable in Angular 2 from a TypeScript file.
Let my show you my code...
My TypeScript code
#Component({
selector: 'app-request-assignClaim',
templateUrl: './request-assignClaim.component.html'
})
export class RequestAssignClaimComponent {
vm: RequestAssignViewModel;
constructor(
private route: ActivatedRoute,
private router: Router,
private requestService: IRequestService,
private growlService: GrowlService,
private actionService: ActionService,
private userService: UserService
) {
this.vm = new RequestAssignViewModel();
this.vm.isDisplayed = false;
}
showAssignClaims(request: RequestListItemViewModel): void {
this.vm.request = request;
this.loadAvailableUsers().subscribe(() => {
this.vm.isDisplayed = true;
this.assign();
});
}
assign(): void {
this.actionService.assignResponsible(this.vm.request.id, this.vm.request.responsible).subscribe(() => {
}, (e: any) => {
this.growlService.push({
severity: "info",
summary: "Error",
detail: "An error occurred while assigning the claim to another user, please try again "
});
});
}
close(): void {
this.vm.isDisplayed = false;
}
private loadAvailableUsers(): Observable<any> {
return new Observable((o: Observer<any>) => {
o.next(null);
o.complete();
});
}
}
My HTML
<p-dialog header="Assign claim" [(visible)]="vm.isDisplayed" [width]="700" >
<div class="ui-g">
<div class="ui-g-12">
<p-dataTable [value]="vm.list" selectionMode="none"
[(selection)]="vm.selectedRequests" datakey="Id" [paginator]="true"
[rows]="10" [responsive]="true">
<p-column field="name" [sortable]="true">
{{ vm.request.name }}
</p-column>
</p-dataTable>
</div>
<div class="ui-g-12 align-right">
<button pButton type="button" icon="ui-icon-close" label="Close"
styleClass="flat" (click)="close()"></button>
<button pButton type="button" icon="ui-icon-check" label="Assign"
styleClass="flat"></button>
</div>
</div>
</p-dialog>
So, I understand why is not working :(
If anybody can help me I really appreciate.
In typescript file, add the below code:
vm.list: any = [];
And pass the array to vm.list
So that ,[value] will get array of object:
<p-dataTable [value]="vm.list" selectionMode="none"
[(selection)]="vm.selectedRequests" datakey="Id" [paginator]="true"
[rows]="10" [responsive]="true">
I would like to create a ViewRef from markup that is dynamically inserted into a template. Is this possible based on the following code sample?
template.html:
<ng-container *ngTemplateOutlet="dynamic; context: cntx"></ng-container>
<ng-template #dynamic>
<div [innerHTML]="markup"></div>
</ng-template>
Injected markup from API call to bind to div's innerHTML attribute:
<div>
<div id="forViewRef"></div>
</div>
component.ts:
#ContentChild('#forViewRef', { read: ViewContainerRef }): someHndl;
private _nativeElem: any;
constructor(
private sanitizer: DomSanitizer,
private _vcRef: ViewContainerRef,
private _resolver: ComponentFactoryResolver) {
// to ensure template has been created, #dynamic
this._nativeElem = this._vcRef.element.nativeElement;
}
// listen to lifecycle hook
ngAfterContentChecked() {
if (this._nativeElem !== undefined)
// childContent ref is undefined
console.log(this.someHndl);
// markup is in the DOM
console.log(this._nativeElem.querySelectorAll('#forViewRef'));
}
To create component dynamically inside <div id="forViewRef"></div> you can do the following:
Let's say we need to load the following component
#Component({
selector: 'dynamic-comp',
template: `
<h2>Dynamic component</h2>
<button (click)="counter = counter + 1">+</button> {{ counter }}
`
})
export class DynamicComponent {
counter = 1;
}
so first add it to declarations and entryComponents array of your #NgModule
...
declarations: [ ..., DynamicComponent ],
entryComponents: [ DynamicComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
after that create
template.html
<button (click)="createComponent()">Create component</button>
<div id="forViewRef"></div>
and finally write
component.ts
export class AppComponent {
compRef: ComponentRef<DynamicComponent>;
constructor(private injector: Injector,
private resolver: ComponentFactoryResolver,
private appRef: ApplicationRef) {}
createComponent() {
const compFactory = this.resolver.resolveComponentFactory(DynamicComponent);
this.compRef = compFactory.create(this.injector, null, '#forViewRef');
this.appRef.attachView(this.compRef.hostView);
}
ngOnDestroy() {
if(this.compRef) {
this.compRef.destroy();
}
}
}
I use appRef.attachView in order to include dynamic component to change detection cycle
Plunker Example
See also
Display custom tag in google maps infowindow angular2
Angular2 - Component into dynamicaly created element
Add a component dynamically to a child element using a directive