Extending EventRenderer of RadCalendar throws convertion error


#1

Hello!

This is my first post, so I apologize if this is an easy situation. Please, if this isn’t the right place to ask this, do let me know!

My goal is to extend the EventRenderer’s renderEvents() method.

So far I’ve covered most of the issues, from getting the proper android.d.ts definitions from Pro UI’s folder into my references.d.ts file, so typescript knows the right signatures and types and even added the declare var com: any | com to said file.

I based the following code on this guide’s explanation: https://docs.telerik.com/devtools/android/controls/calendar/calendar-events

Here is my class:

export class MyEventRenderer extends com.telerik.widget.calendar.events.EventRenderer {
    shapeSpacing = 25;
    shapeRadius = 10;
    paint: android.graphics.Paint;
    constructor(Ctx: android.content.Context) {
        super(Ctx);
        this.paint = new android.graphics.Paint();
        this.paint.setAntiAlias(true);

        return global.__native(this); //Added this line when I saw all the examples doing it. Not really explained why you have to do it but the compailer seems to not append it and you never get the native object back, so I assume this is just that. Also it now recieves an object of instance EventRenderer
    }

    public renderEvents(canvas: androidgraphicsCanvas, cell: com.telerik.widget.calendar.CalendarDayCell): void {
        console.log("rendering!"); //Never happens
        let startX = cell.getLeft() + this.shapeSpacing;
        let startY = cell.getTop() + this.shapeSpacing;

        let drawTextRect: android.graphics.Rect = new android.graphics.Rect();
        if (cell.getText() != null) {
            let text = cell.getText();
            cell.getTextPaint().getTextBounds(text, 0, text.length, drawTextRect);
        }

        let x = startX;
        let y = startY;

        let spacingForDate = drawTextRect.width();

        for (let i = 0; i < cell.getEvents().size(); i++) {
            let e = cell.getEvents().get(i);
            this.paint.setColor(e.getEventColor());
            canvas.drawCircle(x, y, this.shapeRadius, this.paint);
            x += this.shapeSpacing;
            if (x > cell.getRight() - spacingForDate - this.shapeSpacing) {
                x = startX;
                y += this.shapeSpacing;
            }
        }
    }
}

And here is the implementation (on home-page.ts):

const hvm = new HomeViewModel();

export function refreshCalendar() {
    hvm.calendarEventsExample();
    const calendar = <calendarModule.RadCalendar>topmost().getViewById("calendar");
    if (android) {
        const eventRender = new MyEventRenderer(android.context);
        calendar.android.getEventAdapter().setRenderer(eventRender);
    }
}

**This is the error I get: **

Error: Cannot convert object to Lcom/telerik/widget/calendar/events/EventRenderer; at index 0
File: "file:///data/data/org.nativescript.MyFirstApp/files/app/home/home-page.js, line: 26, column: 43

One thing I did to see if I was receiving the right object type was the following:


console.log("MyEventRenderer:");
console.log(eventRender instanceof MyEventRenderer); //FALSE!!
console.log("EventRenderer:");
console.log(eventRender instanceof com.telerik.widget.calendar.events.EventRenderer); //TRUE

I have no idea why this happens, the eventRenderer I create returns false to an instance of the very class it instantiates but true as expected from the class it was extended from. So not sure why there is a convertion error.

Am I missing something here? I get that it might not be the right object signature or that the implementation is wrong (maybe the guide missed other @override methods needed). Any suggestions?

Thanks!


Nativescript Calendar: Label inside Cell in month view
#2

Error: Cannot convert object to … usually occurs when a JavaScript instance is returned in constructor instead of the native java instance. But I could see you are already handling that in your constructor with global.__native(this).

To debug further, try removing constructor completely and write a log statement inside your renderEvents and see if that hits. Also please share which version of CLI, Runtime, and Pro UI you are using.


#3

Ceirtanly!

I’m using NS 3.4.2, just updated.

Using Pro UI 3.3.0, core modules ^3.4.0

So removing the constructor wont fire the renderEvents() method at all either. But wont throw any errors at any point, it seems that it’s just ignoring it. The calendar does render the events but its the default Shape_and_Text way. [This is probably due to the calendar assigning a new object with default props instead of throwing an exception]

Thank you so much for taking the time to answer!


#4

Glad you got a solution.

At my end the issue was never reproduced, I was able to successfully extend from base class, renderEvents used to be called with or without a constructor.


#5

Hey man! Thanks again for replying.

I never got a solution. It keeps crashing at the same line with the same error.

It never fires the event, with or without the constructor, it crashes every single time.

Would it be possible, with the code above, for you to show me if the circles do get painted? I even started a new project from scratch but to no avail.

Thanks

Edit: I probably didn’t express myself correctly on my first answer haha. The thing is, if I create a normal, vanilla EventRenderer I do get a normal render-method-event-result with its default setting [Shape_And_Text according to the enum values]. However I’m trying to do it my way with a circle shape instead. So I probably didn’t express myself correctly. <-- This never worked, it crashed and I still cannot extend the base class.


#6

Your exact code works for me in Playground.

Note: I doubt playground supports TypeScript’s extend syntax, so I have used JavaScript one. But should not be a problem in local project, last time it worked for me.


#7

Man, I have no idea what’s going on!

So I tried to extend it using normal JS syntax, on my code-behind-file, the way you do it.

Here are some insights and questions, hopefully you can still take time to answer :slight_smile:

  1. On the playground example you linked, [which does work BTW] you create an onLoad event for the calendar. You seem to be getting the caller object through const android = (<any>args.object).android; (do correct me if I’m wrong) <-- Is this so you get the caller’s native instance? not sure what this line is exactly doing specially with the .android bit, ir why it would be necessary. Maybe a good practice?
export function onCalendarLoaded(args: EventData) {
    hvm.calendarEventsExample();
    const android = (<any>args.object).android;
    if (android) {
        // initializeEventRenderer(); // Commented to see if it worked with my extended class, but to no avail.
        android.getEventAdapter()
            .setRenderer(new MyEventRenderer(application.android.context));
    }
}
  1. Right, so if I keep the object.extend syntax that is inside initializeEventRenderer(); and then use the onLoad event, it does paint a circle as intended. However, if I try to use MyEventRenderer, from another file with proper TypeScript syntax and constructor with super(Ctx), it crashes just the same.

This baffles me so much! I have no idea why this happens!

  1. I still have no idea how to keep my code, since the only way that seemed to work was avoiding TypeScript syntax and therefore not use my extended class/constructor. Then use JS syntax to extend the base class [like you did], which needs a declaration (again) of both com and android, but this kind of defeat the whole idea of using TS :frowning:

Hopefully you could provide your insight on the matter. Again, thank you so much for taking the time to answer.


#8

Here you go,

  1. .android / .nativeView is how you will get access to the underlaying native component. Using <any> just for TypeScript’s type casting.
  2. As I already mentioned, TypeScript’s extend syntax should work on a local project (tested already), just seems to be a issue with Playground as TypeScript’s __extend helper overrides the NativeScript’s one while compiling.
  3. I have a lot of customization in my projects where I still use the TypeScript syntax and tns-platform-declarations, works great for me. Not exactly sure why not in your end.

#9

Hey man!

Thank you for your insight!

After a while, I still couldn’t get TS syntax to work, no matter what version I use or if I do it in a new project. Not sure where it goes wrong.

So export class MyEventRenderer extends com.telerik.widget.calendar.events.EventRenderer { ... } did not work at all.

I even added
/// <reference path="node_modules/nativescript-pro-ui/android.d.ts" />
to my reference file to avoid doing this in my class:
extends (com.telerik.widget.calendar.events.EventRenderer as { new(context):any; }) { }

Anyways, the only way that it seemed to work was to stick to .extend({}) of the parent class com.telerik.widget.calendar.events.EventRenderer

So it looks like:

declare var com: any; 
export var MyEventRenderer = com.telerik.widget.calendar.events.EventRenderer.extend({...}); 

Again, thanks for taking the time to answer.

It still baffles me that TS extend syntax couldn’t yield the right object.

Best Regards!