NativeScript / sample-Groceries

:green_apple: :pineapple: :strawberry: A NativeScript-built iOS and Android app for managing grocery lists

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ListView Disappears After Animation

spicywhitefish opened this issue · comments

Really enjoying NativeScript and the Groceries Tutorial. Great job, NativeScript team!


TNS version 3.0.1
End of chapter 3.
I had to add animation-fill-mode: forwards to keep the grocery list from disappearing on both platforms.
I am hopeful that you will not be able to reproduce this issue, or that the tutorial can be amended to reduce frustration for other developers.
Thanks!

list-common.css

ListView {
    opacity: 0;
}

.visible {
    animation-name: show;
    animation-duration: 1s;
    // Not in the tutorial! Needed to keep list from disappearing
    animation-fill-mode: forwards;
}

@keyframes show {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

.add-bar {
    background-color: #CB1D00;
    padding: 5 10;
}

.add-bar Image {
    height: 15;
    vertical-align: center;
    margin-left: 10;
    margin-right: 5;
}

TextField {
    color: white;
}

list.html

<GridLayout rows="auto, *">

    <GridLayout row="0" , columns="*, auto" class="add-bar">
        <TextField #groceryTextField [(ngModel)]="grocery" hint="Enter a grocery item" col="0"></TextField>
        <Image src="res://add" col="1" (tap)="add()"></Image>
    </GridLayout>

    <ListView [items]="groceryList" row="1" class="small-spacing" [class.visible]="listLoaded">
        <ng-template let-item="item">
            <Label [text]="item.name" class="medium-spacing"></Label>
        </ng-template>
    </ListView>
    <ActivityIndicator [busy]="isLoading" [visibility]="isLoading ? 'visible' : 'collapse'" row="1"
                       horizontalAlignment="center" verticalAlignment="center"></ActivityIndicator>

</GridLayout>

list.component.ts

import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {GroceryListService} from '../../shared/grocery/grocery-list.service';
import {TextField} from 'tns-core-modules/ui/text-field';

@Component({
    selector: "list",
    templateUrl: "pages/list/list.html",
    styleUrls: ["pages/list/list-common.css", "pages/list/list.css"],
    providers: [GroceryListService]
})
export class ListComponent implements OnInit {
    groceryList: Object[] = [];
    grocery = '';
    isLoading = false;
    listLoaded = false;

    @ViewChild('groceryTextField') groceryTextField: ElementRef;

    constructor(private groceryListService: GroceryListService) {
    }

    ngOnInit(): void {
        this.isLoading = true;
        this.groceryListService.load()
            .subscribe(loadedGroceries => {
                loadedGroceries.forEach(groceryObject => {
                    this.groceryList.unshift(groceryObject);
                });
                this.isLoading = false;
                this.listLoaded = true;
            })
    }

    add() {
        if (this.grocery.trim() === '') {
            alert('Enter a grocery item');
            return;
        }

        const textField = this.groceryTextField.nativeElement as TextField;
        textField.dismissSoftInput();

        this.groceryListService.add(this.grocery)
            .subscribe(
                groceryObject => {
                    this.groceryList.unshift(groceryObject);
                    this.grocery = '';
                },
                () => {
                    alert({message: 'An  error occurred while adding an item to your list.', okButtonText: 'OK'});
                    this.grocery = '';
                }
            )
    }

}

grocery-list.service.ts

import { Injectable } from "@angular/core";
import { Http, Headers } from "@angular/http";
import { Observable } from "rxjs/Rx";
import "rxjs/add/operator/map";

import { Config } from "../config";
import { Grocery } from "./grocery";

@Injectable()
export class GroceryListService {
    constructor(private http: Http) {}

    load() {
        let headers = new Headers();
        headers.append("Authorization", "Bearer " + Config.token);

        return this.http.get(Config.apiUrl + "Groceries", {
            headers: headers
        })
            .map(res => res.json())
            .map(data => {
                let groceryList = [];
                data.Result.forEach((grocery) => {
                    groceryList.push(new Grocery(grocery.Id, grocery.Name));
                });
                return groceryList;
            })
            .catch(this.handleErrors);
    }

    add(name: string) {
        let headers = new Headers();
        headers.append("Authorization", "Bearer " + Config.token);
        headers.append("Content-Type", "application/json");

        return this.http.post(
            Config.apiUrl + "Groceries",
            JSON.stringify({ Name: name }),
            { headers: headers }
        )
            .map(res => res.json())
            .map(data => {
                return new Grocery(data.Result.Id, name);
            })
            .catch(this.handleErrors);
    }

    handleErrors(error: Response) {
        console.log(JSON.stringify(error.json()));
        return Observable.throw(error);
    }
}

The issue is not reproducible with the latest version of sample-Groceries application.