Skip to content

When using ngTemplateOutlet ERROR Error: View already has a parent #2073

Open
@Jonatthu

Description

@Jonatthu

I posted this a while ago but still not getting any response from nativescript-angular so I bring it here
#2052

Environment

  • CLI: 6.1.2
  • Cross-platform modules: 6.1.2
  • iOS Runtime: 13.1
  • NativeScript-Angular: 8.2.2
  • Angular: 8.2.7

Describe the bug
When I working with the following snippet...

<StackLayout class="property-group">
	<app-search-bar *ngIf="showSearch" label="Enter to filter properties" [searchTerm]="searchTerm"
		[showSearch]="false" (searchChange)="onSearchChange($event)"></app-search-bar>
	<StackLayout class="property-group_accordion">
		<ng-container *ngFor="let property of filteredPropertyComponents; let i = index">
			<GridLayout (tap)="onPropertyOpened(property); opened = i;"
				class="property-group_accordion_element"
				[class.property-group_accordion_element--active]="opened == i" rows="*"
				columns="auto, *">
				<Label [text]="property.details.name | humanize"
					class="property-group_accordion_element_name" textWrap="true" row="0"
					col="0"></Label>
			</GridLayout>
			<StackLayout [visibility]="opened == i ? 'visible' : 'collapsed'"
				class="property-group_accordion_body" rows="*" columns="*">
				<ng-template [ngTemplateOutlet]="property.templateRef"></ng-template>
			</StackLayout>
		</ng-container>
	</StackLayout>
</StackLayout>

The first render of the list will work just fine but once I run a search and I start filtering the array variable filteredPropertyComponents it will hide the other components from the list as expected, once you clear your search and filteredPropertyComponents goes to the initial state (rendering the original list) the next error message will be on the console:

CONSOLE ERROR [native code]: ERROR Error: View already has a parent. View: ProxyViewContainer(2163) Parent: StackLayout(2313)
CONSOLE ERROR [native code]: ERROR CONTEXT {
"view": {
"def": {
"nodeFlags": 17580161,
"rootNodeFlags": 1,
"nodeMatchedQueries": 0,
"flags": 0,
"nodes": [
{
"nodeIndex": 0,
"parent": null,
"renderParent": null,
"bindingIndex": 0,
"outputIndex": 0,
"checkIndex": 0,
"flags": 1,
"childFlags": 17580161,
"directChildFlags": 1,
"childMatchedQueries": 0,
"matchedQueries": {},
"matchedQueryIds": 0,
"references": {},
"ngContentIndex": null,
"childCount": 12,
"bindings": [],
"bindingFlags": 0,
"outputs": [],
"element": {
"ns": null,
"name": null,
"attrs": [],
"template": null,
"componentProvider": null,
"componentView": null,
"componentRendererType": null,
"publicProviders": {},
<…>

By exploring different options I saw a way to fix the problem but the desired layout no longer is possible
If I remove the parent of the ng-template which is the StackLayout this will work just fine:

From this:

			<StackLayout [visibility]="opened == i ? 'visible' : 'collapsed'"
				class="property-group_accordion_body" rows="*" columns="*">
				<ng-template [ngTemplateOutlet]="property.templateRef"></ng-template>
			</StackLayout>

To this:

<ng-template [ngTemplateOutlet]="property.templateRef"></ng-template>

So my final template will be this:

<StackLayout class="property-group">
	<app-search-bar *ngIf="showSearch" label="Enter to filter properties" [searchTerm]="searchTerm"
		[showSearch]="false" (searchChange)="onSearchChange($event)"></app-search-bar>
	<StackLayout class="property-group_accordion">
		<ng-container *ngFor="let property of filteredPropertyComponents; let i = index">
			<GridLayout (tap)="onPropertyOpened(property); opened = i;"
				class="property-group_accordion_element"
				[class.property-group_accordion_element--active]="opened == i" rows="*"
				columns="auto, *">
				<Label [text]="property.details.name | humanize"
					class="property-group_accordion_element_name" textWrap="true" row="0"
					col="0"></Label>
			</GridLayout>
			<ng-template [ngTemplateOutlet]="property.templateRef"></ng-template>
		</ng-container>
	</StackLayout>
</StackLayout>

Now it does not throw any errors but the layout it's broken.

Here some screenshots:

  1. Working fine

Screen Shot 2019-11-05 at 8 47 53 AM

  1. Filtering working fine

Screen Shot 2019-11-05 at 8 48 41 AM

  1. If I press clear which renders the original list will freeze and throw the error message.

Screen Shot 2019-11-05 at 8 49 26 AM

Here the code that I am using to access to the templateRef:

property.component.ts

import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { __Field, __InputValue } from '@app/graphql';

@Component({
	selector: 'app-property',
	templateUrl: './property.component.html',
	styleUrls: ['./property.component.scss'],
	encapsulation: ViewEncapsulation.None,
})
export class PropertyComponent implements OnInit
{
	/**
	 * Defines the template on the property component.
	 */
	@ViewChild(TemplateRef, { static: true })
	public templateRef: TemplateRef<any>;

	constructor() { }

	public ngOnInit(): void
	{
	}

}

and here the html

<ng-template>
	<ng-content></ng-content>
</ng-template>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions