Hello Forum,
I have an array with label descriptions. An array with image file names. An array with buttons with text. My labels display fine, my images are blank, my buttons show but with no text. No error messages.
Any ideas on what I'm missing?
Thanks in advance.
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:lv="nativescript-telerik-ui/listview" loaded="pageLoaded">
<ActionBar title="RadListView" />
<lv:RadListView items="{{ myItems }}">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout scrollDirection="Vertical" itemHeight="200" spanCount="3"/>
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<StackLayout>
<Label text="{{ $value }}" class="lable" textWrap="true" />
<Image src="{{ $parents['lv:RadListView'].myPics, $parents['lv:RadListView'].myPics }}" height="95" width="95" />
<Button text="{{ $parents['lv:RadListView'].myBtext, $parents['lv:RadListView'].myBtext }}" />
</StackLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
</Page>
main-page.js
var view = require("ui/core/view");
var image = require("ui/image");
var observable = require("data/observable");
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5",
"Desc 6",
"Desc 7",
"Desc 8",
"Desc 9"
];
var myImages = [
"~/img/thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png",
"~/img/Thb_AmFlagMap.png"
];
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5",
"Tap 6",
"Tap 7",
"Tap 8",
"Tap 9"
];
var viewModel = new observable.Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
exports.pageLoaded = function(args) {
var page = args.object;
page.bindingContext = viewModel;
};
12 Answers, 1 is accepted
Thank you for your interest in UI for NativeScript.
I reviewed the case and found that the issue could be related to the way that the data is bind. Accessing the parent of the main list view for showing a value in the other component could lead to a problem and the value not to be shown properly.
My suggestion is to create a custom component with the needed properties and with its help to create the needed array, which to be bind to the RadListView source. For example:
XML
<
ActionBar
title
=
"RadListView"
/>
<
GridLayout
>
<
lv:RadListView
items
=
"{{ myItems }}"
>
<
lv:RadListView.listViewLayout
>
<
lv:ListViewLinearLayout
scrollDirection
=
"Vertical"
/>
</
lv:RadListView.listViewLayout
>
<
lv:RadListView.itemTemplate
>
<
StackLayout
orientation
=
"vertical"
>
<
Label
text
=
"{{ title }}"
class
=
"lable"
textWrap
=
"true"
/>
<
Image
src
=
"{{ imageurl }}"
height
=
"95"
width
=
"95"
/>
<
Button
text
=
"{{ buttontitle }}"
/>
</
StackLayout
>
</
lv:RadListView.itemTemplate
>
</
lv:RadListView
>
</
GridLayout
>
</
Page
>
TypeScript
import { EventData, Observable } from 'data/observable';
import {ObservableArray} from "data/observable-array"
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
class Item{
constructor(public title, public imageurl, public buttontitle){}
}
export function pageLoaded(args: EventData) {
let page = <
Page
>args.object;
var viewModel = new Observable();
var myArray=new ObservableArray();
myArray.push(new Item("Desc 1", "~/img/test.png", "Tap 1"));
myArray.push(new Item("Desc 2", "~/img/test.png", "Tap 2"));
myArray.push(new Item("Desc 3", "~/img/test.png", "Tap 3"));
viewModel.set("myItems", myArray);
page.bindingContext = viewModel;
}
JavaScript
var observable_1 = require("data/observable");
var observable_array_1 = require("data/observable-array");
var Item = (function () {
function Item(title, imageurl, buttontitle) {
this.title = title;
this.imageurl = imageurl;
this.buttontitle = buttontitle;
}
return Item;
}());
function pageLoaded(args) {
var page = args.object;
var viewModel = new observable_1.Observable();
var myArray = new observable_array_1.ObservableArray();
myArray.push(new Item("Desc 1", "~/img/test.png", "Tap 1"));
myArray.push(new Item("Desc 2", "~/img/test.png", "Tap 2"));
myArray.push(new Item("Desc 3", "~/img/test.png", "Tap 3"));
viewModel.set("myItems", myArray);
page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
I am also attaching the whole project.
For further help, you could review the sample project here.
If you still have a problem with the ListView, please provide some sample project, which could be debugged locally.
Regards,
nikolay.tsonev
Telerik by Progress
I'm sorry, I may not have been clear enough with my question.
I have three groups of elements, each group is in it's own array. Is there an easier way to do this and NOT have to parse each of my (3) arrays and assemble the three matching elements into a new array?
The sample project link ( https://github.com/telerik/nativescript-ui-samples/tree/release/sdk/app/listview/getting-started ) you sent looks like it may offer a solution for me, but unfortunately for me it's in TypeScript and I don't understand it enough to use it. Please, can you convert it into JavaScript? That would be a huge help, thank you in advance.
I reviewed your case ones again and indeed you could access the other array in the XML while using the $parents keyword, however, there is no way to get the index of the current element, which will allow you to load specific element from the other arrays.
This is known limitation for pure NativeScript project and we have already logged a feature request for this functionality here. For further info, you could keep track on it.
In the meantime as a temporary solution, you could use itemLoading event and with its help to get the Image and Button elements by id. Then you could setup src property for the Image and text for the Button. For example:
XML
<
Page
xmlns
=
"http://schemas.nativescript.org/tns.xsd"
xmlns:lv
=
"nativescript-telerik-ui/listview"
loaded
=
"pageLoaded"
>
<
ActionBar
title
=
"RadListView"
/>
<
lv:RadListView
items
=
"{{ myItems }}"
itemLoading
=
"func"
>
<
lv:RadListView.listViewLayout
>
<
lv:ListViewGridLayout
scrollDirection
=
"Vertical"
itemHeight
=
"200"
spanCount
=
"3"
/>
</
lv:RadListView.listViewLayout
>
<
lv:RadListView.itemTemplate
>
<
StackLayout
>
<
Label
id
=
"label"
text
=
"{{ $value }}"
class
=
"lable"
textWrap
=
"true"
/>
<
Image
id
=
"pic"
height
=
"95"
width
=
"95"
/>
<
Button
id
=
"bt"
/>
</
StackLayout
>
</
lv:RadListView.itemTemplate
>
</
lv:RadListView
>
</
Page
>
JavaScript
var observable_1 = require("data/observable");
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5",
"Desc 6",
"Desc 7",
"Desc 8",
"Desc 9"
];
var myImages = [
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png",
"~/img/test.png"
];
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5",
"Tap 6",
"Tap 7",
"Tap 8",
"Tap 9"
];
var Item = (function () {
function Item(title, imageurl, buttontitle) {
this.title = title;
this.imageurl = imageurl;
this.buttontitle = buttontitle;
}
return Item;
}());
function pageLoaded(args) {
var page = args.object;
var viewModel = new observable_1.Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
function func(args) {
var layout = args.view;
var image = layout.getViewById("pic");
image.src = myImages[args.itemIndex];
var button = layout.getViewById("bt");
button.text = myBtext[args.itemIndex];
}
exports.func = func;
For further info, you could also review the attached sample project.
Regarding the other request. You could build the project on your side and all typescript files will be compiled to JavaScript. You could follow the steps:
1. git clone https://github.com/telerik/nativescript-ui-samples
2. cd --samples/
3. tns prepare <platform name>
Hope this helps.
Regards,
nikolay.tsonev
Progress Telerik
Thank you so much Nikolay, for your terrific work! That was the explanation and answer to my question I was looking for.
Followup question: The function you have (below), I don't see it called or referenced anywhere else, where or how is that used?
var Item = function () {
function Item(title, imageurl, buttontitle) {
this.title = title;
this.imageurl = imageurl;
this.buttontitle = buttontitle;
}
return Item;
};
The Item function was part of the first example, where has been demonstrated, how to load the data using a custom component with the needed properties, however, this part of the code is not needed at this time. I have just missed to remove it from the sample.
Regarding that, you could just ignore it and remove it from the project.
Let me know if I could assist you further.
Regards,
nikolay.tsonev
Progress Telerik
Follow up question #2: No changes in the main-page.xml file. I have a list of image files in my 'img' folder as in the previous code sample, I need to get that list of images and put it into myImage[]. I don't get any errors but no images show up either?
Thank you in advance...
main-page.js
var observable_1 = require("data/observable");
var fs = require("file-system");
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5",
"Desc 6",
"Desc 7",
"Desc 8",
"Desc 9"
];
var myImages = [];
var documents = fs.knownFolders.documents();
var myFolder = documents.getFolder("img");
myFolder.getEntities().then(function (entities) {
entities.forEach(function (entity) {
myImages = entity.name;
});
},
function (error) {
console.log("Error: " + error);
});
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5",
"Tap 6",
"Tap 7",
"Tap 8",
"Tap 9"
];
var viewModel = new observable_1.Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
function pageLoaded(args) {
var page = args.object;
page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
function func(args) {
var layout = args.view;
var image = layout.getViewById("pic");
image.src = myImages[args.itemIndex];
var button = layout.getViewById("bt");
button.text = myBtext[args.itemIndex];
}
exports.func = func;
The issue in the sample code was related to the fact that knownFolders.documents() will return the application's 'documents' folder, where the images do not exist. What you are looking for is the `currecntApp()` method, which will give you the correct path to your application folder and you will be able to list all files from `img`.
Also, bear in mind that you should take the image sync which will allow loading the data in the ListView. For your help you could review the attached code sample:
XML
<
Page
xmlns
=
"http://schemas.nativescript.org/tns.xsd"
xmlns:lv
=
"nativescript-telerik-ui/listview"
loaded
=
"pageLoaded"
>
<
ActionBar
title
=
"RadListView"
/>
<
lv:RadListView
items
=
"{{ myItems }}"
itemLoading
=
"func"
>
<
lv:RadListView.listViewLayout
>
<
lv:ListViewGridLayout
scrollDirection
=
"Vertical"
itemHeight
=
"200"
spanCount
=
"3"
/>
</
lv:RadListView.listViewLayout
>
<
lv:RadListView.itemTemplate
>
<
StackLayout
>
<
Label
id
=
"label"
text
=
"{{ $value }}"
class
=
"lable"
textWrap
=
"true"
/>
<
Image
id
=
"pic"
height
=
"95"
width
=
"95"
/>
<
Button
id
=
"bt"
/>
</
StackLayout
>
</
lv:RadListView.itemTemplate
>
</
lv:RadListView
>
</
Page
>
TyeScript
import { EventData, Observable } from 'data/observable';
import {ObservableArray} from "data/observable-array"
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
import {ListView, ItemEventData} from "tns-core-modules/ui/list-view";
import {StackLayout} from "tns-core-modules/ui/layouts/stack-layout";
import {Image} from "tns-core-modules/ui/image";
import {Button} from "tns-core-modules/ui/button";
import {knownFolders, Folder, FileSystemEntity} from "file-system";
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5"
];
var myImages=[];
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5"
];
class Item{
constructor(public title, public imageurl, public buttontitle){}
}
export function pageLoaded(args: EventData) {
readFiles();
let page = <
Page
>args.object;
console.log("start data loading")
console.dir(myImages);
var viewModel = new Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
page.bindingContext = viewModel;
}
export function func(args){
var layout:StackLayout=<
StackLayout
>args.view;
var image:Image=<
Image
>layout.getViewById("pic");
image.src=myImages[args.itemIndex];
var button:Button=<
Button
>layout.getViewById("bt");
button.text=myBtext[args.itemIndex];
}
function readFiles(){
var documents = knownFolders.currentApp();
var myFolder:Folder = documents.getFolder("img");
var array= myFolder.getEntitiesSync();
console.log("array 1");
console.dir(array);
(<
any
>array).forEach(element => {
myImages.push(element._path);
});
console.log("get image end")
}
JavaScript
var observable_1 = require("data/observable");
var file_system_1 = require("file-system");
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5"
];
var myImages = [];
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5"
];
var Item = (function () {
function Item(title, imageurl, buttontitle) {
this.title = title;
this.imageurl = imageurl;
this.buttontitle = buttontitle;
}
return Item;
}());
function pageLoaded(args) {
readFiles();
var page = args.object;
console.log("start data loading");
console.dir(myImages);
var viewModel = new observable_1.Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
function func(args) {
var layout = args.view;
var image = layout.getViewById("pic");
image.src = myImages[args.itemIndex];
var button = layout.getViewById("bt");
button.text = myBtext[args.itemIndex];
}
exports.func = func;
function readFiles() {
var documents = file_system_1.knownFolders.currentApp();
var myFolder = documents.getFolder("img");
var array = myFolder.getEntitiesSync();
console.log("array 1");
console.dir(array);
array.forEach(function (element) {
myImages.push(element._path);
});
console.log("get image end");
}
Regards,
nikolay.tsonev
Progress Telerik
Follow up question #3: 'ItemTap event' I got from https://docs.nativescript.org/cookbook/ui/list-view#itemtap-event.
Thank you in advance...
No changes in my main-page.xml file.
I get an error "unexpected token" when I do:
listView.on(listViewModule.ListView.itemTapEvent, function (args: listViewModule.ItemEventData) {
var tappedItemIndex = args.index;
var tappedItemView = args.view;
// Do someting
});
I get an error "listview is not a constructor" when I do:
listView.on(listViewModule.ListView.itemTapEvent, function (args) {
var tappedItemIndex = args.index;
var tappedItemView = args.view;
// Do someting
});
main-page.js
var observable_1 = require("data/observable");
var file_system_1 = require("file-system");
var listViewModule = require("nativescript-telerik-ui/listview");
var myDesc = [
"Desc 1",
"Desc 2",
"Desc 3",
"Desc 4",
"Desc 5"
];
var myImages = [];
var myBtext = [
"Tap 1",
"Tap 2",
"Tap 3",
"Tap 4",
"Tap 5"
];
function pageLoaded(args) {
readFiles();
var page = args.object;
console.log("start data loading");
console.dir(myImages);
var viewModel = new observable_1.Observable();
viewModel.set("myItems", myDesc);
viewModel.set("myPics", myImages);
viewModel.set("myBt", myBtext);
page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
function func(args) {
var layout = args.view;
var image = layout.getViewById("pic");
image.src = myImages[args.itemIndex];
var button = layout.getViewById("bt");
button.text = myBtext[args.itemIndex];
}
var listView_1 = new listViewModule();
listView_1.on(listViewModule.ListView.itemTapEvent, function(args) {
var tappedItemIndex = args.index;
var tappedItemView = args.view;
console.log(tappedItemIndex)
});
exports.func = func;
function readFiles() {
var documents = file_system_1.knownFolders.currentApp();
var myFolder = documents.getFolder("img");
var array = myFolder.getEntitiesSync();
console.log("array 1");
console.dir(array);
array.forEach(function (element) {
myImages.push(element._path);
});
console.log("get image end");
}
The issue in the code is related to the way that you are attaching to the itemTapEvent.
One way to handle this event is to set up the event name and the name of the callback method in the XML and to define this callback in the code behind. For example:
main-page.xml
<
Page
xmlns
=
"http://schemas.nativescript.org/tns.xsd"
xmlns:lv
=
"nativescript-telerik-ui/listview"
loaded
=
"pageLoaded"
>
<
ActionBar
title
=
"RadListView"
/>
<
lv:RadListView
itemTap
=
"onItemTap"
items
=
"{{ myItems }}"
itemLoading
=
"func"
>
<
lv:RadListView.listViewLayout
>
<
lv:ListViewGridLayout
scrollDirection
=
"Vertical"
itemHeight
=
"200"
spanCount
=
"3"
/>
</
lv:RadListView.listViewLayout
>
<
lv:RadListView.itemTemplate
>
<
StackLayout
>
<
Label
id
=
"label"
text
=
"{{ $value }}"
class
=
"lable"
textWrap
=
"true"
/>
<
Image
id
=
"pic"
height
=
"95"
width
=
"95"
/>
<
Button
id
=
"bt"
/>
</
StackLayout
>
</
lv:RadListView.itemTemplate
>
</
lv:RadListView
>
</
Page
>
main-page.ts
export function onItemTap(args){
console.log("selected item index "+args.itemIndex);
}
export function onItemTap(args){
console.log("selected item index "+args.itemIndex);
}
main-page.xml
<
Page
xmlns
=
"http://schemas.nativescript.org/tns.xsd"
xmlns:lv
=
"nativescript-telerik-ui/listview"
loaded
=
"pageLoaded"
>
<
ActionBar
title
=
"RadListView"
/>
<
lv:RadListView
loaded
=
"lvloaded"
items
=
"{{ myItems }}"
itemLoading
=
"func"
>
<
lv:RadListView.listViewLayout
>
<
lv:ListViewGridLayout
scrollDirection
=
"Vertical"
itemHeight
=
"200"
spanCount
=
"3"
/>
</
lv:RadListView.listViewLayout
>
<
lv:RadListView.itemTemplate
>
<
StackLayout
>
<
Label
id
=
"label"
text
=
"{{ $value }}"
class
=
"lable"
textWrap
=
"true"
/>
<
Image
id
=
"pic"
height
=
"95"
width
=
"95"
/>
<
Button
id
=
"bt"
/>
</
StackLayout
>
</
lv:RadListView.itemTemplate
>
</
lv:RadListView
>
</
Page
>
main-page.ts
import { EventData, Observable } from 'data/observable';
import {ObservableArray} from "data/observable-array"
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
import {StackLayout} from "tns-core-modules/ui/layouts/stack-layout";
import {Image} from "tns-core-modules/ui/image";
import {Button} from "tns-core-modules/ui/button";
import {knownFolders, Folder, FileSystemEntity} from "file-system";
import {RadListView, ListViewEventData} from "nativescript-telerik-ui/listview"
....................................................
export function lvloaded(args){
var listview:RadListView = <
RadListView
>args.object;
listview.on(RadListView.itemTapEvent, function(args:ListViewEventData){
console.log("selected item index "+args.itemIndex);
})
}
main-page.js
var observable_1 = require("data/observable");
var file_system_1 = require("file-system");
var listview_1 = require("nativescript-telerik-ui/listview");
.............................................
function lvloaded(args) {
var listview = args.object;
listview.on(listview_1.RadListView.itemTapEvent, function (args) {
console.log("selected item index " + args.itemIndex);
});
}
exports.lvloaded = lvloaded;
Something that I notice is that you are using the documentation for the pure NativeScript ListView, instead of the this for RadListView, which is provided by nativescript-telerik-ui plugin and which you use in your project.
The right resources could be found in this documentation here and for further help, you could use this sample project.
It would also help if you could open a new ticket for every individual problem, which you have. This will help to separate the issues and also it will be easier for the others to find the solution while reading the forum
Regards,
nikolay.tsonev
Progress Telerik