Nativescript -Open SideDrawer on button click - nativescript

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 :))

Related

Nativescript ActionBar custom component

I am trying to create a custom component as described here in order to reuse the action bar and its logic in different places of my app.
Here is what I have setup the component:
/components/header/header.xml
<ActionBar title="Title" class="{{ 'mode' == dark ? 'bg-dark' : 'bg-white' }}" loaded="loaded">
</ActionBar>
/components/header/header.ts
exports.loaded = (args) => {
let page = <Page> args.object;
let pageObservable = new Observable({
'mode' : page.get('mode')
});
page.bindingContext = pageObservable;
}
I then try to use the component calling it like this :
some_view.xml
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:header="components/header">
<header:header mode="dark"/>
<StackLayout>..</StackLayout>
...
</Page>
However, navigating to `some-view.xml' I get the following error:
Calling js method onCreateView failed
TypeError: Cannot read property frame of 'undefined'
File "data...../ui/action-bar/action-bar.js" line: 146
Am I doing something wrong?
Have you succeded in creating a custom component based on ActionBar?
Perhaps the problem is that you are trying to get Page instance in the loaded method in your /components/header/header.ts file. args will return you reference to the ActionBar instead of Page. On other hand while using TypeScript the events should be defined like this export function loaded(args){...}. In the above-given code you are using JavaScript syntax. I am attaching sample code, where has been shown, how to create custom component.
component/action-bar/action-bar.xml
<ActionBar loaded="actionbarLoaded" title="Title" icon="">
<NavigationButton text="Back" icon="" tap="" />
<ActionBar.actionItems>
<ActionItem icon="" text="Left" tap="" ios.position="left" />
<ActionItem icon="" text="Right" tap="" ios.position="right" />
</ActionBar.actionItems>
</ActionBar>
component/action-bar/action-bar.ts
export function actionbarLoaded(args){
console.log("actionbar loaded");
}
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" xmlns:AB="component/action-bar">
<Page.actionBar>
<AB:action-bar />
</Page.actionBar>
<StackLayout>
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
</StackLayout>
</Page>
main-page.ts
import { EventData } from 'data/observable';
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
// Event handler for Page "navigatingTo" event attached in main-page.xml
export function navigatingTo(args: EventData) {
// Get the event sender
let page = <Page>args.object;
page.bindingContext = new HelloWorldModel();
}

NativeScript binding breaks UI

I have setup a custom tab view defined as the following :
main.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="loaded"
xmlns:t1="partial-views/explore"
xmlns:t2="partial-views/community">
<!--ACTION BAR-->
<ActionBar title="Haloose">...</ActionBar>
<StackLayout>
<!-- TABS -->
<StackLayout id="sl_main">
<t1:explore id="tab_explore" visibility="{{ currentActive == 'explore' ? 'visible' : 'collapsed' }}" />
<t2:community id="tab_community" visibility="{{ currentActive == 'community' ? 'visible' : 'collapsed' }}"/>
</StackLayout>
<-- FIXED MENU -->
<GridLayout id="menu">
<Image tap="changeVisibleTab"/>
<Image tap="changeVisibleTab" />
</GridLayout>
</StackLayout>
</Page>
Let's call this file main.xml . It's associated to a main.js where I've defined a binding context:
main.js
exports.loaded = function(args){
page = args.object;
//Set Up page view model
mainObservable = new Observable({
currentActive:"explore",
menuItemsArray:[
new MenuItem("explore"),
new MenuItem("community")
]
});
//Bind page to view model
page.bindingContext = mainObservable;
}
For each tab I have a folder containing a js , css and xml file.
A sample tab.xml file would look like this :
tab.xml
<StackLayout loaded="tabLoaded" > <looots of stuff /> </StackLayout>
Everything works as expected, however if I try to bind the stack layout to an object , all of the UI elements are hidden.
If I remove binding, I can see them again.
not working tab.js
var Observable = require("data/observable").Observable;
var profile;
exports.tabLoaded = function(args){
profile = args.object;
var profileBinding = {
username : "Aaron Ullal"
}
profile.bindingContext = profileBinding; //removing this line makes elements visible
}
What is causing this? Perhaps multi level binding is not supported?
When you use custom XML components, like your tabs, and add bindings to them (in your case the visibility binding, those bindings are basically applied to the root tag in your XML component. So when you change the binding context in your tab.js the visibility binding starts looking for a currentActive property in profileBinding. In order to achieve what you want you have to wrap your tab XML in another layout, like this:
<StackLayout>
<StackLayout loaded="tabLoaded" >
<!--looots of stuff -->
</StackLayout>
</StackLayout>
It should work as expected then.

NativeScript: how to make view 'transparent' for any user interactions

Is there a way to make a view 'transparent' to any user interactions? For example I have a view (with transparent background) and a button under that view. I want the user could tap the button under that view. If I have a scroller view under that view I want the user interacts with scroller when scroll over that view, so the view doesn't interfere or intercept user's gestures. But only this view should be transparent to user's interactions not its children. So, if I have a button inside that view it behaves normally.
Example XML:
<AbsoluteLayout width="100%" height="100%">
<Button text="Button1" tap="onTap1" />
<GridLayout width="100%" height="100%" backgroundColor="transparent">
<Button text="Button2" tap="onTap2" horizontalAlignment="center" verticalAlignment="center"/>
</GridLayout>
</AbsoluteLayout>
Thank you for your help.
You have multiple approaches to make a view change its color in NativeScript.
For example you can directly change its backgroundColor. Another oiption is to use animation and third option is to use CSS-animation.
Here is a basic example for the first two options.
page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout>
<GridLayout width="300" height="300" id="myGrid" backgroundColor="transparent">
</GridLayout>
<Button text="Tap me" tap="onTap" />
<Button text="Or Tap me" tap="onAnotherTap" />
</StackLayout>
</Page>
page.js
import { EventData } from "data/observable";
import { Page } from "ui/page";
import { HelloWorldModel } from "./main-view-model";
import { GridLayout } from "ui/layouts/grid-layout";
import { Color } from "color";
var myGridView;
export function navigatingTo(args: EventData) {
var page = <Page>args.object;
page.bindingContext = new HelloWorldModel();
// get refference to the view using its id
myGridView = <GridLayout>page.getViewById("myGrid");
}
export function onTap(args:EventData) {
var color = new Color("#FF0000");
myGridView.backgroundColor = color;
}
export function onAnotherTap(args:EventData) {
myGridView.animate({
backgroundColor: new Color("#3D5AFE"),
duration: 3000
});
}
All of the options can be found described in NativeScript documenation

Nativescript page title not rendering when set after navigation

I m bulding an app and i have a problem with rendering the title in the ActionBar after navigating to that page. Since the ActionBar cannot have an id i m using an observable viewModel in wich i set the title property.
-----xml-----
<Page.actionBar>
<ActionBar title="{{ name }}">
</ActionBar>
</Page.actionBar>
-------------
------js-----
exports.pageLoaded = function(args) {
page = args.object;
var navData = page.navigationContext;
viewModel.set("name",navData.name);
page.bindingContext = viewModel;
};
What i have seen so far debugging this problem is that when i close the phone screen and after that open it (refreshing the app) the action bar title will render.
Found the answer (a workaround) ,
<ActionBar>
<ActionItem ios.systemIcon="12" android.systemIcon="ic_menu_search" tap="showSearch" />
<ActionItem android.systemIcon="ic_menu_moreoverflow" tap="logout" text="Logout" android.position="popup" />
<ActionBar.titleView>
<StackLayout orientation="horizontal">
<Label text="{{ name }}" />
<Image src="res://app_icon" />
</StackLayout>
</ActionBar.titleView>
You need to set the title in a different page event, fairly certain you should do this in the navigatedTo event for the page.
For more info on the page navigation events, check out this blog post Nathanael Anderson - FluentReports - page navigating order of events

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