Skip to content

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

Closed
@Jonatthu

Description

@Jonatthu

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

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions