Using widgets with Angular
In this tutorial, you'll learn how to easily integrate widgets into Angular, using the WatchList widget as an example. Let's create a simple widget component.
Simple widget
Let's create a component of watch list widget as basic example:
import { Component, effect, ElementRef, OnDestroy, OnInit, signal, ViewChild } from '@angular/core'
import { newWatchListWidget, WatchListWidgetState } from '@dxfeed-widgets/watch-list'
const dataProviders = {
ipfPath: '/your-path/ipf',
ipfAuthHeader: 'your-header',
feedPath: 'wss://your-path/feed',
feedAuthHeader: 'your-header',
fundamentalsPath: '/api/fundamentals',
fundamentalsAuthHeader: 'your-header',
schedulePath: '/api/schedule',
}
@Component({
selector: 'watch-list',
standalone: true,
template: ` <div class="root" #watch-list></div>`,
})
export class WatchListComponent implements OnInit, OnDestroy {
@ViewChild('watch-list', { static: true })
widgetContainer: ElementRef | undefined
widget: ReturnType<typeof newWatchListWidget> | null = null
injector = inject(Injector)
ngOnInit(): void {
this.widget = newWatchListWidget({
element: this.widgetContainer?.nativeElement,
providers: dataProviders,
// Here you can enable or disable different widget features
config: {
dataExportEnabled: true
}
// Here you can provide initial state of you widget
state: {
symbols: [],
selectedSymbol: undefined,
columns: ['symbol', 'lastPrice'],
columnSizes: {},
filters: {},
sort: undefined,
}
})
}
ngOnDestroy(): void {
this.widget?.unmount()
}
}
Connecting widgets
Using standalone widget is a possible way to use library, but let's make something more complex and create a connection between two widgets.
Firstly, we need to establish a shareable state. As an example, we can connect widgets by symbol. In this case, our app will appear as follows:
import { Component } from '@angular/core'
import { WatchListComponent } from './watch-list.component'
@Component({
selector: 'two-linked-widgets',
standalone: true,
imports: [WatchListComponent],
template: `
<div class="root">
<watch-list (selectedSymbolChange)="onSymbolSelect($event)"></watch-list>
</div>
`,
})
export class TwoLinkedComponent {
selectedSymbol: string | undefined
onSymbolSelect(symbol: string | undefined): void {
this.state.selectedSymbol = symbol
}
}
We provide some state on the top level of our application. Let's now adjust our simple component and create one more widget to facilitate the passing of widget state.
@Component({
selector: 'watch-list',
standalone: true,
template: ` <div class="root" #watch-list></div>`,
})
export class WatchListComponent implements OnInit, OnDestroy {
@ViewChild('watch-list', { static: true })
widgetContainer: ElementRef | undefined
@Output()
selectedSymbolChange: EventEmitter<string | undefined> = new EventEmitter()
widget: ReturnType<typeof newWatchListWidget> | null = null
injector = inject(Injector)
ngOnInit(): void {
this.widget = newWatchListWidget({
element: this.widgetContainer?.nativeElement,
providers: dataProviders,
// Here you can enable or disable different widget features
config: {
dataExportEnabled: true
}
// Here you can provide initial state of you widget
state: {
symbols: [],
selectedSymbol: undefined,
columns: ['symbol', 'lastPrice'],
columnSizes: {},
filters: {},
sort: undefined,
}
})
this.widget.addStateListener('selectedSymbol', symbol => {
this.selectedSymbolChange.emit(symbol)
})
}
ngOnDestroy(): void {
this.widget?.unmount()
}
}
@Component({
selector: 'time-and-sales',
standalone: true,
template: ` <div class="root" #time-and-sales></div>`,
})
export class TimeAndSalesComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('time-and-sales', { static: true })
widgetContainer: ElementRef | undefined
@Input() symbol: string | undefined
widget: ReturnType<typeof newTimeAndSalesWidget> | null = null
injector = inject(Injector)
ngOnInit(): void {
this.widget = newTimeAndSalesWidget({
element: this.widgetContainer?.nativeElement,
providers: dataProviders,
})
}
ngOnChanges(changes: SimpleChanges) {
this.widget?.updateState({ symbol: changes['symbol'].currentValue })
}
ngOnDestroy(): void {
this.widget?.unmount()
}
}
Now we can provide this data to another component or widget the following way:
import { Component } from '@angular/core'
import { WatchListComponent } from './watch-list.component'
import { TimeAndSalesComponent } from './time-and-sales.component'
import { AnyAnotherComponent } from './any-another.component'
@Component({
selector: 'two-linked-widgets',
standalone: true,
imports: [WatchListComponent, TimeAndSalesComponent, AnyAnotherComponent],
template: `
<div class="root">
<watch-list
(selectedSymbolChange)="onSymbolSelect($event)"
></watch-list>
<time-and-sales [symbol]="state.selectedSymbol"></time-and-sales
<any-another-component [symbol]="state.selectedSymbol"></any-another-component>
</div>
`,
})
export class TwoLinkedComponent {
selectedSymbol: string | undefined
onSymbolSelect(symbol: string | undefined): void {
this.state.selectedSymbol = symbol
}
}