Hello,
Will the problem described [here](https://github.com/NativeScript/nativescript-angular/issues/377#issuecomment-275272724) be fixed or is there a workaround that does not involve refreshing the whole list?
I am currently using a component selector inside the radlistview, and when the "switchcase" inside that component changes and causes the background/display of the view to change, the element becomes white and nothing is rendered.
Thank you.
6 Answers, 1 is accepted
Thanks for writing.
I have reviewed the related discussion and can confirm that we have a similar example in our Angular SDK that works as expected:
https://github.com/telerik/nativescript-ui-samples-angular/tree/release/sdkAngular/app/listview/selection-states
Since I also noticed that in the related discussion the standard ListView component is used, I would like to ask you whether you are using ListView or RadListView? Does the above example help you implement your scenario or you need a different approach?
Thanks!
Regards,
Deyan
Progress Telerik
Hello Deyan,
The scenario in the example does not work for me. I am not trying to select items.
This is what I have
<GridLayout> <RadListView backgroundColor="transparent" (itemLoading)="onItemLoading($event)" [items]="allCards"> <ng-template tkListItemTemplate let-item="item" let-index="index"> <StackLayout> <Label *ngIf="item.sectionTitle" class="section-title" [text]="item.sectionTitle"></Label> <StackLayout class="card"> <ink-no-data *ngIf="!defaultCard && loaded && index === 0" [isCentered]=true [title]="'You have no default card!'" [description]="'Create or activate a card.'"></ink-no-data> <ink-card [card]="item" displayOptions=true></ink-card> </StackLayout> </StackLayout> </ng-template> </RadListView></GridLayout>
<StackLayout orientation="vertical" class="card-container" [class.edit-display]="editDisplay && cardType !== 'image'"> <GridLayout [ngSwitch]="currentState" class="content"> <NSImage *ngSwitchCase="'qr'" [src]="card.fullQRImageUrl" stretch="aspectFit" (tap)="toggleQR()"></NSImage> <StackLayout class="template" [class.collapsed]="currentState !== 'template'"> <ng-template inkCardTemplate></ng-template> </StackLayout> <StackLayout *ngSwitchCase="'image'" class="upload"> <NSImage src="{{card.fullMediaUrl}}" stretch="fill" height="100%"></NSImage> </StackLayout> <DockLayout class="overlay" stretchLastChild=false (tap)="currentState === 'qr' ? toggleOptions() : ''"> <StackLayout dock="top"> <Button *ngIf="(currentState === 'template' || currentState === 'image') && displayOptions" class="icon more-options rotate" [text]="'\ue802'" (tap)="toggleOptions()"></Button> <Button *ngIf="currentState !== 'template' && currentState !== 'image'" class="icon more-options" [text]="'\ue805'" (tap)="close()"></Button> </StackLayout> <StackLayout dock="bottom"> <Button *ngIf="displayEditButton && currentState !== 'qr'" class="icon edit-button" [text]="'\ue80c'" (tap)="editCard()"></Button> </StackLayout> </DockLayout> <DockLayout *ngSwitchCase="'options'" class="options" stretchLastChild=false> <GridLayout rows="auto" dock="top"> <FlexboxLayout class="header" flexDirection="column"> <Label flexGrow="1" text="{{card.name || 'No Name'}}" fontSize="16"></Label> <Label flexGrow="1" text="created on {{card.createdDate | date:'longDate'}}" fontSize="14"></Label> </FlexboxLayout> <StackLayout class="overlay overlay-options"> <Button class="icon more-options" [text]="'\ue805'" (tap)="close()"></Button> </StackLayout> </GridLayout> <GridLayout rows="auto" columns="*, *" dock="bottom"> <FlexboxLayout class="buttons-left" flexDirection="column" flexGrow="1"> <Button class="option-button" text="Show QR Code" (tap)="toggleQR()" flexGrow="1"></Button> <Button class="option-button" *ngIf="!card.isDefault" text="Make Default" (tap)="makeDefault()" flexGrow="1"></Button> <Button class="option-button" text="Edit Card" (tap)="editCard()" flexGrow="1"></Button> </FlexboxLayout> <FlexboxLayout class="buttons-right" flexDirection="column" col="1" flexGrow="1"> <Button class="option-button" text="Copy Url" (tap)="copyURL()" flexGrow="1"></Button> <Button class="option-button" *ngIf="!card.isActive" text="Activate" (tap)="activate()" flexGrow="1"></Button> <Button class="option-button" *ngIf="card.isActive && !card.isDefault" text="Deactivate" (tap)="deactivate()" flexGrow="1"></Button> <Button class="option-button" text="Delete" (tap)="delete()" flexGrow="1"></Button> </FlexboxLayout> </GridLayout> </DockLayout> </GridLayout></StackLayout>I forgot to include in my reply that the screenshots are from a working scenario where I used ScrollView instead.
But I would like to use RadListView to make use of its functionality of loading only visible items on the viewport instead of the whole list.
Thank you.
Thanks for writing back.
Looking at your HTML code I presume the reason for the undesired behavior lies beneath the way RadListView works under iOS. We internally use the native iOS UICollectionView which does not automatically refresh when visual elements within the cell are added/removed - which the ngIf directive does here.
One possible approach I can think of is using the Multiple Templates support in RadListView which we have recently introduced:
http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/ListView/multiple-templates
Basically - you can define different views for different items.
Does this work for you?
Regards,
Deyan
Progress Telerik
We are facing the same issue - ven through we are using the Multiple templates approach and not *ngIf, the view is not refreshing when a new item is added to the observable array. Here is our html and component.
<GridLayout rows="*" class="m-x-10"> <RadListView [items]="this.messagesForView" [itemTemplateSelector]="templateSelector"> <ng-template tkTemplateKey="testPrint" let-item="item"> <GridLayout rows="auto auto" columns="auto *"> <Label row="0" col="0" text="" class="fa p-10 m-y-5"></Label> <Label row="0" col="1" [text]="'Your test ' + item.testName + ' is ready for download at ' + item.testLink" textWrap="true"></Label> <Label row="1" col="1" text="11:50" horizontalAlignment="right" class="m-r-10"></Label> </GridLayout> </ng-template> <ng-template tkTemplateKey="otherMessage" let-item="item"> <GridLayout rows="auto auto" columns="auto *"> <Label row="0" col="0" text="" class="fa p-t-4 m-y-5"></Label> <Label row="0" col="1" [text]="item.body" textWrap="true"></Label> <Label row="1" col="1" text="13:10" horizontalAlignment="right" class="m-r-10"></Label> </GridLayout> </ng-template> </RadListView> <!--For item delete -- pending implementation --> <!-- <GridLayout *tkListItemSwipeTemplate columns="* *" class="listItemSwipeGridLayout" height="100%"> <StackLayout id="mark-view" class="markViewStackLayout" col="0" (tap)="onLeftSwipeClick($event)" backgroundColor="#FB7EA1" height="100%" verticalAlignment="center"> <Label text="Undo" horizontalAlignment="center" class="question-swipe"></Label> </StackLayout> <StackLayout id="delete-view" class="deleteViewStackLayout" col="1" (tap)="onRightSwipeClick($event)" backgroundColor="#FB7EA1" height="100%" verticalAlignment="center"> <Label text="Delete" horizontalAlignment="center" class="question-swipe"></Label> </StackLayout> </GridLayout> --></GridLayout>]
The component:
import { AfterContentInit, Component, OnInit, OnDestroy } from "@angular/core";import { NavigationExtras, Router } from "@angular/router";import { RouterExtensions } from "nativescript-angular";import { android } from "application"; // THis is to import application for handleing back button.import { DatePipe } from '@angular/common'; // For showing time on messageimport * as email from "nativescript-email"; //for the email featureimport { Subscription } from "rxjs/Rx";import { Page } from "ui/page";import { Location } from "@angular/common";//import ui elementsimport scrollViewModule = require("ui/scroll-view");// import htmlViewModule = require("ui/html-view");import { ListViewEventData, RadListView } from "nativescript-telerik-ui/listview"; //This import is for rad list and event data on radList.import { topmost } from "ui/frame"; //To catch the rad list component as view.import { View } from "ui/core/view"; //To use a component as a View.//to show dialog for modify Qimport { action } from "ui/dialogs";import { LoadingIndicator } from "nativescript-loading-indicator";import { isTablet } from "../shared/device-constant/device.constant";import { UserStatusService } from "../services/userStatus.service";import { FirebaseMessagingService } from "../services/firebase-messaging.service";// import { McqItem } from "../models/questionMCQ.model";import { AndroidBAckButtonHandlerService } from "../services/androidBackButtonHandler.service";import { ObservableArray } from "data/observable-array";@Component({ moduleId: module.id, selector: "messaging", styleUrls: [(isTablet ? '../tablet.css' : '../phone.css')], templateUrl: "./messaging.component.html",})export class MessagingComponent implements OnInit, OnDestroy { uid: string; private backButtonHandler: Subscription; public isTablet: boolean; composeOptions: email.ComposeOptions; public messagesForView: ObservableArray<any>; private _templateSelector: (item: any, index: number, items: any) => string; public messagesSubscriber: Subscription; constructor(private router: Router, private routerExtensions: RouterExtensions, private location: Location, private userStatusService: UserStatusService, private firebaseMessagingService: FirebaseMessagingService, private page: Page, private androidBAckButtonHandlerService: AndroidBAckButtonHandlerService) { } public ngOnInit() { this.messagesForView = new ObservableArray(); this._templateSelector = this.templateSelectorFunction; this.page.actionBarHidden = true; this.messagesSubscriber = this.firebaseMessagingService.messagesReceived.subscribe((currentMessages) => { this.messagesForView = new ObservableArray(currentMessages); }); // this.firebaseMessagingService.getMessageFromFirebase(); if (this.firebaseMessagingService.getMessages() !== undefined) { this.messagesForView = new ObservableArray(JSON.parse(this.firebaseMessagingService.getMessages())); } else { const welcomeMessage = { type: "otherMessage", testName: "Trial Test", testLink: "Trial Link", title: "Welcome", body: "Hello", }; this.messagesForView.push(welcomeMessage); } // this.loader.show(this.options); //Subscribing android back button event emitter. this.backButtonHandler = this.androidBAckButtonHandlerService.detailTestBackHandler.subscribe((status) => { console.log("Back button pressed on detail test component and the status is: " + JSON.stringify(status)); }); } get templateSelector(): (item: any, index: number, items: any) => string { return this._templateSelector; } set templateSelector(value: (item: any, index: number, items: any) => string) { this._templateSelector = value; } public templateSelectorFunction = (item: any, index: number, items: any) => { return item.type; } public ngOnDestroy() { .... } sendMail() { ... }}
Please tell us how we can get the list to refresh on its own (without needing a pull to refresh or navigating out and coming back).
Thanks
Can you please share which UI component are you using: RadListView or ListView? As the issue you are pointing is ListView related and this forum is related to RadListView cases.
In the meantime: you may want to check out the multiple templates functionality in RadListView:
http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/ListView/multiple-templates
It allows you to define a specific view depending on a given condition for the different items.
ListView supports multiple templates as well.
I hope this is helpful.
Regards,
Deyan
Progress Telerik