NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.21k stars 241 forks source link

iOS - GridLayout with dynamically positioned cells crashes on iOS. #1796

Open sbknick opened 5 years ago

sbknick commented 5 years ago

Environment Provide version numbers for the following components (information can be retrieved by running tns info in your project folder or by inspecting the package.json of the project):

Describe the bug On iOS, when a GridLayout child element is positioned using "col" and "row" where the positioning is calculated at runtime---eg [col]="idx % 2" [row]="idx / 2"---this causes a crash on iOS with a TypeError: undefined is not an object (evaluating 'rowGroup.getIsAuto').

To Reproduce

  1. Create a NS Angular project.
  2. Create a component with an arbitrary set of "items":
    export class ItemsComponent {
    items = ["Item 1", "Item 2", "Item 3"];
    }
  3. In the component's template, attempt to display the items in a GridLayout, calculating the 'col' and 'row' dynamically:
    <GridLayout columns="*, *" rows="auto, auto">
    <StackLayout *ngFor="let item of items; let idx = index"
        [col]="idx % 2" [row]="idx / 2">
        <Label [text]="item"></Label>
    </StackLayout>
    </GridLayout>
  4. When running the app, on iOS, the app will crash.

Expected behavior The items should be displayed nicely in a grid, evenly spaced horizontally and auto-spaced vertically.

Sample project https://github.com/sbknick/ns-ios-dynamicpositionedgridlayout

Additional context On Android, this functions as expected.

tsonevn commented 5 years ago

Hi @sbknick, Thank you for the provided sample project. I was able to recreate the issue on my side for iOS and will mark it as a bug, which we will investigate further. As a temporary solution, I would suggest using braces {{ }}, while setting up the col and row properties binding. For example:

 <GridLayout columns="*, *" rows="auto, auto" style="border-width: 1">
        <StackLayout *ngFor="let item of items; let idx = index"
            col="{{idx % 2}}" row="{{idx / 2}}">
            <Label [text]="item"></Label>
            <Label [text]="idx"></Label>
        </StackLayout>
    </GridLayout>

The code above will work as expected on both iOS and Android.

jawa-the-hutt commented 5 years ago

commenting here due having the same underlying issue on a Nativescript-Vue project.

The suggested workaround with the mustache templating also wasn't working for me with Vue in this instance. So, I came up with a slightly different syntax in case someone else runs across this before this is fixed.

instead of the mustache syntax use the following:

<GridLayout columns="*, *" rows="auto, auto" style="border-width: 1">
  <StackLayout v-for="item of items" :key="index"
      :col="`${ index % 2 }`" :row="`${ index / 2 }`">
    <Label :text="item"></Label>
    <Label :text="index"></Label>
  </StackLayout>
</GridLayout>
dammynex commented 4 years ago

commenting here due having the same underlying issue on a Nativescript-Vue project.

The suggested workaround with the mustache templating also wasn't working for me with Vue in this instance. So, I came up with a slightly different syntax in case someone else runs across this before this is fixed.

instead of the mustache syntax use the following:

<GridLayout columns="*, *" rows="auto, auto" style="border-width: 1">
  <StackLayout v-for="item of items" :key="index"
      :col="`${ index % 2 }`" :row="`${ index / 2 }`">
    <Label :text="item"></Label>
    <Label :text="index"></Label>
  </StackLayout>
</GridLayout>

Thanks! This worked

jarrodwhitley commented 2 years ago

I was having the same issue, but for me it was because I had column="*,*" instead of "columns". Check your syntax, friends!