Nativescript-angular: Layout issue when using custom components in a GridLayout

Created on 24 Jan 2017  路  10Comments  路  Source: NativeScript/nativescript-angular

When using this type of layout in conjunction with Angular components (one of which uses a ListView underneath) creates the following troublesome layout.

I would expect this layout to just work:

<GridLayout rows="*,100" columns="*">
    <test-list-cmp row="0" col="0"></test-list-cmp> <!-- This has ListView underneath -->
    <test-cmp row="1" col="0"></test-cmp>
</GridLayout>

Simple sample project which demonstrates this problem:
https://github.com/NathanWalker/layout-bug-demo

Screenshot of problem...
screen shot 2017-01-23 at 10 46 00 pm

ios

Most helpful comment

Hi @NathanWalker,

I don't think it has anything to do with the ListView.
If you wrap the custom components inside a StackLayout and set row/col on that, the problem goes away (at least on Android).

<ActionBar title="Test" icon="" class="action-bar">
</ActionBar>
<GridLayout rows="*,100" columns="*">
  <StackLayout row="0" col="0">
    <test-list-cmp></test-list-cmp>
  </StackLayout>
  <StackLayout row="1" col="0">
    <test-cmp></test-cmp>
  </StackLayout>
</GridLayout>

I can't find the link with the explanation and the workaround I once had.

As I remember it, the problem is that layout properties are not inherited by the custom components. (It might have something to do with them being wrapped inside a ProxyViewContainer, but I can't remember).

So you either have to wrap the custom component inside a StackLayout OR add the layout properties inside you custom component like this:

<GridLayout rows="100" columns="75,*" [row]="cRow" [col]="cCol">
    <Label text="Sample" row="0" col="0"></Label>
    <Label text="This layout issue is troublesome." row="0" col="1"></Label>
</GridLayout>
import { Component, Input } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'test-cmp',
    templateUrl: 'test-cmp.component.html'
})
export class TestCmpComponent {
  @Input() cRow: number;
  @Input() cCol: number;
}

All 10 comments

Hey @NathanWalker correct me if I am wrong, but by design, in iOS, the ListView won't be displayed if no size is predefined. Perhaps this is the reason for your custom component not to render as expected!?

Hi @NickIliev I'm not sure actually - are you thinking that if the test-list-cmp had an explicit height set or the underlying ListView had an explicit height, it should work?

Should height: 80% work on the ListView to render properly? I believe I tried that and have run into issues with ListView height there as well.

Hi @NathanWalker,

I don't think it has anything to do with the ListView.
If you wrap the custom components inside a StackLayout and set row/col on that, the problem goes away (at least on Android).

<ActionBar title="Test" icon="" class="action-bar">
</ActionBar>
<GridLayout rows="*,100" columns="*">
  <StackLayout row="0" col="0">
    <test-list-cmp></test-list-cmp>
  </StackLayout>
  <StackLayout row="1" col="0">
    <test-cmp></test-cmp>
  </StackLayout>
</GridLayout>

I can't find the link with the explanation and the workaround I once had.

As I remember it, the problem is that layout properties are not inherited by the custom components. (It might have something to do with them being wrapped inside a ProxyViewContainer, but I can't remember).

So you either have to wrap the custom component inside a StackLayout OR add the layout properties inside you custom component like this:

<GridLayout rows="100" columns="75,*" [row]="cRow" [col]="cCol">
    <Label text="Sample" row="0" col="0"></Label>
    <Label text="This layout issue is troublesome." row="0" col="1"></Label>
</GridLayout>
import { Component, Input } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'test-cmp',
    templateUrl: 'test-cmp.component.html'
})
export class TestCmpComponent {
  @Input() cRow: number;
  @Input() cCol: number;
}

Thanks @m-abs that definitely helps explain a couple things for sure and does work.
It would be nice if the renderer handled some of this under the hood so you wouldn't have to workaround general expectations.

still needs that workaround

@yassern in the previous comments there are two possible workarounds for this issue (1. wrap the custom component in some layout; 2. Use Angular input) - aren't they working for your case?

Yes, it is working.
But would be nice do not need them.

This is a headache because using the workarounds makes the HTML code too much verbose, there is something we can do using ViewContainerRef? if so.. there is some example? i see this post in the documentation but i don't understand how to register my custom component so we can create a componente that have a single Label in its template and supports all the CSS styles and Layout properties for a Label nativescript component, i already extends to Label but that did nothing.

We've been using another workaround for a while.

If you change the selector to include an attribute selector, e.g. from test-cmp to test-cmp, [test-cmp] you can use the component like this:

<GridLayout rows="*,100" columns="*">
    <StackLayout test-list-cmp row="0" col="0"></StackLayout> <!-- This has ListView underneath -->
    <StackLayout test-cmp row="1" col="0"></StackLayout>
</GridLayout>

It is a lot prettier than the old workaround.

Thanks @m-abs Your latest suggestion worked for me! I couldn't get the first one you offered. Sucks that the properties aren't funneled down into the component created.

Would said component need to extend the GridLayout class in order to work more naturally?

Was this page helpful?
0 / 5 - 0 ratings