I followed the guidelines to use nativescript-fresco with ng2+nativescript for my android app because it was crashing every time I scrolled more than once down then up. The component in which I'm using it is a listview which displays 20 online images. The urls are passed from the parent component through a #Input directive which works. However, when I switched to FrescoDrawee, the listview is rendered but the images are not.
Here is the html for the component
<GridLayout columns="*,*,*,*,*,*,*,*,*" height="100" class="item"
xmlns:nativescript-fresco="nativescript-fresco">
<ios>
<Image [src]="data.imageUrl" row="0" col="0" colspan="3" class="ios-product-image" (tap)="details(data)"></Image>
</ios>
<android>
<!--<Image [src]="data.imageUrl" row="0" col="0" colspan="3" class="android-product-image" (tap)="details(data)"></Image>-->
<nativescript-fresco:FrescoDrawee width="100" height="100"
[imageUri]="data.imageUrl"
></nativescript-fresco:FrescoDrawee>
</android>
<StackLayout row="0" col="3" colSpan="5" (tap)="details(data)">
<Label [text]="data.name" class="product-name"></Label>
<Label [text]="data.description" textWrap="true" class="product-description"></Label>
<GridLayout columns="*,*,*,*,*,*,*,*,*,*" class="increment-decrement" style="width: 100%; height: 20%; vertical-align: bottom">
<Label [text]="data.price" class="product-price" col="0" colSpan="5"></Label>
<ios>
<Button text="-" col="5" colSpan="1" (tap)="dec()"></Button>
<Label [text]="count" col="6" colSpan="3" class="product-amount" ></Label>
<Button text="+" col="9" colSpan="1" (tap)="inc()"></Button>
</ios>
<android>
<Label text="-" col="5" colSpan="1" class="inc-dec" (tap)="dec()"></Label>
<Label [text]="count" col="6" colSpan="3" class="product-amount"></Label>
<Label text="+" col="9" colSpan="1" class="inc-dec" (tap)="inc()"></Label>
</android>
</GridLayout>
</StackLayout>
<ios>
<Button col="11" class="cart" colSpan="1"></Button>
</ios>
<android>
<Label col="11" class="cart" colSpan="1"></Label>
</android>
<Image src="~/media/ic_add_shopping_cart_white_24dp.png" col="11"
style="height: 20%; width: 20%;" (tap)="addToCart()"></Image>
</GridLayout>
And this is the Type-script
import { Component, OnInit, Input} from "#angular/core";
import LabelModule = require("ui/label");
import application = require("application");
import { RouterExtensions } from "nativescript-angular/router";
import { PublicVariables } from "../../shared/publicVariables";
#Component({
selector:'product-list',
templateUrl: 'pages/products/product_list.html',
styleUrls: ['pages/products/product_list-common.css', 'pages/products/product_list.css']
})
export class ProductListComponent implements OnInit {
#Input() data: any;
private count=0;
constructor(private routerExtensions: RouterExtensions) {}
ngOnInit() {
}
details() {
this.routerExtensions.navigate(["/product/:id"]);
PublicVariables.currentProduct = this.data;
}
inc() {
++this.count;
}
dec() {
if(this.count>0) {
--this.count;
}
}
}
I'm relatively new to native-script so my code may not be the cleanest.
I have added the nativescript-fresco plugin to my project, imported and initialized it in AppModule. What I don't know is if I need to add anything to the component itself apart from the FrescoDrawee tag because I didn't see anything indicating that in the documentation.
Kindly help me figure out what the problem with my code?
I think the problem is with the prefix, you can use it as:
<FrescoDrawee width="100" height="100" [imageUri]="data.imageUrl"></FrescoDrawee>
And for sake of completeness this is what needs to be added to app.module.ts when used with Angular:
import { TNSFrescoModule } from "nativescript-fresco/angular";
import fresco = require("nativescript-fresco");
import application = require("application");
if (application.android) {
application.onLaunch = function (intent) {
fresco.initialize();
};
}
#NgModule({
imports: [
TNSFrescoModule
Related
I updated my project to NativeScript 6 and also updated Android Studio. Now, on both emulators and real devices, I get permission errors when I invoke telephony():
JS: nativeException: java.lang.SecurityException: getLine1NumberForDisplay: Neither user 10089 nor current process has android.permission.READ_PHONE_STATE, android.permission.READ_SMS, or android.permission.READ_PHONE_NUMBERS
Adding the permissions to my own AndroidManifest.xml makes no difference. And, Google Play has a recent policy that restricts READ_SMS to apps that can act as the default text app.
The code in question is in the nativescript-telephony plugin, and I've added an issue to that repository, tho it has not been active for some time.
Try to first install nativescript-contacts and nativescript-permissions plugin for get contact list with set permission for contacts read, edit and add permission.
Set permission in
App_Resources->Android->src->main->Androidmanifest.xml File
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
contact.component.html:-
<ListView row="0" [items]="contactList" separatorColor="transparent">
<ng-template let-contact="item" let-i="index">
<GridLayout rows="*, auto" columns="auto, *, auto">
<Image col="0" *ngIf="contact && contact.photo" class="site-template-image" stretch="aspectFill" [src]="contact ? contact.photo : '~/app/images/avatar.jpg'"></Image>
<StackLayout col="0" class="site-template-first-icon" verticalAlignment="center">
<Label col="0" *ngIf="contact && contact.photo == null" horizontalAlignment="center" fontSize="24" color="#fff" [text]="contact && contact.name.displayname ? contact.name.displayname.charAt(0) : 'N/A'"></Label>
</StackLayout>
<StackLayout col="1" verticalAlignment="center">
<Label class="site-template-title" [text]="contact ? contact.name.displayname:'No data'"></Label>
<WrapLayout orientation="horizontal" *ngIf="contact && contact.phoneNumbers.length > 0">
<Label class="site-template-description" *ngFor="let phoneNumber of contact.phoneNumbers" text="{{phoneNumber.value + ' '}}"></Label>
</WrapLayout>
</StackLayout>
<StackLayout margin="0,16,0,35" row="1" colSpan="2" backgroundColor="lightGray" height="0.3"></StackLayout>
</GridLayout>
</ng-template>
</ListView>
contact.component.ts
import * as contacts from "nativescript-contacts";
import * as permissions from "nativescript-permissions";
declare var android;
#Component({
selector: "Contact",
moduleId: module.id,
templateUrl: "./contact.component.html",
styleUrls: ["./contact.component.css"]
})
export class HomeComponent implements OnInit {
public contactList: any;
constructor() { }
ngOnInit(): void {
// Init your component properties here.
this.getContactList();
}
getContactList() {
permissions.requestPermissions([android.Manifest.permission.GET_ACCOUNTS, android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS], "I need these permissions.")
.then(() => {
let contactFields = ["name", "phoneNumbers"];
contacts.getAllContacts(contactFields).then(
(data) => {
if (data.data.length > 0) {
this.contactList = data.data;
}
}, (err) => {
console.log("Error: " + err);
this.isLoading = false;
}
);
});
}
}
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;
}
I'm completely new to NativeScript but it looks like a sweet platform. I'm writing a toy app and below is my setup:
//code behind
import {AddExpenseModel} from "./add-expense-view-model";
import {EventData} from "tns-core-modules/data/observable";
import {Page} from "tns-core-modules/ui/page";
let expenseModel = new AddExpenseModel();
export function navigatingTo(args: EventData) {
let page = <Page>args.object;
let textField = page.getViewById("tags");
textField.on("textChange", (ev)=>{expenseModel.onTagsTextFieldChange(ev)});
page.bindingContext = expenseModel;
}
export function submit() {
expenseModel.createNewExpense()
}
//view-model
import {Observable, PropertyChangeData} from "tns-core-modules/data/observable";
import {ObservableArray} from "tns-core-modules/data/observable-array";
let u = require('underscore');
export class AddExpenseModel extends Observable {
...
public parsed_tags;
constructor() {
super();
this.parsed_tags = new ObservableArray([]);
...
}
public onTagsTextFieldChange(ev) {
let that = this;
// empty
u.forEach(u.range(this.parsed_tags.length), function (_) {
that.parsed_tags.pop()
});
let parsed = this.parseTags(ev.value);
u.forEach(parsed, function (el) {
that.parsed_tags.push(el);
});
}
private getParsedTags() {
//unbox
return u.map(this.parsed_tags, (el: string) => el)
}
private parseTags(tag_string) {
let arr = u.map(tag_string.split(','), (tag: string) => tag.trim().toLocaleLowerCase());
arr = u.uniq(arr);
arr = u.filter(arr, u.negate(u.isEmpty))
return arr;
}
}
//view
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
<StackLayout class="p-20">
<Label text="Add new expense"/>
<text-field
id="name" text="{{ name }}"
row="0"/>
<text-field id="amount" stext="{{ amount, amount | numberConverter }}" />
<text-field id="tags" secure="false" text="{{ tags }}"
/>
<WrapLayout orientation="horizontal" height="300" width="300">
<ListView items="{{ parsed_tags }}">
<ListView.itemsLayout>
<Label text="{{ $value }}" width="70" backgroundColor="red"/>
</ListView.itemsLayout>
</ListView>
</WrapLayout>
<button text="Add expense" id="submit-button" tap="submit"/>
</StackLayout>
</Page>
What I want to achieve is that when a user writes in the tags textfield, stylised Labels appear in the WrapLayout. This works, however, the Labels appear always stacked vertically. Here's a screenshot
I tried to move the whole WrapLayout section out of the StackedLayout section, but I get a cannot read property 'on' of undefined, undefined.
Putting Labels inside of WrapLayout not within a ListView (i.e. static) works as expected, which makes me thing I probably misuse either the ListView or the WrapLayout. Any directions will be appreciated :)
Cheers
Update
Following Eddy's advice I used a Repeater. Using the following xml
<Repeater items="{{ parsed_tags }}">
<Repeater.itemsLayout>
<WrapLayout orientation="horizontal" backgroundColor="#d3d3d3"/>
</Repeater.itemsLayout>
<Repeater.itemTemplate>
<Label text="{{ $value }}" backgroundColor="#84ddff" marginRight="5" marginLeft="5"/>
</Repeater.itemTemplate>
</Repeater>
correctly produces this:
I still don't see why using a ListView wouldn't work. I used the debugger from Sidekick and this is what I see.
<ListView items="{{ parsed_tags }}">
<ListView.itemsLayout>
<WrapLayout orientation="horizontal" backgroundColor="#d3d3d3" marginRight="5" marginLeft="5"/>
</ListView.itemsLayout>
<ListView.itemTemplate>
<Label text="{{ $value }}" backgroundColor="#84ddff" marginRight="5" marginLeft="5"/>
</ListView.itemTemplate>
</ListView>
I want to create a list view NativeScript with custom item view. I'm using GridLayout to do that.
The problem is: There is large space between rows item.
These are what I've done:
XML:
<Page loaded="loaded">
<ActionBar title="Welcome">
<android>
<NavigationButton android.systemIcon="ic_menu_emoticons" icon="res://icon" tap="showSlideout"/>
</android>
</ActionBar>
<ListView items="{{ items }}">
<ListView.itemTemplate>
<GridLayout rows="auto" columns="auto,*" class="threads-list-wrapper" height="100">
<Image row="0" col="0" src="{{ photo }}"></Image>
<StackLayout row="0" col="1" class="" orientation="vertical">
<Label class="h1" text="{{title}}"></Label>
<Label text="{{ body }}"></Label>
<Label text="{{ date }}"></Label>
</StackLayout>
</GridLayout>
</ListView.itemTemplate>
</ListView>
CSS
.threads-list-wrapper {
padding: 15;
}
.threads-list-wrapper > Image {
height: 64;
width: 64;
margin-right: 15;
}
CODE:
var observableModule = require("data/observable");
var model = new observableModule.Observable();
exports.loaded = function (args) {
var items = [
{
photo: 'res://icon',
title: 'Ardiansyah Putra',
body: 'Ini adalah pesan yang saya kirimkan kepada anda, mohon cepat dibalas ya',
date: 'Just Now'
},
{
photo: 'res://icon',
title: 'Bagus Putra',
body: 'Ini adalah pesan yang saya kirimkan kepada anda, mohon cepat dibalas ya',
date: '12 Jan'
}
];
var page = args.object;
model.set("items", items);
page.bindingContext = model;
};
RESULT:
Not sure what exactly is causing the white space in your case , but here is a snippet where after stripping all the CSS there are no extra white spaces generated in the list-view template.
<GridLayout rows="*" columns="*, *">
<Image col="0" src="res://icon" stretch="none" />
<StackLayout col="1" >
<Label class="h1" text="{{title}}"></Label>
<Label text="{{ body }}"></Label>
<Label text="{{ date }}"></Label>
</StackLayout>
</GridLayout>
I was following this guide to create a a nativescript custom component http://moduscreate.com/custom-components-in-nativescript/ but it's not working for me
I have a folder pages with a folder inside it called main.
main has a couple of files
main.html
<StackLayout
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:hello="pages/helllo"
loaded="pageLoaded" >
<hello:hello/>
</StackLayout>
main.component.ts
import { Component, ElementRef, OnInit, ViewChild} from "#angular/core";
import { Page } from "ui/page";
import colorModule = require("color");
var Color = colorModule.Color;
#Component({
selector: "my-app",
templateUrl: "pages/main/main.html",
styleUrls: ["pages/main/main-common.css"]
})
export class MainComponent implements OnInit{
constructor(private page: Page) {
}
ngOnInit() {
this.page.actionBarHidden = true;
}
}
and I also have main-common.css but that's not important to show. I then have another folder inside pages called hello with just one file inside of it
hello.html
<StackLayout width="100%" height="100%" backgroundColorr="red">
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
<Label class ="h1" text="h1 hello world" color="black"></Label>
</StackLayout>
however the hello component is not showing no matter what i do i am only getting an empty screen. I also tried changing this line xmlns:hello="pages/helllo" in hello.html file to this xmlns:hello="../helllo" but i didn't get anything not even an error. can someone point out what i am doing wrong?
What you are referring as valid in NativeScript Core but won't work in NativeScript + Angular-2.
What you need instead is to create custom component the Angular-2 way.
For demonstration, we can refer to this sample where a custom item component is created. The example is also described in the documentation and it will also show you how to bind data with #Input directive for this component.
Let me guide you through the process.
1.) Create your custom component
using-item-template.component.ts
import { Component, ChangeDetectionStrategy, Input } from "#angular/core";
#Component({
selector: 'item-component',
styleUrls: ["listview/using-item-template/using-item-template.component.css"],
template: `
<StackLayout *ngFor="let element of data.list" class="model">
<Label [text]="element.model" class="name"></Label>
<Label [text]="element.speed +'mph'" class="speed"></Label>
</StackLayout>
`
})
export class ItemComponent {
#Input() data: any; // this way we "pass data" to our item-component
}
#Component({
selector: 'using-item-template',
styleUrls: ["listview/using-item-template/using-item-template.component.css"],
templateUrl: "listview/using-item-template/using-item-template.component.html",
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UsingItemTemplateComponent {
public manufacturers: Array<any>;
constructor() {
var bugatti = [{ "model": "Bugatti Chiron", "speed": "261" }, { "model": "Bugatti Veyron Super Sport", "speed": "268" }];
var mclaren = [{ "model": "McLaren P1", "speed": "211" }, { "model": "McLaren F1", "speed": "242" }];
var jaguar = [{ "model": "Jaguar XJ220", "speed": 217 }];
this.manufacturers = [{ "list": bugatti }, { "list": mclaren }, { "list": jaguar }];
}
}
using-item-template.component.html
<StackLayout exampleTitle toggleNavButton>
<GridLayout rows="50, *" class="example-container">
<Label text="Top Cars" row="0" class="title" textWrap="true" horizontalAlignment="center"></Label>
<ListView [items]="manufacturers" row="1">
<template let-item="item">
<item-component [data]="item" ></item-component>
</template>
</ListView>
</GridLayout>
</StackLayout>
The last but also crucial part is not to forget to declare your ItemComponent in the NgModule!
main.ts
import { ItemComponent } from "./listview/using-item-template/using-item-template.component";
#NgModule({
declarations: [
ItemComponent, // declare the item component
// the other components in your app
],
bootstrap: [AppComponent],
imports: [
.....
],
})
class AppComponentModule { }