Is it possible to get children in custom component? - nativescript

Is it possible to get children in custom component?
<myCustomComponent>
<Label #id1 text="ID 1"></Label>
<Label #id2 text="ID 2"></Label>
</myCustomComponent>
Is there a way to get the reference of these two Lable to get them positioned in a GridLayout in my custom component?

Apart from the option with getViewById() there are several options to see the a layout's children or their index and also to add, remove, insert and reset children.
e.g.
page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout id="st" class="p-20">
<Label id="lbl-title" text="Tap the button" class="h1 text-center"/>
<Button text="TAP" tap="{{ onTap }}" class="btn btn-primary btn-active"/>
<Label text="{{ message }}" class="h2 text-center" textWrap="true"/>
</StackLayout>
</Page>
page.ts
let page = <Page>args.object;
let stack = <StackLayout>page.getViewById("st");
let label = <Label>page.getViewById("lbl-title");
console.log("page.content: " + page.content); // page.content: StackLayout<st>#file:///app/main-page.xml:19:5;
console.log("stack.getChildrenCount(): " + stack.getChildrenCount()) // 3
console.log("stack.getChildAt(1): " + stack.getChildAt(1)); // stack.getChildAt(1): Button(5)#file:///app/main-page.xml:21:9;
console.log("stack.getChildIndex(label): " + stack.getChildIndex(label)); // 0
console.log("stack.parent: " + stack.parent); // stack.parent: Page(1)#file:///app/main-page.xml:7:1;
var newlabel = new Label();
newlabel.text = "new Label";
stack.addChild(newlabel);
More about all supported methods here

The view class has a getViewById() method for this purpose.
In my-component.xml:
<StackLayout loaded="onLoaded">
<Label id="label1" text="ID 1" mycustomattribute="Hi there."></Label>
<Label id="label2" text="ID 2"></Label>
</StackLayout>
In my-component.js:
exports.onLoaded = function(args) {
let view = args.object;
let label1 = view.getViewById('label1');
console.log(label1.mycustomattribute);
// > "Hi there."
};

Related

NativeScript - Change Label into TextView/TextField with a Button

I am learning to make an app in NativeScript (Angular 2). In my item page, I want to have a button so that when I press it, I can change Label into TextView/TextField for editing the information of the item.
I know that I can use editable in TextView but I still want to know if it is feasible to have the button with that functionality. Thank you !!
item.component.html:
<StackLayout>
<Label class="h3" text="Name: {{ item.get_name() }}" textWrap="true">
</Label>
<Label class="h3" text="Credit: {{ item.get_credit() }}"></Label>
<Button class="btn" text="Edit" (tap)="change()"></Button>
</StackLayout>
<!-- After pressing the button -->
<StackLayout>
<TextView class="h3" [text]="item.get_name()" textWrap="true">
</TextView>
<TextView class="h3" [text]="item.get_credit()"></TextView>
<Button class="btn" text="Save" (tap)="change()"></Button>
</StackLayout>
This can be done in many ways, but one common way is by changing visibility of control and binding it to a variable / property in the code behind.
in your component html:
Then on your component ts or code-behind you can handle it in the change method:
class MyComponentSample {
isLabelMode: boolean = true; // Set to true if you want label to show by default or false if TextView as default
change() {
this.isLabelMode = !isLabelMode; // Basically you are toggling the mode here.
}
}

Dynamic GridLayout in nativescript with angular 2

I'm very new to Nativescript and Angular and it's my first stab at mobile app development, so please bear with me.
I'm trying to create a basic app with Angular2 and Nativescript. What I'm trying to do, is to display 3 buttons at the bottom of the screen when the app starts (these are created dynamically on initialisation). Once you click any of these buttons, I want this row to be moved up and a second row of buttons to appear. The transition should be animated.
In the first approach I tried I couldn't add the GridLayout to my DockLayout.
The home.html file
<DockLayout #container stretchLastChild="false">
</DockLayout>
the home.component.ts file snippet
export class HomePage implements OnInit {
#ViewChild("container") container: DockLayout;
constructor(private _router: Router, private page: Page) {
var view = new View();
}
ngOnInit() {
this.page.actionBarHidden = true;
this.page.backgroundImage = this.page.ios ? "res://background_large_file.jpg" : "res://background_large_file";
console.dir(this.container);
//Create the grid layout on the page
var bottomNav = new GridLayout();
//Add the GridLayout Columns
bottomNav.addColumn(new ItemSpec(1, GridUnitType.auto));
bottomNav.addColumn(new ItemSpec(1, GridUnitType.auto));
bottomNav.addColumn(new ItemSpec(1, GridUnitType.auto));
//Add the GridLayout Row
bottomNav.addRow(new ItemSpec(1, GridUnitType.auto));
//Create the buttons
var FButton = new Button();
FButton.text = "F";
var BButton = new Button();
BButton.text = "B";
var CButton = new Button();
CButton.text= "C";
//Position the buttons
FButton.set('row', '0');
FButton.set('col', '0');
BButton.set('row', '0');
BButton.set('col', '1');
CButton.set('row', '0');
CButton.set('col', '2');
bottomNav.addChild(FButton);
bottomNav.addChild(BButton);
bottomNav.addChild(CButton);
//Attempt to add to DockLayout container
--This is the part I can't get working
}
}
The other approach I was considering would be to hardcode my template and only show the first row. On tap of one of the buttons in the first row I'd move it up and fade in the second row. I couldn't get the reference to the GridLayouts on the page to allow me to do this. I'm thinking I might need to use "let container = this.container;" but am a bit unsure on this.
The home.html file
<DockLayout #container stretchLastChild="false">
<GridLayout #second_row columns="*, *, *" rows="auto" dock="bottom" class="choices hidden">
<Button text="M" row="1" col="0"></Button>
<Button text="F" row="1" col="1"></Button>
<Button text="D" row="1" col="2"></Button>
</GridLayout>
<GridLayout #initial_row columns="*, *, *" rows="auto" dock="bottom" class="choices initial">
<Button text="F" row="0" col="0" (tap)="showF()"></Button>
<Button text="B" row="0" col="1" (tap)="showB()"></Button>
<Button text="C" row="0" col="2" (tap)="showC()"></Button>
</GridLayout>
</DockLayout>
The home.component.ts file
export class HomePage implements OnInit {
#ViewChild("container") container: DockLayout;
constructor(private _router: Router, private page: Page) {
var view = new View();
}
ngOnInit() {
this.page.actionBarHidden = true;
}
showC() {
let container = <View>this.container;
container.animate({
opacity: 1,
duration:200
});
console.log('in here');
}
}
The final layout I'm aiming for is (any taps on the new row of buttons - #second_row - will navigate off to other pages once I set up on tap events and routing):
<DockLayout #container stretchLastChild="false">
<GridLayout #second_row columns="*, *, *" rows="auto" dock="bottom" class="choices hidden">
<Button text="M" row="1" col="0"></Button>
<Button text="F" row="1" col="1"></Button>
<Button text="D" row="1" col="2"></Button>
</GridLayout>
<GridLayout #initial_row columns="*, *, *" rows="auto" dock="bottom" class="choices initial">
<Button text="F" row="0" col="0" (tap)="showF()"></Button>
<Button text="B" row="0" col="1" (tap)="showB()"></Button>
<Button text="C" row="0" col="2" (tap)="showC()"></Button>
</GridLayout>
</DockLayout>
I would appreciate any help and advice on the subject.
Thanks in advance!
I would suggested you to use NativeScript Angular translate animation. With its help you could move up the first GridLayout and to show the next one. You could review my sample project here .In regard to that you could also review below attached articles.
http://docs.nativescript.org/angular/ui/animation.html
http://docs.nativescript.org/angular/tutorial/ng-chapter-4
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
For your first example to add your new gridlayout to your page:
page.content = bottomNav;
Would do the trick.

Nativescript -Open SideDrawer on button click

I am using telerik ui for native script. I need a toggle button at top to open the side menu. but I am not able to call the Showdrawer() as per the docs.
What I need is on button click side menu should open. I tried calling RadSideDrawer.prototype.showDrawer(), but failed.
Is there any other side menu available for Nativescript?
main-page.xml
<Page xmlns="http://www.nativescript.org/tns.xsd" xmlns:drawer="nativescript-telerik-ui/sidedrawer" loaded="pageLoaded">
<Page.actionBar>
<ActionBar>
<android>
<NavigationButton text="Go Back" android.systemIcon="ic_menu_moreoverflow" tap="showSideDrawer" />
</android>
</ActionBar>
</Page.actionBar>
<drawer:RadSideDrawer>
<drawer:RadSideDrawer.mainContent>
<StackLayout>
<Label text="{{ mainContentText }}" textWrap="true" />
</StackLayout>
</drawer:RadSideDrawer.mainContent>
<drawer:RadSideDrawer.drawerContent>
<StackLayout cssClass="drawerContent" style="background-color:white;">
<StackLayout cssClass="headerContent">
<Label text="Header" />
</StackLayout>
<StackLayout cssClass="drawerMenuContent">
<Label text="Item 1" style="color:black;" />
<Label text="Item 2" style="color:black;" />
<Label text="Item 3" style="color:black;" />
<Label text="Item 4" style="color:black;" />
</StackLayout>
</StackLayout>
</drawer:RadSideDrawer.drawerContent>
</drawer:RadSideDrawer>
</Page>
getting-started-model.js
var observableModule = require("data/observable");
var GettingStartedViewModel = (function (_super) {
__extends(GettingStartedViewModel, _super);
function GettingStartedViewModel() {
_super.call(this);
this.set("mainContentText", "SideDrawer for NativeScript can be easily setup in the XML definition of your page by defining main- and drawer-content. The component"
+ " has a default transition and position and also exposes notifications related to changes in its state.");
}
return GettingStartedViewModel;
})(observableModule.Observable);
exports.GettingStartedViewModel = GettingStartedViewModel;
function showSideDrawer(args) {
console.log("Show SideDrawer tapped.");
// Show sidedrawer ...
_super.prototype.showDrawer.call(this);
}
exports.showSideDrawer = showSideDrawer;
main page.js
var viewModelModule = require("./getting-started-model");
function pageLoaded(args) {
console.log("Page loaded");
var page = args.object;
page.bindingContext = new viewModelModule.GettingStartedViewModel();
}
exports.pageLoaded = pageLoaded;
You can take a look at this SDK examples that show the main functionality of the RadSideDrawer. As mentioned by #R Pelzer all you need to do is get the instance of the RadSideDrawer for example by using its id:
import drawerModule = require("nativescript-telerik-ui-pro/sidedrawer");
import frameModule = require("ui/frame");
var sideDrawer: drawerModule.RadSideDrawer = <drawerModule.RadSideDrawer>(frameModule.topmost().getViewById("sideDrawer"));
and call its showDrawer() method:
sideDrawer.showDrawer();
Are you calling the showSideDrawer function from code you didn't post? Are you sure you linked the tap button?
<Button tap="showSideDrawer" text="ToggleDrawer"/>
Maybe you can try to give the sideDrawer an Id and use this code.
var drawer = frameModule.topmost().getViewById("sideDrawer");
drawer.showDrawer();
You are getting undefined because no id was assigned to the drawer so to fix your problem assign an id to the sideDrawer <drawer:RadSideDrawer id="sideDrawer"> then you can call
var frame = require('ui/frame');
var drawer = frame.topmost().getViewById("sideDrawer");
function showSideDrawer(){
drawer.showDrawer(); // i prefer using .toggleDrawerState();
};
In my case, I missed inserting , as a result, there was a missing component when toggleDrawer was being called hence the error "TypeError: Cannot read property 'toggleDrawerState' of undefined".
Try inserting all the body component of the xml file in this might solve the issue.
Happy coding :))

Want a textView or textField in Native Script XML without bottom border

The default textbox has a bottom border.
How can I get a textView or textField in Native Script XML without that bottom border?
Based on the suggestion by Nikolay, the following should do it in the stylesheet
background-color: transparent;
border-color: transparent;
One possible decision could be to remove textfield and textview border-bottom is to set background color. This will color up the border too. I will give you an example bellow
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout backgroundColor="red">
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
<TextField hint="" id="tfield" text="tests textfield"/>
<TextView hint="" id="tview" text="tests textView" editable="true" style="border-color:white; " />
</StackLayout>
</Page>
main-page.js
var main_view_model_1 = require("./main-view-model");
var color_1 = require('color');
// Event handler for Page "navigatingTo" event attached in main-page.xml
function navigatingTo(args) {
// Get the event sender
var page = args.object;
var tf = page.getViewById("tfield");
tf.borderColor = new color_1.Color("#ffffff");
tf.backgroundColor = new color_1.Color(100, 255, 0, 0);
var tv = page.getViewById("tview");
tv.borderColor = new color_1.Color("#ffffff");
tv.backgroundColor = new color_1.Color(100, 255, 0, 0);
page.bindingContext = new main_view_model_1.HelloWorldModel();
}
exports.navigatingTo = navigatingTo;

Find button or label inside Griview using Nativescript Grid view

I using GridView Nativescript to arrange the UI and I want to set css into specific button or label dynamically. How can I find inside label when outside button is trigger and I tried using getViewById method but always get empty result. Isn't got any method to find it ?
var gridview;
exports.onPageLoaded = function (args) {
page = args.object;
gridview = page.getViewById("gridview");
};
exports.onSelectedIndexChanged = function(args){
var totalMatch = 0;
var btn = args.object;
var index = btn.index;
var a = gridview.getViewById("25");
btn.backgroundColor = "red";
btn.color = "white";
};
<GridLayout columns="*,1,*,1,*" rows="auto" borderWidth="1" borderColor="#DBDBDB" borderRadius = "3" >
<Button text="selectALL" index="0" tap="onSelectedIndexChanged" backgroundColor= "red" id ="btnSelectAll" color="white" borderRadius="3" />
<Button text="UnselectAll" index="1" col="2" tap="onSelectedIndexChanged" backgroundColor= "white" id ="btnUnSelectAll" borderRadius = "3" />
<Border col="1" borderWidth="1" borderColor="#DBDBDB" />
<Border col="3" borderWidth="1" borderColor="#DBDBDB" />
</GridLayout>
<gv:GridView items="{{ items }}" verticalSpacing="3" horizontalSpacing="3" colWidth="100" rowHeight="50" padding="3" id="gridview" height="400">
<gv:GridView.itemTemplate>
<GridLayout backgroundColor="#ffffff" style="border-width:3px;border-color:#696969;border-radius:5">
<Button text="{{ Name }}" id="{{ Id }}" index="{{ Index }}" tap="onGridViewItemTap" backgroundColor= "white" color="red" style="background-size:100% 100%;background-repeat:no-repeat;background-image:url('~/images/drawable-hdpi-v4/spt_fiter_checked.png')" borderWidth="1" borderColor="#DBDBDB" borderRadius = "5"/>
</GridLayout>
</gv:GridView.itemTemplate>
</gv:GridView>
After my understanding, what you are trying to do is:
press the button in the GridLayout
trigger the onSelectedIndexChanged function
Access the button with id="25"
Modify the button
First, I would like to point out that it is not recommended to access views by ids, especially when you have a complex UI structure. I would suggest that you use bindings. I am not sure what exactly you would like to modify, so I will assume that you would like to change the background property of the button. In this case, you can bind an Observable object in the code to the background property in the XML. Then in the function onSelectedIndexChanged, you can modify the object in the code by setting a new color. Since it is observable, it will notify all of the listeners for the modification. And in our case - the property in the XML.
Here I am sending you a simple example:
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="onPageLoaded">
<GridLayout rows="auto,auto" >
<Button text="Click to Change Color" row="0" tap="onSelectedIndexChanged"/>
<Button text="Button" row="1" backgroundColor="{{color}}"/>
</GridLayout>
</Page>
main-page.js
var observable = require("data/observable");
var json={color:'red'};
var changeCss = new observable.Observable(json);
var gridview;
exports.onPageLoaded = function (args) {
page = args.object;
page.bindingContext=changeCss;
};
exports.onSelectedIndexChanged = function(args){
changeCss.set("color","blue");
};
I hope this will give you some directions.

Resources