charts inside angular template

10 posts, 2 answers
  1. Pacôme
    Pacôme avatar
    7 posts
    Member since:
    Nov 2017

    Posted 27 Nov Link to this post

    Hello, 

    I want to use a ngFor template in order to display multiple charts in the same view and without having to write each charts.
    Here is my template, i've tried to put it inside ScrollView, FlexboxLayout, StackLayout, without success.
    I'm attaching the result i get in an emulator.
    Thank you for considering my problem.

    <ng-template ngFor let-facet [ngForOf]="facets">
        <label [text]="facet.id"></label>
        <RadCartesianChart id="facet.id" height="300" (pointSelected)="filterResults($event)
        (pointDeselected)="unselect($event)">
        <CategoricalAxis seriesName="AxeH" tkCartesianHorizontalAxis labelFitMode="Rotate" allowPan="true"
        allowZoom="true"></CategoricalAxis>
        <LinearAxis seriesName="AxeV" tkCartesianVerticalAxis labelFormat="%.0f"></LinearAxis>
        <BarSeries seriesName="Bar" selectionMode="DataPoint" tkCartesianSeries [items]="facet.values"
        categoryProperty="name" valueProperty="count"></BarSeries>
        </RadCartesianChart>
    </ng-template>
  2. Pacôme
    Pacôme avatar
    7 posts
    Member since:
    Nov 2017

    Posted 27 Nov in reply to Pacôme Link to this post

    Nevermind, I solved the problem by putting ng-template inside ScrollView + StackLayout.
    The problem was with the ScrollView and I've found the solution here : https://stackoverflow.com/questions/44480310/how-can-i-make-a-stacklayout-with-ngfor-loop-into-scrollable-list#
  3. Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 27 Nov Link to this post

    Hello Pacome,

    The display error indicates that most likely the NativeScriptUIChartModule is not imported in the respective NgModule class.
    Instructions on how and where to import this module can be found in this documentation article.
    keep in mind that if you are using Lazy Loading of Angular modules you will need to explicitly import the chart module in the lazily loaded module.

    As a side note, the overall recommendation to use ListView for repeating elements instead of ngFor. The reason is explained here but simply put - using ListView will provide you with recycling and virtualization and this way the application will be performance optimized and using structural Angular directives may cause Out-Of-Memory issues.

    For example:
    <ListView [items]="facets"  class="list-group">
        <ng-template let-facet="item" let-i="index" >
            <StackLayout>
                <Label [text]="i" textWrap="true"></Label>
                <RadCartesianChart height="300" backgroundColor="gray">
                    <CategoricalAxis tkCartesianHorizontalAxis></CategoricalAxis>
                    <LinearAxis tkCartesianVerticalAxis></LinearAxis>
                    <BarSeries tkCartesianSeries [items]="facet" categoryProperty="Country" valueProperty="Amount"></BarSeries>
                </RadCartesianChart>
            </StackLayout>
        </ng-template>
    </ListView>



    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  4. Pacôme
    Pacôme avatar
    7 posts
    Member since:
    Nov 2017

    Posted 29 Nov Link to this post

    Hello Nikolay, 

    Thank you for your informations, I can confirm your example works for me. The only difference I see on the UI is the lines that separates items in ListView which is okay for me if it prevents Out-Of-Memory issues.

    I have another problem, with Angular pipes on Series items which are not called. Here is my syntax, any help on that ?
    <BarSeries tkCartesianSeries [items]="facet.values | facetLabel: 'facet.facetId'" categoryProperty="label" valueProperty="count"></BarSeries>     
  5. Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 29 Nov Link to this post

    Hello Pacome,

    Regarding the lines that separate the items

    This can be resolved by setting separatorColor for your ListView.

    Regarding the pipes usage in RadChart series

    As far as I understand you are passing a parameter pipe with callback called facetLabel. However, it is not entirely clear what you are trying to achieve and what stands behind the custom pipe method you have created (called facetLabel). As the items property expects an array of items to render the Chart, please clarify what is the idea behind your pipe - the best approach would be to send us a sample project demonstrating what you have done so far and detailed description on what is the final goal. Keep in mind that items property is always expecting an array of chart items.

    Reference on how to create custom pipes (with or without parameters) can be found in this documentation article.

    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  6. Pacôme
    Pacôme avatar
    7 posts
    Member since:
    Nov 2017

    Posted 30 Nov in reply to Nikolay Iliev Link to this post

    Hello Nikolay, 

    thank you for your help, 

    Regarding the pipes : what I'm trying to achieve is to modify the array of items. I can use the pipe with the array of items as unique argument. I just can't find the right syntax for sending another argument.
        <BarSeries tkCartesianSeries [items]="facet.values | facetLabel:'facet.values':'facet.facetId'" categoryProperty="label" valueProperty="count"></BarSeries>
                              
     
     transform(facetResults: FacetResults, facetId:string) : FacetResults {
    //some code
    return facetResults
    }

    I confirm it works if i delete the second argument in both the html and ts file.
  7. Answer
    Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 30 Nov Link to this post

    Hi Pacome,

    To create an Angular pipe with multiple arguments, the syntax used for applying in the HTML file is correct. However, keep in mind that in the Pipe transform method the first passed argument is the source (in your case the items array) and then the following argument should be passed.

    To demonstrate the above, I am the Bar series example (HTML file here and Component file here) from nativescript-ui-samples-angular SDK demo application.
    Let's assume that we want to create a Pipe that will simply modify the original items array by passing two arguments.

    Here is how the HTML file will
    <RadCartesianChart tkExampleTitle tkToggleNavButton>
        <CategoricalAxis tkCartesianHorizontalAxis></CategoricalAxis>
        <LinearAxis tkCartesianVerticalAxis></LinearAxis>
        <BarSeries tkCartesianSeries [items]="categoricalSource | tkMyPipe: 55 : 77 " categoryProperty="Country" valueProperty="Amount"></BarSeries>
    </RadCartesianChart>


    and here is the actual code for our tkMyPipe
    @Pipe({
        name: "tkMyPipe"
    })
    export class MyPipe implements PipeTransform {
        // note that the first argument that transform is receiving is the actual data source,
        // then we are passing args1 (value 55 in the HTML) and args2 (value 77 in the HTML)
        transform(data: Array<any>, args1: any, args2: any): any {
            console.dir(data); // e.g. [object Object],[object Object],[object Object] ... the original source array
            console.log(args1); // e.g. 55
            console.log(args2); // e.g. 77
     
            // returning the modified array of items
            return [
                { Country: "Venera", Amount: args1, SecondVal: 14, ThirdVal: 24, Impact: 0, Year: 0 },
                { Country: "Mars", Amount: args2, SecondVal: 23, ThirdVal: 25, Impact: 0, Year: 0 },
            ];
        }
    }

    Nice SO thread exampling the above technique can be found here.
    I hope the info will help you resolve your issue - please do let me know if you need further assistance.

    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  8. Answer
    Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 30 Nov Link to this post

    Hi Pacome,

    To create Angular pipe with multiple arguments, the syntax ou are applying in the HTML file is correct. However, keep in mind that in the Pipe transform method the fisrt passed argument is actually the source (in your case the items array) and then the follwing argument should be passed.

    To demonstrate the above I am the Bar series example (HTML file here and Component file here) from nativescript-ui-samples-angular SDK demo application.
    Let's assume that we want to create a Pipe that wil simply modify the original items array by passing two arguments.

    Here is how the HTML file will
    <RadCartesianChart tkExampleTitle tkToggleNavButton>
        <CategoricalAxis tkCartesianHorizontalAxis></CategoricalAxis>
        <LinearAxis tkCartesianVerticalAxis></LinearAxis>
        <BarSeries tkCartesianSeries [items]="categoricalSource | tkMyPipe: 55 : 77 " categoryProperty="Country" valueProperty="Amount"></BarSeries>
    </RadCartesianChart>


    and here is the actual code for our tkMyPipe
    @Pipe({
        name: "tkMyPipe"
    })
    export class MyPipe implements PipeTransform {
        // note that the first argument that transform is receiving is the actual data source,
        // then we are passing args1 (value 55 in the HTML) and args2 (value 77 in the HTML)
        transform(data: Array<any>, args1: any, args2: any): any {
            console.dir(data); // e.g. [object Object],[object Object],[object Object]
            console.log(args1); // e.g. 55
            console.log(args2); // e.g. 77
     
            // returning the modified array of items
            return [
                { Country: "Venera", Amount: args1, SecondVal: 14, ThirdVal: 24, Impact: 0, Year: 0 },
                { Country: "Mars", Amount: args2, SecondVal: 23, ThirdVal: 25, Impact: 0, Year: 0 },
            ];
        }
    }

    Nice SO thread exapling the above technique can be found here.
    I hope the info will help you resolve your issue - please do let me know if you need further assistance.

    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  9. Pacôme
    Pacôme avatar
    7 posts
    Member since:
    Nov 2017

    Posted 04 Dec in reply to Nikolay Iliev Link to this post

    Hello Nikolay, 

    I have now a ListView with different templates and multiple charts. It compiles ok, but when scrolling down my app crash and I have no idea why. 

    An uncaught Exception occurred on "main" thread.
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
        at java.util.ArrayList.get(ArrayList.java:411)
        at com.telerik.widget.chart.visualization.pieChart.PieSeries.getDataPointColor(PieSeries.java:380)
        at com.telerik.widget.chart.visualization.pieChart.PieSeriesLabelRenderer.getLabelFillPaint(PieSeriesLabelRenderer.java:55)
        at com.telerik.widget.chart.visualization.common.renderers.BaseLabelRenderer.drawLabelBackground(BaseLabelRenderer.java:471)
        at com.telerik.widget.chart.visualization.common.renderers.BaseLabelRenderer.renderLabel(BaseLabelRenderer.java:408)
        at com.telerik.widget.chart.visualization.common.ChartSeries.drawLabels(ChartSeries.java:648)
        at com.telerik.widget.chart.visualization.common.ChartSeries.postRender(ChartSeries.java:576)
        at com.telerik.widget.chart.visualization.common.RadChartViewBase.onDraw(RadChartViewBase.java:287)
        at android.view.View.draw(View.java:17185)
        at android.view.View.buildDrawingCacheImpl(View.java:16474)
        at android.view.View.buildDrawingCache(View.java:16335)
        at android.view.View.draw(View.java:16943)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
        at android.view.View.updateDisplayListIfDirty(View.java:16162)
        at android.view.View.draw(View.java:16951)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
        at android.view.View.updateDisplayListIfDirty(View.java:16162)
        at android.view.View.draw(View.java:16951)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
        at android.widget.ListView.drawChild(ListView.java:3508)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
        at android.widget.AbsListView.dispatchDraw(AbsListView.java:2636)
        at android.widget.ListView.dispatchDraw(ListView.java:3503)
        at android.view.View.draw(View.java:17188)
        at android.widget.AbsListView.draw(AbsListView.java:4299)
        at android.view.View.updateDisplayListIfDirty(View.java:16167)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3711)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3691)
        at android.view.View.updateDisplayListIfDirty(View.java:16130)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:648)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:654)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:762)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2800)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2608)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2215)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6337)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
        at android.view.Choreographer.doCallbacks(Choreographer.java:686)
        at android.view.Choreographer.doFrame(Choreographer.java:621)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
  10. Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 04 Dec Link to this post

    Hi Pacome,

    The error log indicates that some part of the code is probably trying to access/modify item at an index that is not existent (e.g. in a source array).
    However, the error log itself is not enough to reproduce the issue or to give additional instructions on how to handle this case.

    As this is an issue not related to the original one, please post new ticket describing the issue in details and providing a sample project that can reproduce the behavior.
    This way, you will receive proper instructions and the information will be stored in a separate ticket where it can be easily accessed anytime. Note that, you can try to create sample project by using the NativeScript PlayGround where the RadCharts and the list view is supported and the created projects can be shared via URL links.

    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
Back to Top