Nativescript-angular: RadSideDrawer integration

Created on 26 Feb 2016  Â·  32Comments  Â·  Source: NativeScript/nativescript-angular

Anyone succeeded in integrating RadSideDrawer with nativescript-angular, (I’ve tried everything here in terms of general setup: https://github.com/tjvantoll/nativescript-template-drawer)… just doesn’t display anything.

component:

import {Component} from 'angular2/core';
import {registerElement} from 'nativescript-angular/element-registry';

registerElement('Drawer', () => require('nativescript-telerik-ui/sidedrawer'));

@Component({
  selector: 'app',
  templateUrl: './app.component.html'
})
export class AppComponent {}

app.component.html:

<Drawer:RadSideDrawer>
  <Drawer:RadSideDrawer.mainContent>
    <StackLayout>
      <Label text="Test"></Label>
    </StackLayout>
  </Drawer:RadSideDrawer.mainContent>
  <Drawer:RadSideDrawer.drawerContent>
    <StackLayout class="container">
      <Label text="Drawer Test"></Label>
    </StackLayout>
  </Drawer:RadSideDrawer.drawerContent>
</Drawer:RadSideDrawer>

No errors in console at all. App launches just fine. (no exceptions. nothing. normal log)
Displays absolutely nothing. Just a white screen app. Very puzzling.

Most helpful comment

For anyone who stumbles on this thread from a google search make sure to check out the UI for {N} documentation at http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/SideDrawer/getting-started, as well as the samples in https://github.com/telerik/nativescript-ui-samples-angular/tree/release/sdkAngular/app/sidedrawer.

All 32 comments

I should mention I've also tried this just for kicks. Tried several things to no avail.

component:

import {Component} from 'angular2/core';
import {registerElement} from 'nativescript-angular/element-registry';

registerElement('RadSideDrawer', () => require('nativescript-telerik-ui/sidedrawer').RadSideDrawer);

@Component({
  selector: 'app',
  templateUrl: './app.component.html'
})
export class AppComponent {}

app.component.html:

<RadSideDrawer>
  <RadSideDrawer.mainContent>
    <StackLayout>
      <Label text="Test"></Label>
    </StackLayout>
  </RadSideDrawer.mainContent>
  <RadSideDrawer.drawerContent>
    <StackLayout class="container">
      <Label text="Drawer Test"></Label>
    </StackLayout>
  </RadSideDrawer.drawerContent>
</RadSideDrawer>

Same thing. Just white app. I thought maybe it needed some height/width so I tried adding height="100%" and width="100%" on several nodes but still nothing. Stumped.

Oh and lastly the dependencies are correct using the latest:
"nativescript-telerik-ui": "^0.2.4",

I feel like I should have a play. It certainly needs the register element.
<RadSideDrawer.mainContent> ... would that need a directive? ... maybe. Take a look at:
tab views

@matt4446 good thinking... I'll try that when I get the chance.

Using directives does fix it. I have a working implementation with this:

@Directive({
    selector: 'RadSideDrawer'
})
export class RadSideDrawerDirective {
    public drawer: RadSideDrawer;

    constructor(private element: ElementRef) {
        this.drawer = element.nativeElement;
    }
}

@Directive({
    selector: '[mainContent]'
})
export class RadSideDrawerMainDirective {

    constructor(
        private owner: RadSideDrawerDirective,
        private templateRef: TemplateRef,
        private viewContainer: ViewContainerRef
    ) {
    }

    ngOnInit() {

        const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
        //Filter out text nodes, etc
        const realViews = viewRef.rootNodes.filter((node) =>
                            node.nodeName && node.nodeName !== '#text')

        if (realViews.length > 0) {
            this.owner.drawer.mainContent = realViews[0];
        }
    }
}

@Directive({
    selector: '[drawerContent]'
})
export class RadSideDrawerContentDirective {

    constructor(
        private owner: RadSideDrawerDirective,
        private templateRef: TemplateRef,
        private viewContainer: ViewContainerRef
    ) {
    }

    ngOnInit() {

        const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
        //Filter out text nodes, etc
        const realViews = viewRef.rootNodes.filter((node) =>
                            node.nodeName && node.nodeName !== '#text')

        if (realViews.length > 0) {
            this.owner.drawer.drawerContent = realViews[0];
        }
    }
}

with a view like this:

<RadSideDrawer>
  <RadSideDrawer.mainContent *mainContent>
    <StackLayout class="container">
      <Label text="Yo"></Label>
    </StackLayout>
  </RadSideDrawer.mainContent>
  <RadSideDrawer.drawerContent *drawerContent>
    <StackLayout class="container">
      <Label text="Yes"></Label>
    </StackLayout>
  </RadSideDrawer.drawerContent>
</RadSideDrawer>

The * is very important.
I can clean this up and create a plugin? Or does the core team want to integrate this into nativescript-angular ?

I created pretty much the same thing but it didnt work. I wonder what is significantly different.

Copy and paste code time. :+1:

Yeah maybe paste it here, lemme see what the difference is.

exactly the same now (including the template)
I added some logging and the significant parts are hit:

this.owner.drawer.mainContent = realViews[0];
this.owner.drawer.drawerContent = realViews[0];

I just end up with a big blank page. It is either the directives (maybe I've not assigned them to the components correctly) or it is page-router-outlet ... hmmm
Maybe I'll test it without the page-router-outlet tomorrow.

seeing as the code is reached it probably has nothing to do with the directives.
Sleep is needed now ;-)

Ok so the implementation is not quite right yet. Maybe @hdeshev or @vakrilov may know.
It looks like the layout containers like StackLayout are not included and ends up with just a Label.
You can see in this demo that the layout containers are not present:
out

This occurs with a view setup like this:

<RadSideDrawer id="drawer">
  <RadSideDrawer.mainContent *mainContent>
    <StackLayout class="container">
      <Label text="Main Content"></Label>
    </StackLayout>
  </RadSideDrawer.mainContent>
  <RadSideDrawer.drawerContent *drawerContent>
    <StackLayout class="drawer-content">
      <Label text="Drawer Content"></Label>
    </StackLayout>
  </RadSideDrawer.drawerContent>
</RadSideDrawer>

And using the directive setup like this:

import {ElementRef, Directive, Input, TemplateRef, ViewContainerRef} from "angular2/core";
import {TabView, TabViewItem} from "ui/tab-view";
import {RadSideDrawer} from 'nativescript-telerik-ui/sidedrawer/sidedrawer';

@Directive({
    selector: 'RadSideDrawer'
})
export class RadSideDrawerDirective {
    public drawer: RadSideDrawer;

    constructor(private element: ElementRef) {
        this.drawer = element.nativeElement;
    }
}

@Directive({
    selector: '[mainContent]'
})
export class RadSideDrawerMainDirective {

    constructor(
        private owner: RadSideDrawerDirective,
        private templateRef: TemplateRef,
        private viewContainer: ViewContainerRef
    ) {
    }

    ngOnInit() {

        const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
        //Filter out text nodes, etc
        const realViews = viewRef.rootNodes.filter((node) =>
                            node.nodeName && node.nodeName !== '#text')

        if (realViews.length > 0) {
            this.owner.drawer.mainContent = realViews[0];
        }
    }
}

@Directive({
    selector: '[drawerContent]'
})
export class RadSideDrawerContentDirective {

    constructor(
        private owner: RadSideDrawerDirective,
        private templateRef: TemplateRef,
        private viewContainer: ViewContainerRef
    ) {
    }

    ngOnInit() {

        const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
        //Filter out text nodes, etc
        const realViews = viewRef.rootNodes.filter((node) =>
                            node.nodeName && node.nodeName !== '#text')

        if (realViews.length > 0) {
            this.owner.drawer.drawerContent = realViews[0];
        }
    }
}

The problems occurs somewhere with this:

const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
        //Filter out text nodes, etc
        const realViews = viewRef.rootNodes.filter((node) =>
                            node.nodeName && node.nodeName !== '#text')

        if (realViews.length > 0) {
            this.owner.drawer.drawerContent = realViews[0];
        }

This looks very cool, but I think it would be better and more angular-friendly if we get rid of the RadSideDrawer.mainContent tags. I was thinking about possible ways to integrate components having multiple templates, and the best I came up with was something like:

<RadSideDrawer id="drawer">
  <template #main>
    <StackLayout class="container">
      <Label text="Main Content"></Label>
    </StackLayout>
  </template>
  <template #drawer>
    <StackLayout class="drawer-content">
      <Label text="Drawer Content"></Label>
    </StackLayout>
  </template>
</RadSideDrawer>

Of course, that would require that we create a component for the RadSideDrawer selector and manage templates there.

We are thinking of using the same approach for other components exposing multiple templates like the RadListView, for example.

@hdeshev I like your suggestion.
I'm trying to find a way forward on this to implement right away and curious if there's any specific implementation details I need to make your suggestion work? Similar to directives approach above or if there's sample code you could point me to I could try? Thank you.

I'd be willing to help create a separate module (maybe nativescript-telerik-ui-ng) which would contain all the telerik-ui components for angular consumption. Would need just a couple pointers and help with the first 1 (this one) or 2 to get me started. That way it keeps these custom (3rd party lib) components out of nativescript-angular.

@NathanWalker, this will be done by the telerik-ui team. They will focus on this after their initial release at the end of March. If you want them earlier you are more than welcome to do so, but please be in sync with @ginev who is leading that team internally, so that we can later reuse your work :).

Sounds good @valentinstoychev thanks!

For anyone who stumbles on this thread from a google search make sure to check out the UI for {N} documentation at http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/SideDrawer/getting-started, as well as the samples in https://github.com/telerik/nativescript-ui-samples-angular/tree/release/sdkAngular/app/sidedrawer.

i added tns create my-app --ng & done tns plugin add nativescript-telerik-ui
this is my app.component.ts

import { Component, ViewChild, ChangeDetectorRef } from "@angular/core";
import { RadSideDrawerComponent, SideDrawerType } from "nativescript-telerik-ui/sidedrawer/angular";

@Component({
    selector: "my-app",
    templateUrl: "app.component.html"
})
export class AppComponent {
    @ViewChild(RadSideDrawerComponent)
    public drawerComponent: RadSideDrawerComponent;
    private drawer: SideDrawerType;
    public pages: Array<Object>;
    constructor(
        private _changeDetectionRef: ChangeDetectorRef) {
        // List all pages here         
        this.pages = [
            { name: "Home" },
            { name: "About" },
            { name: "Contact" }
        ];
    }

    ngOnInit() {
        this.drawer = this.drawerComponent.sideDrawer;
        this._changeDetectionRef.detectChanges();
    }

    public openDrawer() {
        console.log("drawer called...........................", JSON.stringify(this.drawer));
        this.drawer.toggleDrawerState();
    }
}

app.component.html

<ActionBar title="GitUsers">  
  <NavigationButton icon="res://icon" text="Go Back" (tap)="openDrawer()"></NavigationButton>
</ActionBar>  
<RadSideDrawer #drawer>  
    <template drawerSide>
        <StackLayout class="p bgc-white">
            <ListView [items]="pages" row="1">
                <template let-item="item" let-i="index">
                    <StackLayout>
                        <Label text="{{item.name}}" class="page-name" ></Label>
                    </StackLayout>
                </template>
            </ListView>
        </StackLayout>
    </template>
    <template drawerMain>
        <StackLayout class="m">
            <user-list></user-list>
        </StackLayout>
   </template>
</RadSideDrawer>

but i am getting errors on load and clicking the side drawer icon :

JS: at /data/data/org.nativescript.myapp/files/app/tns_modules/zone.js/dist/
zone-node.js:532:18
JS: at ZoneDelegate.invokeTask (/data/data/org.nativescript.myapp/files/app/
tns_modules/zone.js/dist/zone-node.js:314:38)
JS: at Object.NgZoneImpl.inner.inner.fork.onInvokeTask (/data/data/org.nativ
escript.myapp/files/app/tns_modules/@angular/core/src/zone/ng_zone_impl.js:44:41
)
JS: at ZoneDelegate.invokeTask (/data/data/org.nativescript.myapp/files/app/
tns_modules/zone.js/dist/zone-node.js:313:43)
JS: at Zone.runTask (/data/data/org.nativescript.myapp/files/app/tns_modules
/zone.js/dist/zone-node.js:214:48)
JS: at drainMicroTaskQueue (/data/data/org.nativescript.myapp/files/app/tns_
modules/zone.js/dist/zone-node.js:432:36)
JS: Unhandled Promise rejection: Cannot read property 'sideDrawer' of undefined
; Zone: angular ; Task: Promise.then ; Value: TypeError: Cannot read property 's
ideDrawer' of undefined
JS: Error: Uncaught (in promise): TypeError: Cannot read property 'sideDrawer' o
f undefined
JS: EXCEPTION: TypeError: Cannot read property 'sideDrawer' of undefined
JS: STACKTRACE:
JS: TypeError: Cannot read property 'sideDrawer' of undefined
JS: at AppComponent.ngOnInit (/data/data/org.nativescript.myapp/files/app/ap
p.component.js:15:43)
JS: at DebugAppView._View_AppComponent_Host0.detectChangesInternal (AppCompo
nent.template.js:29:81)
JS: at DebugAppView.AppView.detectChanges (/data/data/org.nativescript.myapp
/files/app/tns_modules/@angular/core/src/linker/view.js:243:14)
JS: at DebugAppView.detectChanges (/data/data/org.nativescript.myapp/files/a
pp/tns_modules/@angular/core/src/linker/view.js:348:44)
JS: at ViewRef_.detectChanges (/data/data/org.nativescript.myapp/files/app/t
ns_modules/@angular/core/src/linker/view_ref.js:131:65)
JS: at /data/data/org.nativescript.myapp/files/app/tns_modules/@angular/core
/src/application_ref.js:435:84
JS: at Array.forEach (native)
JS: at ApplicationRef_.tick (/data/data/org.nativescript.myapp/files/app/tns
_modules/@angular/core/src/application_ref.js:435:38)
JS: at ApplicationRef_._loadComponent (/data/data/org.nativescript.myapp/fil
es/app/tns_modules/@angular/core/src/application_ref.js:406:14)
JS: at /data/data/org.nativescript.myapp/files/app/tns_modules/@angular/core
/src/application_ref.js:393:19
JS: EXCEPTION: TypeError: Cannot read property 'sideDrawer' of undefined
JS: ns-renderer: ERROR BOOTSTRAPPING ANGULAR
JS: ns-renderer: Cannot read property 'sideDrawer' of undefined
JS:
JS: TypeError: Cannot read property 'sideDrawer' of undefined
JS: at AppComponent.ngOnInit (/data/data/org.nativescript.myapp/files/app/ap
p.component.js:15:43)

Hi @sarvagayatri it looks like the error you are experiencing is caused by an bug in the zone.js which is part of the Angular 2 library. Here is the logged issue for reference. To resolve the issue simply change the "zone.js": "^0.6.21" in the devDependencies to "zone.js": "0.6.17"

We are working with the Angular team to resolve this breaking change caused by the zone.js package, in the mean while we are upgrading any project templates that use Angular 2.0.0 to not depend on the latest versions of zone.js.

I have done this command before the tns run android
npm install zone.[email protected]
Or else i got some "timers" exception

How can I implement expandable (Nested) side drawer in android and ios using RadSideDrawer ?

@srnaik What do you mean by "nested", in order to use the RadSideDrawer in {N} + Angular you can follow the short introduction article here.

@VladimirAmiorkov Thank you responding to my question, I have already referred to the article that you have posted and I could able to implement the side drawer with the help of that article. My question is that I would like to add child elements inside every side-drawer item. Please refer to the below piece of code.

**<StackLayout class="sideStackLayout">
            <Label text="Primary" class="sideLabel sideLightGrayLabel">
                   <Label text="Primary nested Item -1" class="sideLabel sideLightGrayLabel"/>
                   <Label text="Primary nested Item -2" class="sideLabel sideLightGrayLabel"/>
            </Label>
</StackLayout>**

Here, how can I add "Primary nested Item -1" & "Primary nested Item -2" as child elements inside "Primary" ?

P.S. The piece of code that I have written is to give you an idea of Nested feature that I am trying to achieve, I hope it was helpful.

@srnaik You can accomplish what you want to do by using a container element instead of a label element, you can use a StackLayout for example, create the "Primary" label inside the StackLayout and then add the other two labels, if you want to make them look different you can create a style (CSS class) for the "Primary" label and then another style for the "nested" labels by applying a margin-right (as example).

Thanks @viniciodeltoro , that was helpful !

Hi @viniciodeltoro,

I have another question related to wrapping the long text in the Label field. I am trying to wrap a long text in the side-drawer, but it is getting truncated, I tried using style = "word-wrap: break-word;width:125px" css property for label, but even then I am not able to wrap the text to the next line.

Please let me know your thoughts on wrapping the text in sidedrawer


Hi @srnaik. You have to use the 'textWrap' property in the label, I believe it doesn't work if you try to add it in your CSS class. Your label code will be something like this.

<Label text="This is a very very very long text" textWrap="true"></Label>

Thank you @viniciodeltoro , That worked :-)

I'm also having the same issue as @sarvagayatri using "zone.js": "~0.8.2", any way to resolve this?

@chrillewoodz Our NativeScript UI sdk examples are currently using the ^0.6.21 version of zonejs without any issues, you can check out all of the package.json dependencies here. Is there a particular reason for using the ~0.8.2 version over ^0.6.21 in your project?

@VladimirAmiorkov That's what the cli created. Seems odd that after 6 months the bug still remains in zonejs..

@chrillewoodz You can track the status of the zonejs issue here. Could you share with me which version of NativeScript (tns --version) are you using?

@VladimirAmiorkov I'm using 2.5.3.

Im getting this error
TypeError: Cannot read property 'sideDrawer' of undefined JS: at ItemsComponent.ngAfterViewInit (file:///data/data/org.nativescript.MyAppTest/files/app/item/items.component.js:34:43) JS: at callProviderLifecycles (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:11110:18) JS: at callElementProvidersLifecycles (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:11085:13) JS: at callLifecycleHooksChildrenFirst (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:11069:17) JS: at checkAndUpdateView (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:12087:5) JS: at callWithDebugContext (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:13067:42) JS: at Object.debugCheckAndUpdateView [as checkAndUpdateView] (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:12607:12) JS: at ViewRef_.detectChanges (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/core/bundles/core.umd.js:10177:63) JS: at PageRouterOutlet.activateOnGoForward (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/nativescript-angular/router/page-router-outlet.js:150:57) JS: at PageRouterOutlet.activateWith (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/nativescript-angular/router/page-router-outlet.js:139:18) JS: at ActivateRoutes.placeComponentIntoOutlet (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/router/bundles/router.umd.js:4584:16) JS: at ActivateRoutes.activateRoutes (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/router/bundles/router.umd.js:4565:26) JS: at file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/router/bundles/router.umd.js:4501:58 JS: at Array.forEach (native) JS: at ActivateRoutes.activateChildRoutes (file:///data/data/org.nativescript.MyAppTest/files/app/tns_modules/@angular/router/bundles/router.umd.js:4501:29)

any idea? thanks

I have tested this and it works fine with this in package.json:

'@angular/animations': '~4.1.0',
'@angular/common': '~4.1.0',
'@angular/compiler': '~4.1.0',
'@angular/core': '~4.1.0',
'@angular/forms': '~4.1.0',
'@angular/http': '~4.1.0',
'@angular/platform-browser': '~4.1.0',
'@angular/router': '~4.1.0',
'nativescript-angular': '~3.0.0',
'nativescript-ng2-fonticon': '^1.3.4',
'nativescript-telerik-ui': '^2.0.1',
'nativescript-theme-core': '~1.0.2',
'reflect-metadata': '~0.1.8',
'rxjs': '~5.3.0',
'tns-core-modules': '~3.0.0',
'zone.js': '~0.8.2',
'email-validator': '^1.0.7',
'nativescript-iqkeyboardmanager': '1.0.1',
'nativescript-social-share': '~1.3.2',
'nativescript-unit-test-runner': '^0.3.3'

But when I set this versions...

'@angular/animations': '~4.2.3',
'@angular/common': '~4.2.3',
'@angular/compiler': '~4.2.3',
'@angular/core': '~4.2.3',
'@angular/forms': '~4.2.3',
'@angular/http': '~4.2.3',
'@angular/platform-browser': '~4.2.3',
'@angular/router': '~4.2.3',
'nativescript-angular': 'next',
'nativescript-ng2-fonticon': '^1.3.4',
'nativescript-telerik-ui': '^2.0.1',
'nativescript-theme-core': '^1.0.4',
'reflect-metadata': '^0.1.8',
'rxjs': '^5.4.0',
'tns-core-modules': 'next',
'zone.js': '^0.8.11',
'email-validator': '^1.0.7',
'nativescript-iqkeyboardmanager': '1.0.1',
'nativescript-social-share': '~1.3.2',
'nativescript-unit-test-runner': '^0.3.3'

It doesn't show the drawer.
Thanks

Was this page helpful?
0 / 5 - 0 ratings