Hi Team,
We have done migration from 10.2 to 11.2.1 angular for multiple widgets. In new version of angular application multiple customized widgets.
Please see below design page for customizable dashboard. we have added two customized widgets. it's showing same result.
we have added two properties uniqueWidgetId and customAccountNumber in gridInformation.
on the basis of these properties we need to initialise the customized widgets. we want to send uniqueWidgetId and customAccountNumber to the customized widgets component from customizable dashboard component. how to send these id's to customized widgets ?.
13 Answer(s)
-
0
Hi,
looking forward to hear from you.
Regards, Aslam
-
0
Hi @aslam.loni
It is not passing uniqe id to the widget in your version. It is implemented here https://github.com/aspnetzero/aspnet-zero-core/pull/4488/files#diff-4193057d53f587480db3ccfd1a5ed167d0b46371461c12ac9782e0012768b809R174.
-
0
Hi @musa.demir
I tried to implement code from above github link but it is not working as expected. Do you have any other solution or code to refer?
Regards, Aslam
-
0
Hi @aslam.loni
Can you please follow that to get access to the github project https://support.aspnetzero.com/QA/Questions/9580/How-to-access-the-ASPNET-Zero-private-GitHub-repository
-
0
Hi @musa.demir
I have github access to this URL. I have read that code and implimented in our sourc code. It's not working as we want in our application. Do you have any other solution. Our release is stuck due to this issue. Looking forward to hear from you as soon as possible.
Please see below error during execution
ERROR NullInjectorError
core.mjs:6494 ERROR NullInjectorError: R3InjectorError(MainModule)[InjectionToken WidgetOnResizeEventHandlerToken -> InjectionToken WidgetOnResizeEventHandlerToken -> InjectionToken WidgetOnResizeEventHandlerToken -> InjectionToken WidgetOnResizeEventHandlerToken]: NullInjectorError: No provider for InjectionToken WidgetOnResizeEventHandlerToken! at NullInjector.get (core.mjs:11157:1) at R3Injector.get (core.mjs:11324:1) at R3Injector.get (core.mjs:11324:1) at R3Injector.get (core.mjs:11324:1) at NgModuleRef.get (core.mjs:21888:1) at R3Injector.get (core.mjs:11324:1) at NgModuleRef.get (core.mjs:21888:1) at Object.get (core.mjs:21565:1) at lookupTokenUsingModuleInjector (core.mjs:3367:1) at getOrCreateInjectable (core.mjs:3479:1)
Please see below code block
customizable-dashboard.component.html
<gridster-item *ngFor="let widget of page.widgets" [item]="widget.gridInformation"> <ng-container *ngComponentOutlet="widget.component"></ng-container> <gridster-item *ngFor="let widget of page.widgets" [item]="widget.gridInformation" (itemResize)="onGridSterItemResize(widget)"> <ng-container *ngComponentOutlet="widget.component; injector:this.widgetSubjects[widget.guid].injector"></ng-container> <button class="btn btn-sm text-white bg-danger deleteWidgetButton" *ngIf="editModeEnabled" (click)="removeItem(widget.gridInformation)" > <i class="la la-times"></i> </button> </gridster-item> </gridster-item>
customizable-dashboard.component.ts
import { GuidGeneratorService } from '@shared/utils/guid-generator.service'; export const WIDGETONRESIZEEVENTHANDLERTOKEN = new InjectionToken<WidgetOnResizeEventHandler>('WidgetOnResizeEventHandlerToken'); @Injectable() export class WidgetOnResizeEventHandler { onResize: Subject<any> = new Subject(); } initializeUserDashboardDefinition(userDashboardResultFromServer: Dashboard, dashboardDefinitionResult: DashboardOutput) { this.userDashboard = { dashboardName: this.dashboardName, filters: [], pages: userDashboardResultFromServer.pages.map((page) => { //gridster should has its own options this.options.push(this.getGridsterConfig()); if (!page.widgets) { return { id: page.id, name: page.name, widgets: [], }; } //only use widgets which dashboard definition contains and have view definition //(dashboard definition can be changed after users save their dashboard, because it depends on permissions and other stuff) page.widgets = page.widgets.filter( (w) => dashboardDefinitionResult.widgets.find((d) => d.id === w.widgetId) && this.getWidgetViewDefinition(w.widgetId) ); return { id: page.id, name: page.name, widgets: page.widgets.map((widget) => { return { id: widget.widgetId, guid: this._guidGenerator.guid(), //View definitions are stored in the angular side(a component of widget/filter etc.) get view definition and use defined component component: this.getWidgetViewDefinition(widget.widgetId).component, gridInformation: { id: widget.widgetId, cols: widget.width, rows: widget.height, x: widget.positionX, y: widget.positionY, uniqueWidgetId:widget.uniqueWidgetId, customAccountNumber:widget.customAccountNumber, }, }; }), }; }), }; } ngOnInit() { //abp.event.trigger('app.dashboardFilters.dateRangePicker.onDateChange', this.selectedDateRange); forkJoin([ this._dashboardCustomizationServiceProxy.getUserDashboard(this.dashboardName, DashboardCustomizationConst.Applications.Angular), this._dashboardCustomizationServiceProxy.getDashboardDefinition(this.dashboardName, DashboardCustomizationConst.Applications.Angular) ] ) .subscribe(([userDashboardResultFromServer, dashboardDefinitionResult]) => { this.dashboardDefinition = dashboardDefinitionResult; if (!this.dashboardDefinition.widgets || this.dashboardDefinition.widgets.length === 0) { this.loading = false; this.busy = false; return; } if (!userDashboardResultFromServer.pages || userDashboardResultFromServer.pages.length === 0 || userDashboardResultFromServer.pages.flatMap(page=>page.widgets).length === 0 ) { this.loading = false; this.busy = false; return; } this.initializeUserDashboardDefinition(userDashboardResultFromServer, dashboardDefinitionResult); this.initializeUserDashboardFilters(); this.createWidgetSubjects(); //select first page (if user delete all pages server will add default page to userDashboard.) this.selectedPage = { id: this.userDashboard.pages[0].id, name: this.userDashboard.pages[0].name }; } onGridSterItemResize(item: any): void { if (this.editModeEnabled) { if (this.widgetSubjects[item.guid]) { this.widgetSubjects[item.guid].handler.onResize.next(null); } } } createWidgetSubjects() { for (let i = 0; i < this.userDashboard.pages.length; i++) { var page = this.userDashboard.pages[i]; for (let i = 0; i < page.widgets.length; i++) { const widget = page.widgets[i]; this.createWidgetSubject(widget.guid); } } } createWidgetSubject(guid: string) { var handler = new WidgetOnResizeEventHandler(); this.widgetSubjects[guid] = { handler, injector: Injector.create({ providers: [{ provide: WIDGETONRESIZEEVENTHANDLERTOKEN, useValue: handler }], parent: this._injector }) } }
widget-profit-share.component.html
export class WidgetProfitShareComponent extends WidgetComponentBaseComponent implements OnInit { profitSharePieChart: ProfitSharePieChart; constructor(injector: Injector, private _dashboardService: TenantDashboardServiceProxy, @Inject(WIDGETONRESIZEEVENTHANDLERTOKEN) private _widgetOnResizeEventHandler: WidgetOnResizeEventHandler ) { super(injector); this.profitSharePieChart = new ProfitSharePieChart(this._dashboardService); _widgetOnResizeEventHandler.onResize.subscribe(() => { this.profitSharePieChart.reload(); }); } ngOnInit() { this.profitSharePieChart.reload(); } }
-
0
Hi @musa.demir
Looking forward to hear from you.
Regards, Aslam
-
0
Hi @aslam.loni It seems like you forgot to add some part of code. Can you please verify that you implemented those:
https://github.com/aspnetzero/aspnet-zero-core/pull/4488/files#diff-4193057d53f587480db3ccfd1a5ed167d0b46371461c12ac9782e0012768b809R30
https://github.com/aspnetzero/aspnet-zero-core/pull/4488/files#diff-4193057d53f587480db3ccfd1a5ed167d0b46371461c12ac9782e0012768b809R189
https://github.com/aspnetzero/aspnet-zero-core/pull/4488/files#diff-4193057d53f587480db3ccfd1a5ed167d0b46371461c12ac9782e0012768b809R531-R558
https://github.com/aspnetzero/aspnet-zero-core/pull/4488/files#diff-62571f284f4986759baa1210492103467d49ce107ca53e02389acf51e119b3cdR50-R51
-
0
Hi @musa.demir,
Essentially we would like to pass Widget.SomeProperty ( here Widget refers to the Widget Class defined in service-proxies.ts ) from customizable-dashboard.component.html to widget-{WidgetName}.component.ts
Can you please explain the steps needed to achieve this? We are not able to understand the relationship between the code shared above and what we need to implement exactly.
-
0
Hi @aslam.loni
I think this is not supported at the moment. You can create a base widget and create different implementations of the base widget with the parameter you want to pass for now. For example, you may have BaseSaleWidget and CarSaleWidget and ServiceSaleWidget etc...
-
0
Hi @ismcagdas,
Unfortunately this would not work for us since we want to add the same widget multiple times to the dashboard and bind each instance to a specific value. We want to then retrieve the data for the widget from the database using this specific value.
Can you please suggest any alternative way to implement same or similar functionality?
-
0
Hi @aslam.loni
Could you share how you area planning to add those widgets to page ? Could you share the real life usage scenario ? If I can understand it better, maybe I can offer you another option.
-
0
Hi @ismcagdas,
We are building an Accounting and Financial Modelling related system. Hence, on the dashboard we have widgets that can be mapped to specific accounts selected by the user. The widgets will then show data with various filters such as Monthly, Quarterly, Yearly, under different budgets, scenarios, etc. Here, it is important to note that every user may want to add different accounts on their dashboard depending upon their role in the organization, type of the organization, organizational goals etc.
Hence, we need to create a Custom Account Widget that can be mapped by the users to any account of their choice. Since there can be multiple accounts being watched, it would be useful to have multiple instances of this widget bound to different Account Numbers.
-
0
Hi @aslam.loni
Thanks. I think in that case, you can follow such an approach. First of all, you can assign a uniqueId to each widget. You can modify widget source code and generate a new guid. After that, you can define a new setting for widget filters and store it with the unique widgetId in AbpSettings table. When a widget is rendered, it can get the related setting and show the correct data by using that filter.