Description
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:
- Working fine
- Filtering working fine
- If I press clear which renders the original list will freeze and throw the error message.
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>