how to use multiple item templates of nativescript in pure javascript - nativescript

I'm trying to implement multiple item templates for different data.
my xml looks this
<lv:RadListView row="1" items="{{ list_data }}"
itemTemplateSelector="{{ templateSelector }}">
<lv:RadListView.itemTemplate>
<GridLayout rows="*,*" columns="*,auto" margin="15">
<Label row="0" col="0" text="{{ name }}"
textWrap="true" />
<Label row="1" col="0" text="{{ age }}"
textWrap="true" />
<Label rowSpan="2" col="1" text="{{ duration }}"
textWrap="true" />
</GridLayout>
</lv:RadListView.itemTemplate>
<lv:RadListView.itemTemplates>
<template key="break">
<GridLayout rows="*" columns="*,auto" margin="15"
backgroundColor="green">
<Label row="0" col="0" text="break"
textWrap="true" />
<Label rowSpan="2" col="1" text="{{ duration }}"
textWrap="true" />
</GridLayout>
</template>
</lv:RadListView.itemTemplates>
</lv:RadListView>
on viewmodel
var count = 1;
var viewModel = observableModule.fromObject({
list_data: [{ template: "default", name: "crunches", age: "X 30", duration: "45 sec" },
{ template: "break" },
{ template: "default", name: "situp", age: "X 30", duration: "45 sec" },
{ template: "break" },
{ template: "default", name: "jumpingjack", age: "X 30", duration: "45 sec" },
],
templateSelector: function name(args) {
console.log(count++)
return "break";
},
here the templateSelector is getting called 20 times. I don't know how it was working.
I need to change the template based on template in list_data.
this is the complete project link
https://play.nativescript.org/?template=play-js&id=cPzCkf

Related

The spacing issue comes when using the side drawer and scroll view in native script angular

I am developing android and ios applications using native script-angular. I am using UISidedrawer plugin for showing the menu's, I have an issue while using UISidedrawer and ScrollView same time, In my component, space was automatically taken. Here are my code and screenshot.
I am creating a side drawer and menu's like:
<RadSideDrawer [transition]="drawerTransition">
<GridLayout rows="auto,*,110" column="auto" tkDrawerContent height="100%">
<StackLayout row="0" column="0" orientation="vertical" class="sidedrawer-header">
<Label class="italic" text="Welcome "></Label>
</StackLayout>
<ListView row="1" column="0" [items] = "navMenu" rowHeight="40" class="sidedrawer-content" separatorColor="#40053e" (itemLoading)="onItemLoading($event)">
<ng-template>
<StackLayout
//code
</StackLayout>
</ng-template>
</ListView>
<StackLayout row="2" column="0" class="sidedrawer-footer" orientation="vertical">
<Button text="Logout" (tap)="logout()" pageTransition="slideright"></Button>
</StackLayout>
</GridLayout>
<StackLayout tkMainContent>
<StackLayout>
<ng-content></ng-content>
</StackLayout>
</StackLayout>
</RadSideDrawer>
My side drawer component.ts code
import { RadSideDrawerComponent, SideDrawerType } from 'nativescript-ui-sidedrawer/angular';
import { SlideInOnTopTransition } from 'nativescript-ui-sidedrawer';
#Component({
moduleId: module.id,
selector: "side-drawer",
templateUrl: 'side-drawer.component.html',
styleUrls: ['side-drawer.component.css']
})
export class SideDrawerComponent implements AfterViewInit, OnDestroy, OnInit {
#ViewChild(RadSideDrawerComponent) drawerComponent: RadSideDrawerComponent;
private drawer: SideDrawerType;
drawerTransition: any;
navMenu: any[] = [
{id: '0', name: 'Dashboard', icon: '~/Images/dashboard.png', commands: ['/dashboard'] },
{id: '1', name: 'Status', icon: '~/Images/progress.png', commands: ['/status'] },
{id: '2', name: 'Transcript', icon: '~/Images/send.png', commands: ['/transcript'] },
{id: '3', name: 'Change Password', icon: '~/Images/password.png', commands: ['/password'] },
{id: '4', name: 'Support', icon: '~/Images/contact.png', commands: ['/contact'] },
{id: '5', name: 'About Us', icon: '~/Images/about.png', commands: ['/about'] },
{id: '6', name: 'FAQ', icon:'~/Images/faq.png',commands:['/faq']},
];
constructor( ) {
this.drawerTransition = new SlideInOnTopTransition();
}
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
}
}
My menu content html
<side-drawer>
<GridLayout rows="*,100">
<StackLayout row="0" orientation="vertical">
<StackLayout orienatation="vertical">
<ScrollView>
<Label text="Hello World> </Label>
</ScrollView>
</StackLayout>
</StackLayout>
<StackLayout row="1">
</StackLayout>
</GridLayout>
</side-drawer>
How to remove unwanted space. Only the space issue occurs when we use a scroll view inside the side drawer and ios platform only.

Page-router-outlet to get the higher component

I am working on nativescript angular project that using RadSideDrawer
And here my main-routing.module.ts
import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { MainComponent } from "~/app/components/main/main.component";
const routes: Routes = [
{
path: "",
component: MainComponent,
children: [
{ path: "", redirectTo: "/home", pathMatch: "full" },
{ path: "home", loadChildren: "~/app/components/home/home.module#HomeModule" },
{
path: "browse",
loadChildren: "~/app/components/browse/browse.module#BrowseModule"
},
{
path: "search",
loadChildren: "~/app/components/search/search.module#SearchModule"
},
{
path: "featured",
loadChildren: "~/app/components/featured/featured.module#FeaturedModule"
},
{
path: "settings",
loadChildren: "~/app/components/settings/settings.module#SettingsModule"
}
]
}
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class MainRoutingModule {}
here is my main.component.html
<RadSideDrawer [drawerTransition]="sideDrawerTransition">
<GridLayout tkDrawerContent rows="auto, *" class="sidedrawer sidedrawer-left">
<StackLayout row="0" class="sidedrawer-header">
<Label class="sidedrawer-header-image fa" text=""></Label>
<Label class="sidedrawer-header-brand" text="User Name"></Label>
<Label class="footnote" text="username#mail.com"></Label>
</StackLayout>
<ScrollView row="1">
<StackLayout class="sidedrawer-content">
<GridLayout columns="auto, *" class="sidedrawer-list-item" [class.selected]="isComponentSelected('/home')"
(tap)="onNavItemTap('/home')">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Home" class="p-r-10"></Label>
</GridLayout>
<GridLayout columns="auto, *" class="sidedrawer-list-item" [class.selected]="isComponentSelected('/browse')"
(tap)="onNavItemTap('/browse')">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Browse" class="p-r-10"></Label>
</GridLayout>
<GridLayout columns="auto, *" class="sidedrawer-list-item" [class.selected]="isComponentSelected('/search')"
(tap)="onNavItemTap('/search')">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Search" class="p-r-10"></Label>
</GridLayout>
<GridLayout columns="auto, *" class="sidedrawer-list-item" [class.selected]="isComponentSelected('/featured')"
(tap)="onNavItemTap('/featured')">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Featured" class="p-r-10"></Label>
</GridLayout>
<StackLayout class="hr-light"></StackLayout>
<GridLayout columns="auto, *" class="sidedrawer-list-item" [class.selected]="isComponentSelected('/settings')"
(tap)="onNavItemTap('/settings')">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Settings" class="p-r-10"></Label>
</GridLayout>
<GridLayout columns="auto, *" class="sidedrawer-list-item" (tap)="signOut()">
<Label col="0" text="" class="fa"></Label>
<Label col="1" text="Signout" class="p-r-10"></Label>
</GridLayout>
</StackLayout>
</ScrollView>
</GridLayout>
<page-router-outlet tkMainContent class="page page-content"></page-router-outlet>
</RadSideDrawer>
here is my app-routing.module.ts
import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { AuthGuard } from "~/app/shared/services/auth-guard.service";
import { LogGuard } from "~/app/shared/services/log-guard.service";
const routes: Routes = [
{
path: "",
loadChildren: "~/app/components/main/main.module#MainModule",
canActivate: [AuthGuard]
},
{
path: "login",
loadChildren: "~/app/components/login/login.module#LoginModule",
canActivate: [LogGuard]
},
{
path: "register",
loadChildren: "~/app/components/register/register.module#RegisterModule",
canActivate: [LogGuard]
}
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {}
and here my app.component.html
<app-no-connection></app-no-connection>
<page-router-outlet></page-router-outlet>
and here my home.component.html
<ActionBar class="action-bar">
<NavigationButton ios:visibility="collapsed" icon="res://menu" (tap)="onDrawerButtonTap()"></NavigationButton>
<ActionItem icon="res://navigation/menu" android:visibility="collapsed" (tap)="onDrawerButtonTap()" ios.position="left">
</ActionItem>
<Label class="action-bar-title" text="Home"></Label>
</ActionBar>
<GridLayout class="page page-content">
<Label class="page-icon fa" text=""></Label>
<Label class="page-placeholder" text="<!-- Page content goes here -->"></Label>
</GridLayout>
and here my home.component.ts
import { Component, OnInit } from "#angular/core";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import * as app from "tns-core-modules/application";
#Component({
selector: "Home",
moduleId: module.id,
templateUrl: "./home.component.html"
})
export class HomeComponent implements OnInit {
constructor() {
// Use the component constructor to inject providers.
console.log("ini home");
}
ngOnInit(): void {
// Init your component properties here.
}
onDrawerButtonTap(): void {
console.log("tapped side bar");
const sideDrawer = <RadSideDrawer>app.getRootView();
sideDrawer.showDrawer();
}
}
my RadSideDrawer is not in app.component.html. It is in main.component.html. so in my app.component.html just has <page-router-outlet></page-router-outlet>.
I did like that because I need to login first before get the MainComponent.
But. It doesn't work. my RadSideDrawer not shown. And I don't understand why i got this error ERROR TypeError: sideDrawer.showDrawer is not a function when i tap drawer on home.component.html
Any suggestion please?
<RadSideDrawer [drawerTransition]="sideDrawerTransition" tkExampleTitle tkToggleNavButton>
<StackLayout tkDrawerContent class="sideStackLayout">
<!-- Your navigation drawer items -->
</StackLayout>
<page-router-outlet tkMainContent></page-router-outlet>
</RadSideDrawer>
AppComponent
#ViewChild(RadSideDrawerComponent) public drawerComponent: RadSideDrawerComponent;
private drawer: RadSideDrawer;
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
this.drawer.gesturesEnabled = false; // To disbale the drawer.
}
// Code to enable Drawer:
this.drawer.gesturesEnabled = true;
// Controll sidedrawer from Other Screen
sideDrawer = <RadSideDrawer>app.getRootView();
this.sideDrawer.gesturesEnabled = true;

RadListView - Update a textfield value

I have a product list in RadListView and each product has a quantity selector. User can press + - buttons to increase or decrease the quantity or can type into the textfield too. All these controls are working and data is being updated in the observable but not on the screen. THe value being shown in the textfield doesn't update on screen. Here's the code:
<StackLayout col="1" orientation="horizontal" class="qtySelect bg-secondary">
<Label class="mdi qtyButtons" text="" pid="{{ id }}" tap="qtyDecrease" />
<TextField text="{{ quantity }}" keyboardType="Number" verticalAlignment="top" class="qtyText" />
<Label class="mdi qtyButtons" text="" pid="{{ id }}" tap="qtyIncrease" />
</StackLayout>
JS
function findById(pid){
var index;
products.forEach (function(elem, i) {
if(elem.id == pid){
index = i;
}
});
return index;
}
exports.qtyDecrease = function(args){
var index = findById(args.object.pid);
console.log(index);
var product = products.getItem(index);
if(product.min_order < product.quantity)
product.quantity = parseInt(product.quantity)-1;
else
Toast.makeText("Minimum quantity of "+product.min_order+" is required for this product.").show();
products.set(index, product);
}
exports.qtyIncrease = function(args){
var index = findById(args.object.pid);
console.log(index);
var product = products.getItem(index);
product.quantity = parseInt(product.quantity)+1;
products.set(index, product);
}
If I scroll the item out of view and back in, I can see the updated values. I tried refresh() method on the list but that makes the list scroll to the top which is undesirable.
So how can I force refresh on just that element?
Edit: Full code
<lv:RadListView row="1" items="{{ products }}" id="productList">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout scrollDirection="Vertical" spanCount="2" />
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<GridLayout rows="{{ width+', auto' }}" class="borders">
<fresco:FrescoDrawee row="0" width="{{ width }}" height="{{ width }}" decodeWidth="{{ width }}" decodeHeight="{{ width }}" imageUri="{{ image }}" placeholderImageUri="~/images/loading.jpg" failureImageUri="~/images/loading.jpg" progressiveRenderingEnabled="true" id="{{ 'product'+id }}" tap="selectItem" />
<StackLayout row="1" class="card-content bg-white">
<label text="{{ name }}" class="bold" />
<Label text="{{ 'Net Weight: '+netWeight+' gms' }}" class="h6 text-black" />
<GridLayout columns="auto,auto">
<Label col="0" text="Qty: " class="h6 text-black" />
<StackLayout col="1" orientation="horizontal" class="qtySelect bg-secondary">
<Label class="mdi qtyButtons" text="" pid="{{ id }}" tap="qtyDecrease" />
<TextField text="{{ quantity }}" keyboardType="Number" verticalAlignment="top" class="qtyText" />
<Label class="mdi qtyButtons" text="" pid="{{ id }}" tap="qtyIncrease" />
</StackLayout>
</GridLayout>
<Button text="{{ addToCartText }}" class="btn trans-white" padding="0" pid="{{ id }}" tap="addToCart" />
</StackLayout>
</GridLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
JS
const screenWidth = settings.getNumber("screenWidth");
var boxWidth = screenWidth/2;
var page;
var prodSearchCriteria;
var productRadList;
var productsVM;
var products;
var numProductsView;
function loadProducts(criteria){
http.request({
url: config.apiUrl+"products.php",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({
auth: config.apiAuth,
criteria: criteria
})
}).then(function(request){
var response = JSON.parse(request.content);
productsVM.set("numProducts", response.data.length);
productsVM.set("minWeight", response.min_weight);
productsVM.set("maxWeight", response.max_weight);
productsVM.set("designs", response.designs);
products.length = 0;
for (var i = 0; i < response.data.length; i++) {
products.push({
id: response.data[i].id,
image: config.siteUrl+"/product_img/"+response.data[i].image,
name: response.data[i].name,
netWeight: response.data[i].net_weight,
width: boxWidth,
min_order: response.data[i].min_order,
quantity: response.data[i].min_order,
addToCartText: "Add to Cart"
});
}
productIdsString = productIdsString.slice(0, -1);
numProductsView.resetNativeView();
}, function(error){
console.log(JSON.stringify(error));
});
}
exports.onLoaded = function(args) {
page = args.object;
prodSearchCriteria = page.navigationContext;
if("filters" in prodSearchCriteria){
} else {
prodSearchCriteria.filters = {};
}
productsVM = new observableModule.fromObject({
userAvatar: settings.getString("userAvatar"),
userEmail: settings.getString("userEmail"),
cartNumProducts: settings.getNumber("cartNumProducts"),
cartNetWeight: settings.getNumber("cartNetWeight"),
cartFineWeight: settings.getNumber("cartFineWeight"),
cartLabor: settings.getNumber("cartLabor"),
numProducts: 0,
minWeight: 0,
maxWeight: 0,
designs: []
});
products = new observableArrayModule.ObservableArray();
page.bindingContext = productsVM;
productsVM.set("products", products);
numProductsView = view.getViewById(page, "numProducts")
productRadList = view.getViewById(page, "productList");
loadProducts(prodSearchCriteria);
}
Try to wrap the quantity change in setTimeout() of 10 milliseconds
Did you try to bind data again manually (in increase -decrease functions and in textfield’s changed event)?

Nativescript iOS error

I am using NS 2.3 with AppBuilder. Recently I started seeing the following error in my console:
UIDataDetectorTypeLegacyPhoneNumber is incompatible with other types
Here is the markup of th epage where the error occurs:
<Page xmlns="http://schema.nativescript.org/tns.xsd" actionBarHidden="true" loaded="pageLoaded" navigatingTo="onNavigatingTo" xmlns:drawer="nativescript-telerik-ui/sidedrawer" xmlns:sharedDrawers="widgets/drawers">
<drawer:RadSideDrawer id="mainDrawer">
<drawer:RadSideDrawer.mainContent>
<ScrollView id="wrapper" opacity="0">
<DockLayout stretchLastChild="true">
<StackLayout class="bg" dock="top" paddingTop="7">
<GridLayout id="mainHeader" rows="auto" columns="auto, *, auto" dock="top">
<Button class="icomoon-icon" text="" row="0" col="0" horizontalAlignment="center" verticalAlignment="center" tap="openDrawer" fontSize="18"/>
<Label class="title" horizontalAlignment="center" text="Page Title" row="0" col="1" />
<Button class="icomoon-icon" text="" row="0" col="2" horizontalAlignment="center" verticalAlignment="center" tap="close" fontSize="20" />
</GridLayout>
<Image src="~/images/img.png" width="130" />
<Label text="{{ greeting }}" class="greeting" />
</StackLayout>
<StackLayout dock="top" cssClass="content">
<Label class="heading" text="some text..." textWrap="true" />
<Label id="text" text="some more text..." class="text" textWrap="true" />
<HtmlView id="h-privacy" class="h-view" html="{{ privacy }}" tap="toPrivacyPolicy" />
<Label cssClass="button" text="continue" tap="next" />
<HtmlView id="h-notices" class="h-view" html="{{ notices }}" tap="toNotices" marginTop="10" />
</StackLayout>
</DockLayout>
</ScrollView>
</drawer:RadSideDrawer.mainContent>
<drawer:SideDrawer.drawerContent>
<sharedDrawers:mainDrawer />
</drawer:SideDrawer.drawerContent>
</drawer:RadSideDrawer>
</Page>
The page simple displays some text to the user and has a button to move to the next screen. When the page is loaded, the above error shows 4 times in the output window. Note that the app still works without a problem, I was just curious why am I getting this error and how to prevent it from happening.
Here is the loaded event code:
function pageLoaded(args) {
loader.show();
var page = args.object;
var lang = appSettings.getString('languageCode', 'en');
model.set('strings', lang == 'en' ? en : es);
//get the personal information
model.set('customer', JSON.parse(global.user));
//set the greeting
var greeting = '';
var hour = (new Date()).getHours();
if (hour >= 0 && hour < 12) {
greeting = 'Good morning, ' + model.customer.firstName;
}
if (hour >= 12 && hour < 17) {
greeting = 'Good afternoon, ' + model.customer.firstName;
}
if (hour >= 17 && hour <= 23) {
greeting = 'Good evening, ' + model.customer.firstName;
}
model.set('greeting', greeting);
loader.hide();
page.getViewById('wrapper').animate({
opacity: 1,
duration: 1000
});
model.set('privacy', 'some text');
model.set('notices', 'some text');
//set the line height
var lbl = page.getViewById('text');
func.labelLineHeight(lbl);
page.bindingContext = model;
if (page.ios) {
var fontSize = 14;
var fontName = 'HelveticaNeue';
var hp = page.getViewById('h-privacy');
hp.ios.font = UIFont.fontWithNameSize(fontName, fontSize);
hp.marginLeft = -5;
var hn = page.getViewById('h-notices');
hn.ios.font = UIFont.fontWithNameSize(fontName, fontSize);
hn.marginLeft = -5;
}
}
project.json:
{
"nativescript": {
"id": "com.company.appname"
},
"dependencies": {
"moment": "2.14.1",
"moment-timezone": "0.5.5",
"nativescript-background-http": "2.4.0",
"nativescript-email": "1.3.3",
"nativescript-intl": "0.0.4",
"nativescript-iqkeyboardmanager": "1.0.0",
"nativescript-loading-indicator": "2.2.1",
"nativescript-maskedinput": "0.0.3",
"nativescript-phone": "1.2.3",
"nativescript-social-share": "1.3.1",
"nativescript-telerik-ui": "1.5.0",
"nativescript-touchid": "2.1.0",
"tns-core-modules": "2.3.0",
"nativescript-push-notifications": "0.0.19",
"nativescript-pdf-view": "file:nativescript-pdf-view-1.2.0.tgz"
},
"devDependencies": {}
}
Does anyone have a an idea what this is about?
Thank you.

NativeScript, In ListView, ItemTap event is not working

In ListView, ItemTap event is not working.
<ListView items="{{ menu }}" row="1" itemTap="listViewItemTap" >
<ListView.itemTemplate>
<GridLayout columns="auto, *">
<Image src="{{ imageURL }}" row="0" cssClass="icon"/>
<StackLayout col="1">
<Label text="{{ title }}" cssClass="name"/>
<Label text="{{ subtitle }}" cssClass="location"/>
</StackLayout>
</GridLayout>
</ListView.itemTemplate>
</ListView>
Can you make sure you have the listViewItemTap exported in your code.
I have tried the following and seems to work OK:
XML:
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo">
<ListView items="{{ menu }}" row="1" itemTap="listViewItemTap" >
<ListView.itemTemplate>
<GridLayout columns="auto, *">
<Image src="{{ imageURL }}" row="0" cssClass="icon"/>
<StackLayout col="1">
<Label text="{{ title }}" cssClass="name"/>
<Label text="{{ subtitle }}" cssClass="location"/>
</StackLayout>
</GridLayout>
</ListView.itemTemplate>
</ListView>
</Page>
JS:
exports.onNavigatingTo = function(args) {
var page = args.object;
page.bindingContext = {
menu:[
{ imageUrl: "", title: "title 1", subtitle: "subtitle 1"},
{ imageUrl: "", title: "title 2", subtitle: "subtitle 2"},
{ imageUrl: "", title: "title 3", subtitle: "subtitle 3"},
{ imageUrl: "", title: "title 4", subtitle: "subtitle 4"},
]
}
}
exports.listViewItemTap = function() {
console.log("Item tapped!");
}
Also one thing to look for:
If you are not using binding for the itemTap event(as in the XML you posted) - you should provide the event handler in the code-behind of the page.
If you are using binding (itemTap="{{ listViewItemTap }}") you should provide the event handler in your bindingContext object.

Resources