I'm trying to get this to work, but it only gives me following error. I did almost the same thing for the nativescript-groceries app, but angular2-seed-advanced has a somewhat different architecture, seems to be a dependency injection problem somewhere between nativescript and the seed project and the telerik-ui.
Any help is appreciated:
EXCEPTION: Error in
/data/data/com.yourdomain.appname/files/app/app/components/app.component.tns.html:0:0
ORIGINAL EXCEPTION: TypeError: Cannot read property 'android' of undefined
ORIGINAL STACKTRACE:
TypeError: Cannot read property 'android' of undefined
at RadSideDrawer.initOldDrawer (/data/data/com.yourdomain.appname/files/app/tns_modules/nativescript-telerik-ui/sidedrawer/sidedrawer.js:91:40)
at RadSideDrawer._createUI (/data/data/com.yourdomain.appname/files/app/tns_modules/nativescript-telerik-ui/sidedrawer/sidedrawer.js:147:18)
at RadSideDrawer.View._onContextChanged (/data/data/com.yourdomain.appname/files/app/tns_modules/ui/core/view.js:197:14)
at RadSideDrawer.View._onAttached (/data/data/com.yourdomain.appname/files/app/tns_modules/ui/core/view.js:149:14)
at Page.View._addViewCore (/data/data/com.yourdomain.appname/files/app/tns_modules/ui/core/view.js:125:18)
at Page.View._addView (/data/data/com.yourdomain.appname/files/app/tns_modules/ui/core/view-common.js:952:14)
at Page.Object.defineProperty.set [as content] (/data/data/com.yourdomain.appname/files/app/tns_modules/ui/content-view/content-view.js:19:22)
at ViewUtil.insertChild (/data/data/com.yourdomain.appname/files/app/tns_modules/nativescript-angular/view-util.js:56:28)
at ViewUtil.createAndAttach (/data/data/com.yourdomain.appname/files/app/tns_modules/nativescript-angular/view-util.js:103:18)
at ViewUtil.createView (/data/data/com.yourdomain.appname/files/app/tns_modules/nativescript-angular/view-util.js:110:25)
ERROR CONTEXT:
[object Object]
Here are my changes
nativescript/package.json
### Added dependency
"nativescript-telerik-ui": "^1.3.1",
nativescript/app/native.module.ts
...
import {SIDEDRAWER_PROVIDERS} from 'nativescript-telerik-ui/sidedrawer/angular';
...
#NgModule({
...
providers: [
NS_ANALYTICS_PROVIDERS,
### Added sidedrawer providers
SIDEDRAWER_PROVIDERS,
{ provide: RouterExtensions, useClass: TNSRouterExtensions }
],
...
})
export class NativeModule { }
nativescript/app/pages/app/app.component.ts:
...
import {Inject, ChangeDetectorRef} from '#angular/core';
...
import {Page} from 'ui/page';
...
export class NSAppComponent extends AppComponent {
constructor(
#Inject(Page) private _page: Page,
private _changeDetectionRef: ChangeDetectorRef,
#Inject(AnalyticsService) public analytics: AnalyticsService,
#Inject(LogService) private log: LogService,
#Inject(Store) private store: Store<any>,
#Inject(Router) private router: Router)
{
// ### ADDED Page and ChangeDetectionRef
super(_page, _changeDetectionRef, analytics, log);
...
nativescript/app/app/components/app.component.ts
...
import {ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, AfterViewInit} from '#angular/core';
...
import {
SIDEDRAWER_DIRECTIVES,
RadSideDrawerComponent,
SideDrawerType
} from 'nativescript-telerik-ui/sidedrawer/angular';
import {DrawerTransitionBase, PushTransition} from 'nativescript-telerik-ui/sidedrawer';
import {Page} from 'ui/page';
...
#BaseComponent(
{
moduleId : module.id,
selector : 'sd-app',
templateUrl : 'app.component.html',
directives : [SIDEDRAWER_DIRECTIVES],
changeDetection: ChangeDetectionStrategy.Default // Everything else uses OnPush
}
)
export class AppComponent implements AfterViewInit {
private _currentNotification: string;
private _sideDrawerTransition: DrawerTransitionBase;
#ViewChild(RadSideDrawerComponent) public drawerComponent: RadSideDrawerComponent;
private drawer: SideDrawerType;
constructor(
private page: Page,
private changeDetectionRef: ChangeDetectorRef,
public analytics: AnalyticsService,
public logger: LogService)
{
logger.debug(`Config env: ${Config.ENVIRONMENT().ENV}`);
this.page.on("loaded", this.onLoaded, this);
}
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
this.changeDetectionRef.detectChanges();
}
public onLoaded(args) {
this._sideDrawerTransition = new PushTransition();
}
public get sideDrawerTransition(): DrawerTransitionBase {
return this._sideDrawerTransition;
}
public get currentNotification(): string {
return this._currentNotification;
}
public openDrawer() {
this.drawer.showDrawer();
}
public onDrawerOpening() {
console.log("Drawer opening");
this._currentNotification = "Drawer opening";
}
public onDrawerOpened() {
console.log("Drawer opened");
this._currentNotification = "Drawer opened";
}
public onDrawerClosing() {
console.log("Drawer closing");
this._currentNotification = "Drawer closing";
}
public onDrawerClosed() {
console.log("Drawer closed");
this._currentNotification = "Drawer closed";
}
}
nativescript/app/app/components/app.component.tns.html
<RadSideDrawer #drawer>
<StackLayout tkDrawerContent class="sideStackLayout">
<StackLayout class="sideTitleStackLayout">
<Label text="Navigation Menu"></Label>
</StackLayout>
<StackLayout class="sideStackLayout">
<Label text="MenuItemA" ></Label>
<Label text="MenuItemB" ></Label>
<Label text="MenuItemC" ></Label>
</StackLayout>
</StackLayout>
<StackLayout tkMainContent>
<!-- nested original content in Drawer -->
<ActionBar title="Test" class="action-bar">
<ActionItem ios.position="right" android.position="popup">
<Button [text]="'MENU' | translate" (tap)=openDrawer() class="action-btn"></Button>
</ActionItem>
<ActionItem nsRouterLink="/about" ios.position="right" android.position="popup">
<Button [text]="'ABOUT' | translate" class="action-btn"></Button>
</ActionItem>
</ActionBar>
<StackLayout class="container">
<lang-switcher></lang-switcher>
<ScrollView>
<page-router-outlet></page-router-outlet>
</ScrollView>
</StackLayout>
</StackLayout>
nativescript/app/app/components/app.component.tns.css
.sideStackLayout {
background-color: white;
}
Ok, got it to work and wanted to share this, as it is not exactly straightforward or especially well documented...
With the release of nativescript-telerik-ui 1.4.1 and the final 2.0.0 release of Angular this is pretty easy actually.
nativescript/package.json
### Added dependency
"nativescript-telerik-ui": "^1.4.1",
nativescript/app/native.module.ts
...
import { SIDEDRAWER_DIRECTIVES } from 'nativescript-telerik-ui/sidedrawer/angular';
...
#NgModule({
...
declarations: [
SIDEDRAWER_DIRECTIVES, ### allows usage of <RadSideDrawer> in pages
HomeComponent,
AboutComponent
],
...
})
export class NativeModule { }
nativescript/app/pages/app/app.component.ts:
no changes - drawer is supposed to be used per page
nativescript/app/app/components/app.component.ts
no changes - drawer is supposed to be used per page
nativescript/app/app/components/about/about.component.ts
import {ViewChild, ChangeDetectorRef, Inject} from '#angular/core';
...
import {RadSideDrawerComponent, SideDrawerType } from 'nativescript-telerik-ui/sidedrawer/angular';
import {DrawerTransitionBase, PushTransition} from 'nativescript-telerik-ui/sidedrawer';
import {Page} from 'ui/page';
...
export class AboutComponent {
private _currentNotification: string;
private _sideDrawerTransition: DrawerTransitionBase;
#ViewChild(RadSideDrawerComponent) public drawerComponent: RadSideDrawerComponent;
private drawer: SideDrawerType;
constructor(
private page: Page,
private changeDetectionRef: ChangeDetectorRef )
{
this.page.on("loaded", this.onLoaded, this);
}
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
this.changeDetectionRef.detectChanges();
}
public onLoaded(args) {
this._sideDrawerTransition = new PushTransition();
}
public get sideDrawerTransition(): DrawerTransitionBase {
return this._sideDrawerTransition;
}
public get currentNotification(): string {
return this._currentNotification;
}
public openDrawer() {
this.drawer.showDrawer();
}
public onDrawerOpening() {
console.log("Drawer opening");
this._currentNotification = "Drawer opening";
}
public onDrawerOpened() {
console.log("Drawer opened");
this._currentNotification = "Drawer opened";
}
public onDrawerClosing() {
console.log("Drawer closing");
this._currentNotification = "Drawer closing";
}
public onDrawerClosed() {
console.log("Drawer closed");
this._currentNotification = "Drawer closed";
}
}
nativescript/app/app/components/app.component.tns.html
<RadSideDrawer #drawer
(drawerOpening)="onDrawerOpening()"
(drawerOpened)="onDrawerOpened()"
(drawerClosing)="onDrawerClosing()"
(drawerClosed)="onDrawerClosed()"
[transition]="sideDrawerTransition">
<StackLayout tkDrawerContent class="sideStackLayout">
<Label text="MenuItemA" ></Label>
<Label text="MenuItemB" ></Label>
<Label text="MenuItemC" ></Label>
</StackLayout>
<StackLayout tkMainContent>
<!-- nested original content in Drawer -->
<ActionBar title="Test" class="action-bar">
<ActionItem ios.position="right" (tap)=openDrawer() android.position="popup">
<Button [text]="'MENU' | translate" class="action-btn"></Button>
</ActionItem>
<ActionItem nsRouterLink="/about" ios.position="right" android.position="popup">
<Button [text]="'ABOUT' | translate" class="action-btn"></Button>
</ActionItem>
</ActionBar>
<StackLayout>
<Label text="Angular 2 Seed Advanced is ...
...
</StackLayout>
</StackLayout>
nativescript/app/app/components/app.component.tns.css
.sideStackLayout {
background-color: white;
}
Related
I am trying to create a dropdown in my nativescript angular app by using nativescript dropdown plugin. I am seeing an error "Dropdown(1) is not a valid view instance" when I run the app
import { DropDownModule } from "nativescript-drop-down/angular";
.html file
<GridLayout rows="auto, auto, auto, *"
columns="auto, *" (tap)="openVersionDropdown()" >
<DropDown #dd backgroundColor="red" [items]="itemsVersion"
[selectedIndex]="selectedVersionIndex" (opened)="onopen()"
(closed)="onclose()" (selectedIndexChange)="onVersionChange($event)" row="0" colSpan="2"></DropDown>
<Label text="Selected Index:"
row="1"
col="0"
fontSize="18"
verticalAlignment="bottom"></Label>
<Label [text]="selectedVersionIndex"
row="1"
col="1"></Label>
ts file
import {DropDown, SelectedIndexChangedEventData, ValueList} from "nativescript-drop-down";
....
public itemsVersion: ValueList<string>;
selectedVersionIndex : number;
public onopen() {
console.log("Drop Down opened.");
}
public onclose() {
console.log("Drop Down closed.");
}
public changeStyles() {
this.cssClass = "changed-styles";
}
openVersionDropdown(){
let dropdown = <DropDown>this.page.getViewById('ddVersion');
dropdown.open();
}
onVersionChange(args: SelectedIndexChangedEventData){
console.log(`Drop Down selected index changed from ${args.oldIndex} to ${args.newIndex}. `);
}
ngOnInit(): void {
this.itemsVersion = new ValueList<string>();
for (let loop = 0; loop < 5; loop++) {
this.itemsVersion.push({
value: `${loop}` ,
display: "Item "+ loop,
});
}
}
Try to this for add dropdown in application:
1.demo.module.ts:-
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { DemoComponent } from "./demo.component";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { DropDownModule } from "nativescript-drop-down/angular";
#NgModule({
imports: [
NativeScriptCommonModule,
NativeScriptFormsModule,
DropDownModule,
],
declarations: [
DemoComponent
],
providers: [
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class DemoModule { }
2.demo.component.html:-
<GridLayout row="0" rows="auto" col="0" columns="*,auto"
class="demo-container" ios:style="padding:8">
<DropDown row="0" col="0" #ddlInitial [items]="initialList"
[selectedIndex]="initialSelectedIndex" ios:style="padding:8"
(selectedIndexChanged)="onInitialChange($event)"
hint="Initial"
class="eloha-font-semibold demo-drop-input">
</DropDown>
<Label row="0" col="1" text="" class="fa set-icon-color"
[ngClass]="{'font-size-lg': !isTablet, 'font-size-lg-tablet': isTablet}"
verticalAlignment="middle" android:style="padding-right: 10"></Label>
</GridLayout>
3.demo.component.ts:-
import { Component, OnInit, NgZone, ChangeDetectorRef, ChangeDetectionStrategy, ViewChild, AfterViewInit, ElementRef } from "#angular/core";
import * as frameModule from "tns-core-modules/ui/frame";
import { isIOS, device } from "tns-core-modules/platform";
import * as orientation from 'nativescript-orientation';
import { RouterExtensions } from "nativescript-angular/router";
import * as dialogs from "tns-core-modules/ui/dialogs";
import { DeviceType } from "tns-core-modules/ui/enums";
import { ActivatedRoute } from "#angular/router";
import { SelectedIndexChangedEventData, ValueList } from "nativescript-drop-down";
import { DatePipe } from "#angular/common";
#Component({
selector: "Demo",
moduleId: module.id,
templateUrl: "./demo.component.html",
styleUrls: ['./demo.component.css'],
providers: [DatePipe]
})
export class AddFamilyComponent implements OnInit {
public isTablet: boolean = false;
//Value
public initialList: ValueList<string>;
//Get dropDown selected index
public initialSelectedIndex = 0;
constructor(private zone: NgZone,
private _ref: ChangeDetectorRef,
private route: ActivatedRoute,
private datePipe: DatePipe,
private routerExtensions: RouterExtensions) {
this.isIos = isIOS;
this.pageIndex = "2";
}
ngOnInit(): void {
orientation.setOrientation("portrait");
orientation.disableRotation();
}
ngAfterViewInit(): void {
if (isIOS) {
const controller = frameModule.topmost().ios.controller;
// get the view controller navigation item
const navigationItem = controller.visibleViewController.navigationItem;
// hide back button
navigationItem.setHidesBackButtonAnimated(true, false);
}
}
//Add initial value
getInitialValueList() {
let initialSource = new ValueList<string>([
{ value: "Mr", display: "Mr" },
{ value: "Mrs", display: "Mrs" },
{ value: "Miss", display: "Miss" }
]);
this.initialList = initialSource;
}
//Change initial selection value
onInitialChange(args: SelectedIndexChangedEventData) {
let initialValue = this.initialList.getValue(args.newIndex);
}
}
4. demo.component.css:-
.demo-drop-input {
font-size: 17;
padding-top: 5;
padding-left: 5;
padding-right: 0;
padding-bottom: 5;
border-radius: 30;
background: #fffff;
}
I am building a nativescript carousel using the nativescript-carousel pluging but when I do tns build android I am getting this error:
node_modules/nativescript-carousel/index.d.ts(1,22): error TS6053: File 'D:/Documents/coursera_examples/nativescript/VilcabambaHotel/node_modules/nativescript-carousel/node_modules/tns-platform-declarations/android.d.ts' not found.
My home.component.html carousel is this:
<GridLayout horizontalAlignment="center" verticalAlignment="top" rows="*" columns="*" height="95%">
<Carousel #carousel ios:indicatorOffset="0,-10" ios:finite="true" ios:bounce="false" showIndicator="true" height="100%" indicatorAnimation="SWAP"
indicatorColor="#66ccff" indicatorColorUnselected="#cceeff" height="250" width="80%">
<CarouselItem backgroundColor="white" height="100%">
<GridLayout *ngIf="cabin">
<Image [src]="BaseURL + cabin.image" ></Image>
</GridLayout>
</CarouselItem>
<CarouselItem backgroundColor="white">
<GridLayout *ngIf="house">
<Image [src]="BaseURL + house.image" ></Image>
</GridLayout>
</CarouselItem>
<CarouselItem backgroundColor="white">
<GridLayout *ngIf="ecoactivity">
<Image [src]="BaseURL + ecoactivity.image" ></Image>
</GridLayout>
</CarouselItem>
</Carousel>
</GridLayout>
this is my home.component.ts
import { Component, OnInit, Inject, ChangeDetectorRef } from '#angular/core';
//import { TNSFontIconService } from 'nativescript-ngx-fonticon';
import { Page } from "ui/page";
import { View } from "ui/core/view";
import { SwipeGestureEventData, SwipeDirection } from "ui/gestures";
import * as enums from "ui/enums";
import { Cabin } from '../shared/cabin';
import { CabinService } from '../services/cabin.service';
import { House } from '../shared/house';
import { HouseService } from '../services/house.service';
import { Ecoactivity } from '../shared/ecoactivity';
import { EcoactivityService } from '../services/ecoactivity.service';
import { DrawerPage } from '../shared/drawer/drawer.page';
import { registerElement } from 'nativescript-angular/element-registry';
import { Carousel, CarouselItem } from 'nativescript-carousel';
registerElement('Carousel', () => Carousel);
registerElement('CarouselItem', () => CarouselItem);
#Component({
selector: 'app-home',
moduleId: module.id,
templateUrl: './home.component.html',
// styleUrls: ['./home.component.css']
})
export class HomeComponent extends DrawerPage implements OnInit {
cabin: Cabin;
house: House;
ecoactivity: Ecoactivity;
cabinErrMess: string;
houseErrMess: string;
ecoactivityErrMess: string;
constructor(private cabinservice: CabinService,
private houseservice: HouseService,
private ecoactivityservice: EcoactivityService,
private changeDetectorRef: ChangeDetectorRef,
private page: Page,
// private fonticon: TNSFontIconService,
#Inject('BaseURL') private BaseURL) {
super(changeDetectorRef);
}
ngOnInit() {
this.cabinservice.getFeaturedCabin()
.subscribe(cabin => this.cabin = cabin,
errmess => this.cabinErrMess = <any>errmess);
this.houseservice.getFeaturedHouse()
.subscribe(house => this.house = house,
errmess => this.houseErrMess = <any>errmess);
this.ecoactivityservice.getFeaturedEcoactivity()
.subscribe(ecoactivity => this.ecoactivity = ecoactivity,
errmess => this.ecoactivityErrMess = <any>errmess);
}
The error disapears if I remove the next lines of code but my carousel stops working
import { registerElement } from 'nativescript-angular/element-registry';
import { Carousel, CarouselItem } from 'nativescript-carousel';
registerElement('Carousel', () => Carousel);
registerElement('CarouselItem', () => CarouselItem
I created a document called reference.d.ts with the next lines of code but the error is still there.
/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />
/// <reference path="./node_modules/tns-platform-declarations/android.d.ts" />
Looks like a improper usage of declaration within plugin, you could manually adjust it by updating the path to
/// <reference path="../tns-platform-declarations/android.d.ts" />
from
/// <reference path="./node_modules/tns-platform-declarations/android.d.ts" />
in index.d.ts
Edit:
If you still find any other TS errors, you may simply add "skipLibCheck": true inside compilerOptions in your tsconfig.json.
I’m new to NativeScript so please excuse me if I’m asking a stupid question. I tried to figure it out using google for days now but had no success.
On the bottom of the app I have some labels with icon font. So what I want to do is to change the label color when clicked.
Screenshot
Here is my app.components.ts
import { Component } from "#angular/core";
import * as dockModule from "tns-core-modules/ui/layouts/dock-layout";
import { TNSFontIconService } from 'nativescript-ng2-fonticon';
import {topmost} from "ui/frame";
import {Page} from "ui/page";
#Component({
selector: "my-app",
template: `
<!-- <ActionBar title="Rupa GIS" class="action-bar" font-size= "7"></ActionBar> -->
<ActionBar title="Rupa GIS" android.icon="res://icon" android.iconVisibility="always" class="action-bar" ></ActionBar>
<!-- Your UI components go here -->
<Page class="pg">
<DockLayout class="formMessag">
<GridLayout class="formMessage1" columns="2*,2*,2*,2*" rows="" dock="bottom" verticalAlignment="bottom" class="mdi" >
<Label class="mdi1" id="dd" [text]="'mdi-map' | fonticon" row="0" col="0" (tap)="onTapMap()" backgroundColor="transparent" verticalAlignment="center" horizontalAlignment="center" ></Label>
<Label class="mdi2" [text]="'mdi-camera' | fonticon" row="0" col="1" (tap)="onTapCam()" backgroundColor="transparent" verticalAlignment="center" horizontalAlignment="center" ></Label>
<Label class="mdi3" [text]="'mdi-info' | fonticon" row="0" col="2" (tap)="onTapInfo()" backgroundColor="transparent" verticalAlignment="center" horizontalAlignment="center" ></Label>
<Label class="mdi4" [text]="'mdi-settings' | fonticon" row="0" col="3" (tap)="onTapSett()" backgroundColor="transparent" verticalAlignment="center" horizontalAlignment="center" ></Label>
</GridLayout>
</DockLayout>
</Page>
`
})
export class AppComponent {
// Your TypeScript logic goes here
// var isSelected = "true";
onTapMap(dd) {
// boolean isSelected = true;
let self = this;
console.log("MAPA");
}
onTapCam() {
console.log("KAMERA");
}
onTapInfo() {
console.log("INFORMACIJE");
}
onTapSett() {
console.log("PODESAVANJA");
}
constructor(private fonticon: TNSFontIconService, private page: Page) {
page.actionBarHidden = true;
}
}
export function pageLoaded() {
console.log("DOBAR DAN!");
}
And here is my app.module.ts
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { TNSFontIconModule } from 'nativescript-ng2-fonticon';
import { AppComponent } from "./app.component";
#NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
imports: [
NativeScriptModule,
TNSFontIconModule.forRoot({
'mdi': 'material-design-icons.css'
})
],
schemas: [NO_ERRORS_SCHEMA],
})
export class AppModule {}
And here is the main.ts
And here is the main.ts
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app.module";
platformNativeScriptDynamic().bootstrapModule(AppModule);
How could I make it so that the onTapMap function changes the color of a label? Any advise or guidance would be greatly appreciated.
Thank you!
Srdjan
You can apply class based on tap events -
<Label class="{{ checkYes ? 'redColor' : 'defaultColor'}}" id="dd"
[text]="'mdi-map' | fonticon" row="0" col="0" (tap)="onTapMap()"
backgroundColor="transparent" verticalAlignment="center"
horizontalAlignment="center" ></Label>`
here i've changed the css class impl. -
class="{{ checkYes ? 'redColor' : 'defaultColor'}}"
on tap event make this variable checkYes true or false and in your css file define two classes as -
.redColor {
color:red;
}
.defaultColor {
color:gray
}
and for function onTapMap() -
onTapMap() {
if(this.checkYes)
this.checkYes = false;
else
this.checkYes = true;
}
hi i need to toggle individual content in listview when the respective button is clicked in nativescript angular,
i added bellow my code. if anyone know please answer me. thanks in advance
import { Component, OnInit } from "#angular/core";
import { Item } from "./item";
import { ItemService } from "./item.service";
#Component({
selector: "ns-items",
moduleId: module.id,
templateUrl: "./items.component.html",
})
export class ItemsComponent implements OnInit {
items: Item[];
isList = true;
toggle(){
this.isList = !this.isList;
}
constructor(private itemService: ItemService) { }
ngOnInit(): void {
this.items = this.itemService.getItems();
}
}
and here my items.component.html
<ActionBar title="My App" class="action-bar">
</ActionBar>
<StackLayout class="page">
<ListView [items]="items" class="list-group">
<template let-item="item">
<GridLayout columns="auto,auto" width="210" height="210" >
<Label [text]="item.name" col="0"
class="list-group-item" visibility="{{isList ? 'visible' : 'collapse'}}"></Label>
<Button [text]="isList ? 'hide' : 'Show'" col="1" (tap)="toggle()"></Button>
</GridLayout>
</template>
</ListView>
</StackLayout>
here problem is when i click the button all the labels are toggle. so i need to generate the variable dynamically. i m very beginner so anyone can help me?
thank in advance.
Guess you have modified the starter template. So if you want hide label on particular list item, try this.
Add visible property to item.ts
export class Item {
id: number;
name: string;
role: string;
visible: boolean;
}
Set value to visible in your item.service.ts. It will be like below.
{ id: 1, name: "Ter Stegen", role: "Goalkeeper", visible: true },
{ id: 3, name: "Piqué", role: "Defender", visible: true },
Your list template should be
<template let-item="item">
<GridLayout class="list-group-item" columns="*,auto">
<Label col="0" [text]="item.name" [visibility]="item.visible ? 'visible' : 'collapse'"></Label>
<Button class="btn" col="1" [text]="item.visible ? 'Hide' : 'Show'" (tap)="toggle(item)"></Button>
</GridLayout>
</template>
And finally the toggle method will be,
ngOnInit(): void {
this.items = this.itemService.getItems();
}
toggle(item: Item) {
item.visible = !item.visible;
}
I have this in my ViewModel:
public class MyClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public MyClass()
{
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
}
}
and this in the xaml:
<Image Source="delete.jpg" HeightRequest="20" WidthRequest="20">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />
</Image.GestureRecognizers>
</Image>
but when the image is clicked nothing appears in output log. What I'm missing ?
Note 1: I've followed the guide here
Note 2: I'm debugging on Android Device
Update 1: full xaml here
You have not provided any code behind, so I had to create my own (see below).
You also would save me 15 minutes if commented out ListView IsEnabled="False"
When you set Command="{Binding TapCommand} the TapCommand corresponds to the TapCommand of the list item, not to the model itself. So, you have 2 options
You can implement click in MyItem (I don't think you want that, so partial code for it commented below in MyItem class)
Define context binding on image itself.
Because of that our view model can be created few times - we don't want that, so the best solution is to define static resource of view model and use it everywhere on page.
The solution is below (you will just need to modify some namespaces and change delte.png to your delete.jpg):
page xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonRendererDemo;assembly=ButtonRendererDemo"
x:Class="ButtonRendererDemo.ImageTapComplexPage"
BindingContext="{StaticResource viewModel}">
<ContentPage.Resources>
<ResourceDictionary>
<local:TapComplexViewModel x:Key="viewModel"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Label Text="text2" VerticalOptions="Center" HorizontalOptions="Center" />
<StackLayout Padding="0,20,0,20">
<Button Text="text" Clicked="onclick" BackgroundColor="#009688"></Button>
</StackLayout>
<Label Text="List Type" VerticalOptions="Center" HorizontalOptions="Center" />
<ListView x:Name="lstItems" RowHeight="60" ItemsSource="{Binding Items}" > <!--IsEnabled="False"-->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill" Padding="0,2,0,2">
<StackLayout Padding="5,5,5,5">
<Image Source="{Binding source}" HorizontalOptions="End" HeightRequest="40" WidthRequest="40" />
</StackLayout>
<StackLayout Orientation="Vertical" Spacing="1">
<Label Text = "{Binding name}" HeightRequest="20" FontAttributes="Bold"/>
<Label Text = "{Binding data, StringFormat='{0:F0}'}" />
</StackLayout>
<StackLayout HorizontalOptions="EndAndExpand" Padding="0,0,15,0" Orientation="Horizontal">
<Image Source="delete.png" HeightRequest="20" WidthRequest="20">
<Image.GestureRecognizers>
<!--<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />-->
<TapGestureRecognizer Command="{Binding Source={StaticResource viewModel}, Path=TapCommand}" CommandParameter="{Binding name}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Code behind
namespace ButtonRendererDemo
{
public partial class ImageTapComplexPage : ContentPage
{
public ImageTapComplexPage()
{
InitializeComponent();
}
void onclick(object sender, EventArgs args)
{
}
}
public class TapComplexViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public ObservableCollection<MyItem> Items { get; private set; }
public TapComplexViewModel()
{
Items = new ObservableCollection<MyItem>()
{
new MyItem { name="First", source="Icon.png", data=0.5f },
new MyItem { name="Second", source="Icon.png", data=0.6f },
new MyItem { name="Third", source="Icon.png", data=0.7f }
};
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
}
}
public class MyItem
{
public string name { get; set; }
public string source { get; set; }
public float data { get; set; }
//public ICommand TapCommand
//{
// get { return new Command(() => { }); }
//}
}
}
In the back end of the xaml file make sure u set the BindingContext to the view model: Something like this:
xaml.cs
public partial class TapInsideFrameXaml : ContentPage
{
public TapInsideFrameXaml ()
{
InitializeComponent ();
// The TapViewModel contains the TapCommand which is wired up in Xaml
BindingContext = new TapViewModel ();
}
}
Also check:
On Menu > tools > options > debugging > General:
Ensure "Redirect all output window text to the immediate window" is NOT checked
On Project Properties > Build:
Configuration: Debug
"Define DEBUG constant" is checked
"Define TRACE constant" is checked
On the Output window:
Show output from: Debug
Right-click in the output window and ensure "Program output" is checked
Also make sure you are debugging using F5 and not Ctrl f5
You declared the PropertyChangedEvent event but you never actually use it. Try this:
public class MyClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public MyClass()
{
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
OnPropertyChanged();
}
protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler (this, new PropertyChangedEventArgs (propertyName));
}
}