Events

This sample shows how to bind to Wijmo control events and integrate them with the Angular event broadcasting infrastructure.

Binding to Wijmo events

The wijmo.angular module allows you to bind to control events by specifying the event handler as a value of the attribute corresponding to the control event name. You can specify any valid AngularJS expression as an event handler.

The expression may reference any controller scope properties, plus two additional variables:

The most basic form of an event handler is a function with sender and eventArgs parameters, like you use when you attach a handler in JavaScript code.

The example below attaches the controller scope's onValueChanged function to the InputNumber control's valueChanged event and shows a dialog with the new control value read from the InputNumber.value property:

<wj-input-number value-changed="onValueChanged(s,e)" format="n0" step="10"> </wj-input-number>
$scope.onValueChanged = function (sender, eventArgs) { alert('New value is ' + sender.value); }

Result (live):

True MVC handling

In order to retrieve the new value in the example above, the event handler function in the controller must be familiar with the InputNumber control, which is a part of the view, and reads its value property to get the new value. You may not like this if you are trying for a true MVC approach and want the controller to know nothing about its view.

Fortunately, you can easily correct this. In the example below, the onValueChanged function is declared in the controller with the single newValue parameter, instead of the parameters referencing the control and its data, and the event expression in the markup uses the s.value expression to pass the new value itself, instead of the reference to the control.

<wj-input-number value-changed="onValueChanged(s.value)" format="n0" step="10"> </wj-input-number>
$scope.onValueChanged = function (newValue) { alert('New value is ' + newValue); }

Result (live):

Integrating with Angular events

AngularJS provides the event propagation and handling infrastructure represented by the $scope API methods: $emit, $broadcast, and $on. This API allows multiple controllers in the same page to exchange messages and behave as a single functional unit.

You can integrate Wijmo events into this infrastructure by calling the $emit or $broadcast method from the event handler function defined in the controller scope, or define such calls right in the event attribute on the control directive element, providing another event name agreed upon between controllers, and event data in the approved format.

In the example below, three controllers are organized in a hierarchical structure:

Level 1
The companyCtrl controller has a company property that stores an object representing a company and its stock exchange data.
The HTML header element is bound to the company.name property, making it a header for the whole view.
Level 2
The companyListCtrl controller provides an array of companies in the companies property.
Each company item defines a company name, stock market symbol and an array of stock prices for a certain period of time.
The Wijmo ListBox control is bound to this property, allowing users to choose companies in the list.
Level 3
The companyPricesCtrl controller exposes the prices property with an array of stock prices for each symbol.
The Wijmo FlexChart control is bound to this property, and shows a graph of the stock prices for the selected symbol.

The companyCtrl and companyPricesCtrl controllers recognize the companyChanged event using the $scope.$on method and update their company and prices properties accordingly.

The Wijmo ListBox control, which is bound to the companyListCtrl.companies array, drives the whole unit. The selectedIndexChanged event handler of the control calls the AngularJS $emit and $broadcast methods, passing companyChanged as the event name and the new selected company as the event data, forcing the other two controllers to update their property values, which in turn causes the bound views to update.

The AngularJS event is triggered right from the event attribute in the markup:
selected-index-changed="$emit('companyChanged', s.selectedItem); $broadcast('companyChanged', s.selectedItem)"

<!-- Level 1 --> <div ng-controller="companyCtrl"> <h2 style="color:#88bde6">{{company.name}}</h2> <!-- Level 2 --> <div ng-controller="companyListCtrl" class="child-content"> <wj-list-box items-source="companies" display-member-path="symbol" selected-index-changed= "$emit('companyChanged', s.selectedItem); $broadcast('companyChanged', s.selectedItem)" style="width:250px"></wj-list-box> <!-- Level 3 --> <div ng-controller="companyPricesCtrl" class="child-content"> <wj-flex-chart items-source="prices" binding-x="date" binding="price" header="Prices (1st trading day of each month)" chart-type="LineSymbols"> <wj-flex-chart-axis wj-property="axisX" format="MMM" major-unit="30"> </wj-flex-chart-axis> <wj-flex-chart-legend position="None"> </wj-flex-chart-legend> <wj-flex-chart-series name="Prices"> </wj-flex-chart-series> </wj-flex-chart> </div> </div> </div>
var app = angular.module('app'); app.controller('companyCtrl', function appCtrl($scope) { $scope.company = undefined; $scope.$on('companyChanged', function (event, data) { $scope.company = data; if (!$scope.$root.$$phase) { $scope.$apply(); } }); }); app.controller('companyListCtrl', function appCtrl($scope) { $scope.companies = [ { name: 'Apple Inc', symbol: 'AAPL', prices: getPrices('AAPL') }, { name: 'Amazon, Inc.', symbol: 'AMZN', prices: getPrices('AMZN') }, { name: 'Google Inc.', symbol: 'GOOG', prices: getPrices('GOOG') }, { name: 'Yahoo Inc.', symbol: 'YHOO', prices: getPrices('YHOO') }, ]; }); app.controller('companyPricesCtrl', function appCtrl($scope) { $scope.prices = []; $scope.$on('companyChanged', function (event, data) { $scope.prices = data.prices; if (!$scope.$root.$$phase) { $scope.$apply(); } }); }); function getPrices(symbol) { switch (symbol) { case 'AAPL': return [ { date: new Date('2014-11-03'), price: 108.93 }, { date: new Date('2014-10-01'), price: 98.75 }, { date: new Date('2014-09-02'), price: 102.85 }, { date: new Date('2014-08-01'), price: 95.24 }, { date: new Date('2014-07-01'), price: 92.66 }, ]; case 'AMZN': return [ { date: new Date('2014-11-03'), price: 305.72 }, { date: new Date('2014-10-01'), price: 317.46 }, { date: new Date('2014-09-02'), price: 342.38 }, { date: new Date('2014-08-01'), price: 307.06 }, { date: new Date('2014-07-01'), price: 332.39 }, ]; case 'GOOG': return [ { date: new Date('2014-11-03'), price: 555.22 }, { date: new Date('2014-10-01'), price: 568.27 }, { date: new Date('2014-09-02'), price: 577.33 }, { date: new Date('2014-08-01'), price: 566.07 }, { date: new Date('2014-07-01'), price: 582.67 }, ]; case 'YHOO': return [ { date: new Date('2014-11-03'), price: 46.34 }, { date: new Date('2014-10-01'), price: 40.32 }, { date: new Date('2014-09-02'), price: 39.27 }, { date: new Date('2014-08-01'), price: 35.62 }, { date: new Date('2014-07-01'), price: 35.35 }, ]; default: return []; } }

Result (live):

{{company.name}}