Quantcast
Channel: Top 20 tutorials Blogs from GrapeCity
Viewing all 93 articles
Browse latest View live

Introducing MultiRow Grid Functionality in Wijmo Enterprise

$
0
0

For some time, Wijmo’s Japanese market has asked for a MultiRow grid feature: one that displays cells in a stacked format, reducing the need to scroll right to view additional columns. While it’s not a familiar spreadsheet format in North America, it’s very popular in Japan, and makes a lot of sense once you understand how it works.

In the example below, each item record consists of two rows (we’ll call them first and second). The first row includes Order ID, change date, person who changed it, etc. The second row includes ship date, suggested change date, etc:

Wrap columns to prevent scrolling with MultiRow

Wrap columns to prevent scrolling with MultiRow

With the heavier border between records, you can see how  a user can quickly assess all the fields in a record, instead of needing to scroll right to see more. In addition, you can group like fields so they’re in the same column, offering more of a summary at a glance.

In Wijmo’s MultiRow, you can even collapse the header into a single row:

Collapse headers

Collapse headers

Basic Features and Benefits of MultiRow Grids

  • Display many fields in single page without scrolling.
  • Display a grid in a flexible layout. For instance, in reports, you can create multiple rows and merge cells in single record.
  • Group some fields and show hierarchical structure. For example, you can show customer’s name, e-mail, address fields in the same column group.
  • Provides all the same features as FlexGrid.

Key Features

  • Uses multiple rows to represent each record.
  • Merging cells for each record (not only for single record).
  • Header has the same layout as body, and also header can be collapsed into single row.
  • Users can navigate with keyboard just same way as single row grid.
  • Select all rows of a record by clicking row header.
  • FlexGrid features are also supported. Filtering, grouping, paging, freezing rows and columns, adding and deleting records, data type, datamap, resizing column, etc.

MultiRow is available only in Wijmo Enterprise, and is a great tool for business applications.

Get started with MultiRow.

The post Introducing MultiRow Grid Functionality in Wijmo Enterprise appeared first on Wijmo.


Create a Custom StepChart with FlexChart’s itemFormatter

$
0
0

Wijmo 5 FlexChart offers many advanced features and several Chart Types that are standard in visualization tools. You can also manipulate the FlexChart’s appearance to mimic a different Chart Type. In this example, we’ll walk through how to create a Step Chart, which is a contiguous line chart that consists of horizontal and vertical lines like the image below.

Basic StepChart example

Basic StepChart example

At the moment, Step Chart is not an out-of-the-box feature available with FlexChart, but the appearance can still be achieved. We will use a Scatter Chart Type to do this:

Wijmo's out-of-the-box Scatter Chart

Wijmo’s out-of-the-box Scatter Chart

In order to achieve a Step Chart appearance from the "Scatter" Chart Type, we’ll need to manipulate the format using a property of the FlexChart called itemFormatter.

Using itemFormatter to Customize Scatter Chart

The itemFormatter property allows you to customize the appearance of the chart when the grid is rendered by setting this property to a function.

In this example, we’ll create a function with three parameters:

  1. IRenderEngine object is responsible for drawing pixels on the screen, so we’ll need this to draw the vertical and horizontal lines.
  2. HitTestInfo class provides information about the FlexChart coordinates like the series of data points and the respective pixel coordinates.
  3. A callback function will add the default format to the FlexChart. In our example, we’re using a Scatter Chart Type, so this function will populate the FlexChart control with the Scatter elements at each data point (refer to image below). If we omit this function, the Scatter elements will not appear.

These parameters are sufficient for us to manipulate the grid in any way we like.

The Basic Concept: Draw Lines Between Data Points

To accomplish the StepChart appearance we simply need to draw horizontal and vertical lines to the current data point and the previous data point. We’ll use the Point class, which represents a data coordinate in the FlexChart. (I’ll refer to the points on the FlexChart as data points.)

  1. The first thing to do in our function is get the data about the series and the current data point to be rendered to the chart.
  2. Next, we need to get the previous data point, so we can draw a line to it. If we’re looking at the first data point, we can skip this step because there’s no previous item to point at.
  3. The last point we need is where the two lines connect, which we’ll call the meeting point. The meeting point is the current data point’s X-Coordinate and the previous data point’s Y-Coordinate.

Now we can use the IRenderEngine object to draw our lines. The vertical line will be drawn from the current data point to the meeting data point. The horizontal line will be drawn from the meeting data point to the previous data point.

Here’s an example of the implementation:

chart.itemFormatter = function (engine, hitTestInfo, defaultFormat) {
        	if (hitTestInfo.chartElement == wijmo.chart.ChartElement.SeriesSymbol) {
            	var item = hitTestInfo.item;
	var series = hitTestInfo.series;
	var pi = hitTestInfo.pointIndex;
            	if( pi > 0) {
		var xvals = series.getValues(1);
		// previous data point
                	var prevX = xvals ? xvals[pi - 1] : pi - 1;
		var prevY = series.getValues(0)[pi - 1];
		// convert to pixel coordinates
                	var pt1 = chart.dataToPoint( item.x, prevY);
                	var pt2 = chart.dataToPoint( prevX, prevY);
		// draw lines
                	engine.drawLine( hitTestInfo.point.x, hitTestInfo.point.y, pt1.x, pt1.y);
                	engine.drawLine( pt1.x, pt1.y, pt2.x, pt2.y);
            	}
            // draw default symbol
            defaultFormat();
            }
        };

Your new FlexChart should look something like this:

A custom StepChart with data points

A custom StepChart with data points

Conclusion

The beauty of the itemFormatter property is it doesn’t harm the performance of the application. It’s a base functionality of FlexChart that exists to allow easy customization of the appearance.

In the near future, StepChart will be available as a Chart Type, so creating StepCharts will be even easier. In addition, keep your eye out for other featured Chart Types,including Error Bar Chart, Histogram, Waterfall, and Sunburst.

View the fiddle

Read more about FlexChart

The post Create a Custom StepChart with FlexChart’s itemFormatter appeared first on Wijmo.

Create Amazing Dynamic Charts using Wijmo

$
0
0

Good charts turn raw data into information that users can grasp easily. Great charts go beyond that. They tell engaging stories and invite exploration and discovery. This blog describes the process of implementing of one of the greatest charts I have ever seen using the Wijmo library.

The Chart

We will be implementing a bubble chart that was originally developed by GapMinder, and made famous by a memorable 2006 TED talk by Hans Rosling. The chart shows the evolution of life expectancy, income, and population in 178 countries over a 210-year period.

The same chart was later implemented by Mike Bostock using his D3 library.

The chart is amazing because it includes an animation feature that shows how each country evolved over time in terms of life expectancy, income, and population. As you watch the animation, you can track individual countries or see overall patterns emerge. The final result tells a fascinating story about the Wealth and Health of Nations.

Here is a static version of Mike Bostock’s version of the chart:

Mike Bostock's Wealth and Health of Nations

Mike Bostock’s Wealth and Health of Nations

The Data

Accurate data is at the core of all good charts. Collecting and updating this data is usually the hardest part of creating the charts. Fortunately for us, this part of the job was done by GapMinder and Mike Bostock. We use the same data file in Mike’s sample.

The data is stored in a one-megabyte json file containing information in this format:

 {
    "name": "United States",
    "region": "America",
    "income": [
      [ 1800, 1912.62 ],
      ...
      [ 2009, 41256.08 ]
    ],
    "population": [
      [ 1820, 9980510 ],
      ...
      [ 2008, 303824646 ]
    ],
    "lifeExpectancy": [
      [ 1800, 39.41 ],
      ...
      [ 2009, 79.43 ]
    ]
  }

The income, population, and life expectancy data are represented by arrays of year/value pairs. The data is sparse, especially prior to 1950, and the sample uses linear interpolation to fill in the gaps.

The Wijmo Implementation

Implementing this interactive, dynamic chart using Wijmo and the AngularJS framework was surprisingly easy.

The Controller

The first step was to declare a controller with the time span, the current year, and the data. The data was loaded using Wijmo’s httpRequest method and stored in a CollectionView:

// get reference to the app, create controller
var app = angular.module('app');
app.controller('appCtrl', function ($scope) {
    // nation data
    $scope.yrMin = 1800;
    $scope.yrMax = 2009;
    $scope.year = $scope.yrMin;
    $scope.data = new wijmo.collections.CollectionView(null, {
        sortDescriptions: [
            new wijmo.collections.SortDescription('yearPopulation', false)
        ],
        filter: function (item) {
           return item.population.length > 1 &&
                item.income.length > 1 &&
                item.lifeExpectancy.length > 1;
        }
    });
    // get data
    // https://bost.ocks.org/mike/nations/nations.json
    wijmo.httpRequest('nations.json', {
        success: function (xhr) {
            $scope.data.sourceCollection = JSON.parse(xhr.response);
            $scope.toggleAnimation(); // start animation when data is loaded
        }
    });
});

The “data” CollectionView is initialized without any data, but with a sort description and a filter.

The sort description ensures countries with large populations are plotted first, so they don’t obscure smaller countries.

The filter is used to remove items without enough data. In our data set, there are two countries in this category: Mayotte and Tokelau. This leaves 266 countries on the chart.

The “toggleAnimation” method is responsible for changing the “year” variable between its current value and the last year available, 2009. It was implemented using Wijmo’s animate method:

// animate the year
$scope.animating = 0;
$scope.toggleAnimation = function () {
    if ($scope.animating) {
        clearInterval($scope.animating);
        $scope.animating = null;
    } else {
        var min = ($scope.year < $scope.yrMax - 10) ? $scope.year : $scope.yrMin,
            max = $scope.yrMax,
            duration = 10000 * (max - min) / ($scope.yrMax - $scope.yrMin);
        $scope.animating = wijmo.animate(function (pct) {
            $scope.year = Math.round(min + (max - min) * pct);
            $scope.$apply();
            if (pct == 1) {
                $scope.animating = null;
                $scope.$apply();
            }
        }, duration);
    }
}

The last interesting part of the controller is the function that watches the “year” variable and updates the statistics to reflect the current year:

// update data for current year
$scope.$watch('year', function () {
    $scope.updateData();
});
$scope.updateData = function () {
    var year = $scope.year,
        items = $scope.data.items;
    for (var i = 0; i < items.length; i++) {
        var item = items;
        item.yearIncome = interpolate(item.income, year);
        item.yearPopulation = interpolate(item.population, year);
        item.yearLifeExpectancy = interpolate(item.lifeExpectancy, year);
    }
    $scope.data.refresh();
}

When the year changes, the code scans all the data items and sets “year*” properties to values obtained by interpolating the original data to get the current year’s value. After the loop, the code calls the “refresh” method on the CollectionView so any bound controls will be notified and updated.

At this point, the data is loaded and ready to be plotted. So let’s move on to the view.

The View

The view was implemented using Wijmo’s Angular directives.

It starts with a linear gauge used to show and select the current year, and a button to toggle the animation:

<wj-linear-gauge
    value="year"
    min="{{yrMin}}" max="{{yrMax}}"
    is-read-only="false"
    is-animated="false"
    thumb-size="30">
    <wj-range wj-property="face" thickness="0.08"></wj-range>
    <wj-range wj-property="pointer" thickness="0.08"></wj-range>
</wj-linear-gauge>
<button class="btn btn-success" ng-click="toggleAnimation()">
    <span ng-class="{ 'glyphicon-stop': animating … }"></span>
</button>

The gauge’s “value” property is bound to the “year” variable in the controller. Because the gauge’s “isReadOnly” property is set to false, it can be used to edit the year.

The button element uses the “ng-click” attribute to toggle the animation, and the “ng-class” attribute to show a “play” or “stop” glyph depending on the current state.

Finally, we get to the chart:

<wj-flex-chart
    items-source="data"
    chart-type="Bubble"
    options="{ bubble: { minSize: 5, maxSize: 100 } }"
    item-formatter="chartItemFormatter"
    binding-x="yearIncome"
    tooltip-content="<b>{item.name}</b><br/>{yearPopulation:g1,,} million people">
    <div class="watermark">
        {{ year }}
    </div>
    <wj-flex-chart-series
        binding="yearLifeExpectancy,yearPopulation">
    </wj-flex-chart-series>
    <wj-flex-chart-axis
        wj-property="axisX"
        title="income per capita (inflation-adjusted US dollars)"
        major-grid="false" axis-line="true" min="300" max="100000" log-base="10">
    </wj-flex-chart-axis>
    <wj-flex-chart-axis
        wj-property="axisY"
        title="life expectancy (years)"
        major-grid="false" axis-line="true" min="20" max="85" major-unit="10">
    </wj-flex-chart-axis>
    <wj-flex-chart-legend position="None">
    </wj-flex-chart-legend>
</wj-flex-chart>

The “itemsSource” property is set to the “data” variable in the controller. This is the sorted and filtered CollectionView that contains all the items. When the current year changes, the collection and the chart are automatically updated.

The “chartType” property is set to “Bubble”, and the “options” property is used to set the minimum and maximum size of the bubble symbols. The “itemFormatter” property points to a function used to customize the color of each bubble to reflect the item’s region. In our data set, countries are divided into six regions: Sub-Saharan Africa, South Asia, Middle East & North Africa, America, and Europe & Central Asia. The function is trivial, so we won’t list it here. Please refer to the sample’s source code for details.

The “tooltipContent” property is set to a string that represents an HTML template. In our example, the tooltip will show the country name in bold, followed by its population in the current year, scaled to millions.

Within the chart element, we added a div element that displays the current year as a watermark. The element is positioned behind the chart’s series and axes, and formatted as a large transparent number aligned to the bottom-right of the chart.

The chart series element has a “binding” property that specifies the properties of the data items that represent the Y value and bubble size. The X value was specified by the “bindingX” attribute on the chart element itself.

The axis elements specify the titles and scaling for the X and Y axes. By default, the scaling is calculated automatically, but in this case we wanted to keep it constant so the axes remain fixed as the current year changes.

The explanation is longer than the markup. The final result looks very similar to the original sample:

Wijmo version of the chart

Wijmo version of the chart

Final Touches

When I finished the first version of this sample, one of my colleagues made two really cool suggestions:

  1. Use opacity in order to improve the display of clustered bubbles. With semi-transparent bubbles, clusters with more overlapping bubbles appear as darker areas, improving the quality of the chart, and
  2. Turn on chart selection so users can pick a country they are interested in and track it through the animation.

I loved both suggestions, because they improve the sample a lot, and also because they were really easy to implement. Basically, all I had to do was set the chart’s “selectionMode” property and add a couple of CSS rules.

This image shows the final version of the sample, this time tracking Mexico as it moved across the screen:

Final version: Opacity and Filter

Use opacity to improve the display, and country selection to filter results

Conclusion

I love charts, and had been planning to implement a Wijmo version of this amazing chart for quite some time. When I finally got around to doing it, I was amazed at how easy it turned out to be. It took less than a day to put the whole thing together.

Of course, this was possible only because the idea and the data were made available by GapMinder and Mike Bostock, and I am very grateful to them.

Comparing this implementation to the original is hard, because that was a larger sample, written with Adobe Flash. The original version takes a while to load, but when it’s loaded it offers lots of options including the ability to show different indicators not included in this version.

Compared to the D3 implementation, the animation in our sample is not as smooth. That is because D3 creates the bubbles once, as SVG elements, and then animates smoothly them as they change values. Our sample, on the other hand, re-creates all the bubbles at each animation step. The animation works fine, but it is not as smooth.

The advantage of the Wijmo implementation is that it is extremely general and simple. It leverages the CollectionView class to provide sorting, filtering, and binding notifications as most Wijmo samples do. The markup used to create the chart is also standard, identical to the markup we use to create static business charts. It relies completely on the FlexChart’s performance to create the illusion of animation.

Comparing Wijmo to D3 would be like comparing apples and oranges. Wijmo is a library of UI components for business Web applications. It includes grids, charts, gauges, and input components that are powerful, easy to use, and easy to customize.

D3 is a library for manipulating documents based on data. It excels at creating custom data visualizations like the one described here. In general, creating charts using D3 requires more knowledge, talent, and dedication than using a charting control.

Whatever tool you choose, I hope you find these samples and charts as interesting and inspiring as I do.

View the Sample

Try out the sample for yourself: WealthHealth sample

The post Create Amazing Dynamic Charts using Wijmo appeared first on Wijmo.

Building Great Web Forms with Wijmo

$
0
0

Most web applications use forms to get data from users. Whether the form is made of text boxes, toggles, buttons, checkboxes, or custom controls, web developers need to be purposeful about forms to make users happy and increase conversions.

Our friends at Udacity and Google have put together a course called Building High Conversion Web Forms that covers the main aspects of creating effective web forms.

The course contains a lot of useful information, starting with the amount of information on the form and covering input types, labels, using autocomplete to save users from typing, HTML validation, location services, and touch support. We highly recommend it.

This document extends those basic, general concepts to Wijmo input controls, and how to use them to build highly effective forms.

Pro-active Validation

HTML 5 includes a validation API and validation attributes that allow you to specify if fields are required, minimum and maximum values, pattern-based constraints, and custom validation. You can find out more about the HTML 5 validation API in Mozilla’s Data form validation page.

Wijmo supports HTML 5 validation and extends it by providing “pro-active” validation. If you set the “min” and “max” properties on a Wijmo InputNumber or InputDate control, users will not be able to enter values outside the valid range at all. If a string field has a pre-defined list of acceptable values, use a ComboBox and set the “isEditable” property to false to ensure the value will be one of the options provided.

Formatting and Globalization

All Wijmo controls are localizable, so numbers, dates, and times are formatted and parsed according to the culture selected for the application. The globalization does not interfere with validation, because unlike HTML, Wijmo input controls use actual numbers and dates, not strings.

Touch support

Wijmo has touch support built-in, so in most cases you can forget about that completely. For example, if you click a button to drop-down a list of strings or a calendar, Wijmo will not show a soft keyboard on your phone or tablet. This may seem like a small thing, but it makes a huge difference in usability.

Pseudo-classes

CSS pseudo-classes are keywords added to selectors that specifies a special state of the element to be selected. For example, “:hover” will apply a style when the user hovers over the element specified by the selector.

Pseudo-classes are important in forms because they let you apply styles to elements not only in relation to the content of the document tree, but also in relation to external factors like whether the element has the focus (“:focus”) or is in an invalid state (“:invalid”).

Some of the standard pseudo-classes are limited in their usefulness because they apply only to specific elements, and not to the elements ancestors. For example, many Wijmo input controls contain input elements; when the input elements have the focus, they get the “:focus” pseudo-class, but the control host that contains it does not.

For this reason, Wijmo adds some pseudo-classes of its own to make building effective forms easier:

  • wj-state-focused: Added to control host elements when the control contains the focus (not necessarily when the host element has the focus).
  • wj-state-invalid: Added to control host elements when the control contains an input element in an invalid state.
  • wj-state-empty: Added to control host elements when the control contains an input element with no content (this is different from the “:empty” pseudo-class which is applied to elements that have no children.

Using the Wijmo Pseudo-classes

These pseudo-classes make it possible to build elements that behave like TextField components in Material Design Lite or paper-input elements in Polymer. These composite elements contain a label, an input control, and a validation message.

When the input control is empty and not focused, the label text moves over the input control, assuming the role of a “placeholder”. When the input control has the focus, or is not empty, the label moves to the top-left of the component. The result is a compact and attractive unit that is intuitive, easy-to-use, and very engaging on desktops and on mobile devices.

The image below shows a few input elements in various states:

01_form

The first field is being edited. Notice the blue underline. The second field contains an invalid e-mail address. Notice the red color and the message below the field. The second row of fields contains empty values, so the labels move over the input elements, playing the role of placeholders.

These components were created using HTML and CSS. Thanks to Wijmo’s pseudo-classes, no JavaScript code is required. Here is some of the markup to illustrate:

<div class="wj-labeled-input">
    <wj-combo-box autocomplete="name"
        is-required="true"
        text="item.name"
        id="name"
        accesskey="n">
    </wj-combo-box>
    <label for="name">Name</label>
    <div class="wj-error">We do need your name...</div>
</div>
<div class="wj-labeled-input">
    <wj-combo-box autocomplete="email"
        is-required="true"
        input-type="email"
        pattern="\S+@\S+\.\S+"
        text="item.email"
        id="email"
        accesskey="e">
    </wj-combo-box>
    <label for="email">E-mail</label>
    <div class="wj-error">We need a valid e-mail...</div>
</div>
  

Notice how the markup uses standard HTML features (autocomplete, accesskey, pattern) even though it uses Wijmo controls rather than regular input elements.

The “wj-labeled-input” class and the Wijmo pseudo-classes are used in the CSS to style the whole input elements, including the label, input control, and validation message. For example:

 .wj-labeled-input label {
    font-size: 16px;
    top: 24px;
    …
    color: rgba(0, 0, 0, 0.258824);
    transition-duration: .2s;
    transition-timing-function: cubic-bezier(.4,0,.2,1);
}
    /* move label out of the way when control is focused or not empty */
    .wj-labeled-input .wj-state-focused + label,
    .wj-labeled-input :not(.wj-state-empty) + label {
        font-size: 12px;
        top: 4px;
        color: rgb(63,81,181);
    }

This CSS can be used on any forms that contain any Wijmo input controls, and it can be easily customized to match any application styles. It was adapted from the CSS used to implement the TextField component in Google’s Material Design Lite.

View the Demo

Try this sample for yourself: InputLabels sample

The post Building Great Web Forms with Wijmo appeared first on Wijmo.

2016 Rio: Summer Games Olympic Medal Tracker

$
0
0

Header
2016 is an exciting year for the Olympic games as it is attended by a record number of countries competing in a record number of games. To help keep track of the country leaderboard for this year’s games, we built an OlympicTracker sample. Beginning August 5th we’ll provide real time updates to the medal totals for each nation.

We used AngularJS as our framework, Wijmo for our data visualizations and Material Design for our user interface and UX. You can use these three technologies together to quickly build a full featured application. A great benefit of choosing any of these three technologies is that you can use each one of them independently from the other libraries.

This sample uses a web service to retrieve the number of medals won by each country in real time during the event and then presents that information in two different ways:

1. Wijmo FlexGrid

Grid

2. Wijmo Stacked FlexChart.

Chart
Working with this type of live data feed (just like working with historical data) is relatively simple. We’ll use AngularJS $http to read a JSON file from a server and then build a CollectionView out of our dataset to use for our data layer.

The CollectionView is not just a simple array, but includes advanced are features like Record Management which we will utilize. We can then load that data into a grid employing features such as cell templates, pagination, searching or filtering capabilities, and sorting. The FlexChart provides an alternate means of visualizing the same data that makes it easier to compare results at a glance.

Stay tuned throughout the Olympics as the data updates in our OlympicTracker sample!

The post 2016 Rio: Summer Games Olympic Medal Tracker appeared first on Wijmo.

Using Class Inheritance to Create a Custom Component in Angular 2

$
0
0

As part of the Angular 2 custom component series, today we’re looking into how to create a custom component by inheriting a base class. Specifically, we’ll create an InheritedGrid by deriving it from the Wijmo’s WjFlexGrid component.

Full Series

import { Inject, Injector, ElementRef } from 'angular2/core';
import * as wjGrid from 'wijmo/wijmo.angular2.grid';
export class InheritedGrid extends wjGrid.WjFlexGrid {
  constructor( @Inject(ElementRef) elRef: ElementRef,
         @Inject(Injector) injector: Injector) {
      super(elRef, injector);
  }
}

 

Defining the Constructor

Most of the Wijmo Angular 2 components define a constructor with two parameters of ElementRef and Injector types, and the WjFlexGrid component is not an exception. In order to initialize the base WjFlexGrid class correctly, our component has to define at least these two parameters and pass them to the base class constructor using the super call.

Define the New Class with a Decorator

Now we have our InheritedGrid component, complete with the WjFlexGrid API and functionality. But remember: we’re not just creating a TypeScript class. We’re also creating the Angular 2 component that will be used in the mark-up. InheritedGrid can be used right now, but to add it to another component’s template, we’ll need to use the same wj-flex-grid element name that we did for WjFlexGrid.

That said: having two different components with the same element name is not the best idea. So our minimum customization is to provide it with a different element name. (We’re going to name it inherited-grid.) We’ll add the @Component decorator to the class definition and use the selector property to define a new name:

@Component({
  selector: 'inherited-grid'
})
export class InheritedGrid extends wjGrid.WjFlexGrid {
...
}

Now we have the new element name for our component! But we’ve missed all the other necessary settings defined in the decorator of the base WjFlexGrid class. For example, WjFlexGrid’s decorator assigns the inputs decorator property with an array of grid properties available for bindings in markup. We lost it in our new component, and if you try to bind to them now, you’ll find that the bindings don’t work.

The decorator defined on the derived class fully replaces the decorator definition provided for the base class.

This happens because the @Component decorator defined on the derived class fully replaces the decorator definition provided for the base class. So, it seems that the only way to solve this is to copy-paste all the definitions of the WjFlexGrid’s decorator to our component decorator. Doesn’t that seem to be an annoying technique, for both initial implementation and future component maintenance?

As you might guess, we wouldn’t be writing this article if we didn’t have a better solution to that problem.

@WjComponent decorator

The answer: the @WjComponent decorator offered by the Wijmo for Angular 2 module. It’s used in the same way as the standard @Component decorator and accepts all @Component decorator’s properties (plus some that are Wijmo-specific), but its main benefit is that it merges its property values with the properties provided by the base class decorator. So the last step in our component definition is replacing @Component with @WjComponent:

import { WjComponent } from 'wijmo/wijmo.angular2.directiveBase';
@WjComponent({
  selector: 'inherited-grid'
})
export class InheritedGrid extends wjGrid.WjFlexGrid {
...
}

We may have redefined the decorator’s selector property with the ”inherited-grid” name, but all the other necessary properties like inputs and outputs were taken from the base WjFlexGrid component’s decorator. And now <inherited-grid> element creates our InheritedGrid component with all the property and event bindings correctly functioning!

Magic! Where’s the applause? Well, you’re right. This is a simple and obvious solution.

If this were everything we needed from the decorator, we’d just fill in our custom component with specific settings and behaviors, add some new properties, and we’d be done. But remember: our grid component should contain the predefined Select column, and the simplest way to implement this is to add the wj-flex-grid-column component right to the inherited-grid’s template. We also should mark a place in the template where we can include arbitrary wj-flex-grid-column components.

So we’ll specify a custom template for our component in the separate inheritedGrid.html file:  

<div>
  <!-- Predefined Select column -->
  <wj-flex-grid-column 
    [header]="'Select'" 
    [binding]="'active'" 
    [name]="'select'" 
    [width]="70">
    <template wjFlexGridCellTemplate 
       [cellType]="'Cell'" 
       #cell="cell">
      <editable-selection-renderer 
         [cell]="cell"
         [selectionType]="selectionType">
      </editable-selection-renderer>
    </template>
  </wj-flex-grid-column>
  <!-- The columns specified in markup will go here -->
  <ng-content></ng-content>
</div>

The first wj-flex-grid-column element adds the Select column, with the cell template that includes the editable-selection-renderer component. The editable-selection-renderer component provides single or multiple row selection logic represented by either a radio or a checkbox input control.

After the column component, we added the <ng-content> element, which is the Angular projection placeholder element that specifies where we’ll add the child content in the template. Any wj-flex-grid-column component specified inside our <inherited-grid> component tag will be placed here. As a result, the preset Select column will always be the first column in the grid, and all the arbitrary columns nested in our component will go after it. If we specified <ng-content> element before the Select column definition, then the latter would be the last column in the grid.

With our component, we can define a grid with three columns:

<inherited-grid #grid [itemsSource]="data" [selectionType]="selectionType">
  <wj-flex-grid-column [header]="'ID'" [binding]="'id'" [width]="70">
  </wj-flex-grid-column>
  <wj-flex-grid-column [binding]="'country'"
             [header]="'Country'">
    <template wjFlexGridCellTemplate [cellType]="'Cell'" #cell="cell">
      <editable-string-renderer [cell]="cell"></editable-string-renderer>
    </template>
  </wj-flex-grid-column>
  <wj-flex-grid-column [binding]="'date'"
             [header]="'Date'"
             [width]="150">
    <template wjFlexGridCellTemplate [cellType]="'Cell'" #cell="cell">
      <editable-date-renderer [cell]="cell"></editable-date-renderer>
    </template>
  </wj-flex-grid-column>
</inherited-grid>

While we specified only three columns, our inherited-grid component shows four, including the leading Select column that is embedded in the component template.

Our component template uses some other components: WjFlexGridColumn, WjFlexGridCellTemplate and our own EditableSelectionRenderer. According to the Angular rules, we have to enumerate all these components in our component decorator’s directives property.

Our component also has to introduce two new properties: selectionType, which defines the behavior and look of the Select column cells; and isEditable, which indicates whether grid cells can be edited. To make these properties available for binding in markup, we’ll enumerate them in the decorator’s inputs property.

Taking all this into account, here’s the complete decorator definition on our component class:

@WjComponent({
  selector: 'inherited-grid',
  templateUrl: 'src/customizedComponents/inheritedGrid.html',
  directives: [wjGrid.WjFlexGridColumn,
     wjGrid.WjFlexGridCellTemplate, EditableSelectionRenderer],
  inputs: ['selectionType', 'isEditable']
})
export class InheritedGrid extends wjGrid.WjFlexGrid {
...
}

Here’s one interesting nuance regarding the decorator’s inputs propert: Although we assigned it in our component decorator, the property names defined in the inputs property of the base WjFlexGrid component are still available. This happens because, instead of replacing the inputs property array with the one defined in our decorator, @WjComponent merges arrays from the base and our class—thus making all the properties of the base and derived components available for binding.

 

Customizing behavior

We need to apply the following customizations to the base WjFlexGrid component:

  • Customization: Disable standard row selection.
    Solution: Assign the selectionMode property to None in the component constructor.
  • Customization: Disable standard cell editing.
    Solution: Assign the isReadOnly property to true in the component constructor.
  • Support enable/disable inline cell editing based on the value of the isEditable property.

To satisfy the first two requirements, we’ll modify the component constructor:

constructor( @Inject(ElementRef) elRef: ElementRef,
       @Inject(Injector) injector: Injector) {
  super(elRef, injector);
  // Disable cell selection.
  this.selectionMode = wijmo.grid.SelectionMode.None;
  // Disables standard cell editing functionality.
  this.isReadOnly = true;
}

The disable-editing requirement is a bit more complicated. We could easily do it by disabling the element that contains the grid cells, but remember that the elements representing the Select column cells should stay enabled even in case of the disabled cell editing.

Instead, we’ll use the grid’s formatItem event and change disabled state on a per-cell basis. We could subscribe a handler to implement this logic in the component constructor, but inheritance provides a better way.

Each Wijmo control event includes an onEvent method that triggers the event’s handlers. For the formatItem event, the method is onFormatItem, and the best way to go in the TypeScript OOP environment is to override it:

onFormatItem(e: wijmo.grid.FormatItemEventArgs) {
  super.onFormatItem(e);
  if (e.panel.cellType === wijmo.grid.CellType.Cell) {
    let column = <wijmo.grid.Column>this.columns[e.col];
    wijmo.enable(e.cell, this.isEditable || column.name === 'select');
  }
}

In the first line of code, we call the basic WjFlexGrid implementation of this method, which triggers the handlers subscribed to the event. Then we add a custom code that checks whether the processing cell belongs to the Select or some other column. If the processing cell belongs to a different column, we’ll enable or disable the cell element depending on isEditable’s value.

In addition, we want the new isEditable value to be reflected immediately in our grid’s appearance. We’ll define isEditable as the true property with the getter and setter, and call grid’s invalidate method to force it to refresh its cells:

private _isEditable = true;
get isEditable(): boolean {
    return this._isEditable;
}
set isEditable(value: boolean) {
    if (this._isEditable != value) {
        this._isEditable = value;
        this.invalidate();
    }
}

So that’s inheritance! In the next blog we’ll look at Aggregation.

Full Series

The post Using Class Inheritance to Create a Custom Component in Angular 2 appeared first on Wijmo.

Creating Simple Reports with AngularJS and Wijmo 5

$
0
0

Reporting is a common requirement for business applications. Many specialized tools—SSRS, FlexReport, Active Reports—are powerful and flexible, but have a learning curve associated with them.

If all you need is a simple report, you can accomplish that with a CollectionView, some templates in ng-repeat directives, and a PrintDocument:

  • The CollectionView is responsible for sorting, grouping, and filtering the data.
  • The templates and ng-repeat directives transform the data into documents, using the regular layout and styling features made available by HTML and CSS.
  • Finally, the PrintDocument class transforms the report into a print-friendly version and sends that to the browser’s printing infrastructure. The browser then takes over to provide features including print-preview (Chrome and Edge), page size and orientation, headers and footers, output device (including PDF output), etc.

This approach has some advantages and some limitations.

The main advantage is that by using the browser’s own render engine, you get the same rich layout and styling features provided by HTML and CSS. The CollectionView and PrintDocument classes are part of the Wijmo core (wijmo.min.js), so there’s nothing new to learn, and nothing extra to download.

The main disadvantage is that HTML is provides little control over page dimensions. Headers, footers, and margins are defined outside the report, between the user and the browser. CSS attributes provide some control over page breaks, though, so this is not as big a limitation as it may seem at first.

A Simple Example

We have created a sample application demonstrating the basic ideas behind creating simple reports. You can see it live, inspect the source code, or download the sample here:

http://demos.wijmo.com/5/SampleExplorer/SampleExplorer/Sample/SimpleReports

The sample implements a few reports, all based on the same mechanism:

  • Load the report data into one or more CollectionView objects,
  • Define an HTML fragment that uses ng-repeat directives and templates to define the report content,
  • Render the report into a PrintDocument and print it.

Let’s go over the details of each step.

Loading the data

The report data is typically downloaded from a server using a web service. If the data is available as an OData source, you can get it easily using an ODataCollectionView object. This is what we used in the sample, which is based on the traditional NorthWind database.

Here’s the code that loads the report data:

// load data for reports
var url = 'http://services.odata.org/V4/Northwind/Northwind.svc';
$scope.products = new wijmo.odata.ODataCollectionView(url, 'Products', {
 groupDescriptions: [
  new wijmo.collections.PropertyGroupDescription('ProductName',
   function (item, propName) {
    var value = item[propName];
    return value[0].toUpperCase();
   }
  )
 ],
 sortDescriptions: ['ProductName'],
 loaded: function (s, e) {
  $scope.$apply();
 }
});

This code loads the Products table into a CollectionView and groups the data by product initial. Notice how the groupDescriptions property is initialized with a PropertyGroupDescription object whose function returns the first letter in the product name.

When the CollectionView is loaded, in addition to the regular items collection containing the products, it will contain a groups collection containing CollectionViewGroup objects. Each group provides a name property containing the grouping value (in this case the product’s initial) and an items property that contains the products within the group. This is very useful for creating grouped reports.

$scope.categories = new wijmo.odata.ODataCollectionView(url, 'Categories', {
 fields: ['CategoryID', 'CategoryName', 'Description'],
 sortDescriptions: ['CategoryName'],
 loaded: function (s, e) {
  $scope.$apply();
 }
});

This code loads the Categories table into a CollectionView and retrieves only three fields from the server. This is done to prevent downloading the images that are not used in our reports and are relatively large and slow to download.

The application repeats this pattern to load employees, customers, sales, and invoice data.

Note that the data is loaded asynchronously; when each CollectionView is finished loading, it calls $scope.$apply to update the view with the new data.

If your data is not available as an OData source, you can still get the data using regular HttpRequest calls and create CollectionView objects based on arrays of data objects.

Defining the report

Each report is defined by an HTML fragment. In our example, the reports are stored in the application’s “partials” folder.

Let’s start with a simple report called “productsByCategory”, which is based on two data sources: “categories” and “products”. This is the HTML that defines the report:

<h1 style="background-color:#cccccc; padding:6px">
 Products By Category
 
 <span style="font-size:50%; font-style=italic">
  As of {{ today | date }}
 </span>
</h2>
<div ng-repeat="category in categories.items" style="page-break-inside:avoid">
<h2>
  {{category.CategoryName}}
 </h2>
<div style="margin-left:12pt; columns:3"> <!-- multi-column -->
<div ng-repeat="product in select(products, 'CategoryID', category.CategoryID)">
   {{ $index + 1 }}) {{ product.ProductName }}
  </div>
</div>
</div>

The report starts with a header that contains the title and today’s date. Notice how the report header uses the Angular filter called “date” to format the date value. Filters can also be used to format numbers and currencies.

That is followed by the report body, which has an ng-repeat directive that enumerates the categories. The ng-repeat directive is contained in a div element that uses a style attribute to set its CSS property page-break-inside to “avoid”. This causes the browser to keep categories together on a page if possible.

Within the category div, another ng-repeat directive enumerates the products within the current category and uses a “select” command to retrieve the list of products that belong to the current category. This inner div has the CSS property columns set to “3”, which causes the browser to render the div into three columns.

The output looks like this:

A three-column report

A three-column report

Now let’s look at another report, “employeeSalesByCountry”. Here’s the HTML that defines the report:

<!-- "classified" watermark -->
<div class="watermark">
 <img style=" position:absolute; left:50%; top:40%; transform:translate(-50%, -50%)"
    src="../resources/confidential.png" />
</div>

The report starts with a watermark that shows a “confidential” image behind the report content on every page. The “watermark” class is used by these CSS rules:
.watermark {
 position: fixed;
 width: 100%;
 height: 100%;
}
@media not print {
 .watermark {
  display: none;
 }
}

The CSS makes the watermark element fill the entire page and repeat for every page. It also make the watermark visible only on printed output and not on the screen.

Note that although the “position:fixed” setting should, in theory, cause the content to repeat on every page, not all browsers implement this correctly. Internet Explorer and Edge do it correctly; Chrome renders the watermark only on the first page. We hope this will be fixed soon.

After the watermark, we define the report header:

<!-- report header -->
<h1 style="background-color:#666; color:#fff; padding:10px">
 Employee Sales By Country
 
 <span style="font-size:50%; font-style:italic">
  Between {{ invoices.getAggregate('Min', 'OrderDate') | date }} and
      {{ invoices.getAggregate('Max', 'OrderDate') | date }}
 </span>
</h2>

The header contains a title and the dates reflected in the report. Notice how the date range is calculated directly from the data using the CollectionView’s getAggregate method.

Finally, the report body is defined as follows:

<!-- report body -->
<div ng-repeat="country in invoices.groups" style="page-break-inside:avoid">
<div style="border-bottom:6pt solid #a0a0a0; display:flex"
  ng-init="countrySales = country.getAggregate('Sum', 'ExtendedPrice')">
<div style="width:600px">
   {{ country.name }}
  </div>
<div style="width:500px; text-align:right">
   {{ countrySales | currency }}
  </div>
</div>
<div ng-repeat="salesperson in country.groups" style="display:flex"
  ng-init="personSales = salesperson.getAggregate('Sum', 'ExtendedPrice')">
<div style="width:600px; padding-left:0.5in">
   {{ salesperson.name }}
  </div>
<div style="width:200px; text-align:right">
   {{ personSales / countrySales * 100 | number:0 }}%
  </div>
<div style="width:300px; text-align:right">
   {{ personSales | currency }}
  </div>
</div>
</div>

The outer div uses an ng-repeat directive to enumerate the countries (“invoices.groups”).

It computes and saves the total country sales using the getAggregate method to sum the “ExtendedPrice” property of the invoices and saves that value in a “countrySales” variable.

It renders the country name and total sales, and then uses another ng-repeat directive to enumerate the salespersons within that country. The inner ng-repeat lists the name of the salesperson and the sales made by that person as a percentage of the total sales for the current country and as a currency value.

The result looks like this:

Grouping and aggregation

Grouping and aggregation

These two report definitions illustrate the approach used in all other reports in the sample. They’re all based on ng-repeat directives that iterate through the data and standard HTML/CSS code that formats and lays out the reports.

Generating the Reports

In our sample application, when a report is selected from the ComboBox, the corresponding view is loaded and AngularJS automatically renders it into the document.

Simply printing the document at this point generates a document containing the sample’s headers and other content that is visible, but not part of the report. Worse, the output shows the scrollbars in the container element, and the actual report is cropped.

This is where the PrintDocument class comes into play. The application controller defines a print method implemented as follows:

$scope.print = function () {
 // create document
 var doc = new wijmo.PrintDocument({
  title: $scope.reports.currentItem.header
 }); 
 // add content to it
 var view = document.querySelector('[ng-view]')
 for (var i = 0; i < view.children.length; i++) {
  doc.append(view.children);
 }

 // and print it
 doc.print();
}
Here’s what this method does.
  • It creates a PrintDocument object;
  • It sets its title property to the report name;
  •  It adds the content by copying the content of the ng-view element that contains the report;
  • And finally, it calls the document’s print method, which sends the report to the browser for previewing and printing.

Useful techniques

All of the reports in the sample use the same techniques to accomplish simple and common tasks. Some of these are especially useful when generating report-style output.

Aggregates

The CollectionView and CollectionViewGroup classes provide a getAggregate method that computes aggregates over the whole collection or group. These are useful for generating ranges or sums over groups as shown in the examples above.

For example, recall that our “employeeSalesByCountry” has a header that shows the report period. This is done using the getAggregate method:

<h1 style="background-color:#666; color:#fff; padding:10px">
 Employee Sales By Country
 
 <span style="font-size:50%; font-style:italic">
  Between {{ invoices.getAggregate('Min', 'OrderDate') | date }} and
      {{ invoices.getAggregate('Max', 'OrderDate') | date }}
 </span>
</h2>

In the same report, we calculate the total sales per country and store that value in a variable that can be used in the report and in later calculations:
<div style="border-bottom:6pt solid #a0a0a0; display:flex"
  ng-init="countrySales = country.getAggregate('Sum', 'ExtendedPrice')">
<div style="width:600px">
   {{ country.name }}
  </div>
<div style="width:500px; text-align:right">
   {{ countrySales | currency }}
  </div>
  ...

Page breaks

One of the main limitations in using the browser to generate documents is the lack of control over page size, orientation, and margins. But you do get some level of control over page breaks, which is very convenient to prevent page breaks within report sections.

This is done using the page-break-before, page-break-after, and page-break-inside CSS properties. These attributes have no effect on the screen, but they do affect printed output. Most of the reports in this sample have header sections with the page-break-inside attribute set to “avoid”, which results in groups that stay together on a page (if possible).

For example:

<div ng-repeat="salesperson in country.groups" style="page-break-inside:avoid"
 ng-init="personSales = salesperson.getAggregate('Sum', 'ExtendedPrice')">
<div style="width:600px; padding-left:0.5in">
  {{ salesperson.name }}
 </div>
<div style="width:200px; text-align:right">
  {{ personSales / countrySales * 100 | number:0 }}%
 </div>
<div style="width:300px; text-align:right">
  {{ personSales | currency }}
 </div>
</div>

The page-break-* properties are being replaced by more generic break-* properties, which also handle column and region breaks and will be syntactically compatible with page-break-*. For the time being, however, we only have control over page breaks, and not columns or regions.

Watermarks and other repeating content

In addition to controlling page breaks, you can specify content that repeats on every page, such as a watermark, letterhead, header, or footer.

This is done by putting the repeating content in a div with the position property set to “fixed”. The HTML/CSS specification dictates that this type of element should be rendered on every page. You can use this setting and a CSS media query to generate sections that repeat on every page.

The “employeeSalesByCountry” report uses this technique to add a “Confidential” watermark image to every page on the report.

Unfortunately, there are some caveats:

  • Not all browsers implement position:fixed according to the spec. We mentioned earlier that Edge and IE 11 do. Chrome, however, renders the fixed content only on the first page.
  • Using this technique to add page headers and footers can be tricky because they have to be sized and positioned in a way that works with all page sizes and orientations.
  • Users may configure the browser to add its own page headers and footers, which may conflict with the custom report headers and footers.

Multiple columns

Creating reports with multi-column sections is easy using the CSS column-width, column-count, and columns properties, or with flexible boxes.

The column property allows you to specify a column width to be used within a div. The browser will automatically calculate how many columns fit within the div and how many rows are needed to render it. This simplifies creating responsive multi-column reports. You can also specify how many columns you want, in which case, the browser calculates the column width.

The flexible box approach is slightly more complicated, but offers even more flexibility. Just set the div’s display property to “flex”, and set the wrap, align, and justify properties to achieve the layout you want. For details about flexible boxes, please see this page:

https://css-tricks.com/snippets/css/a-guide-to-flexbox

The reports in the sample use both approaches. The “productsByCategory” report uses a div with columns set to three to render product names into three columns:

<div style="margin-left:12pt; columns:3"> <!-- multi-column -->
<div ng-repeat="product in select(products, 'CategoryID', category.CategoryID)">
  {{ $index + 1 }}) {{ product.ProductName }}
 </div>
</div>

The “employeeSalesByCountry” report and several others use flex boxes to render headers aligned above the actual data:
<div style="border-bottom:6pt solid #a0a0a0; display:flex"
 ng-init="countrySales = country.getAggregate('Sum', 'ExtendedPrice')">
<div style="width:600px">
  {{ country.name }}
 </div>
<div style="width:500px; text-align:right">
  {{ countrySales | currency }}
 </div>
…

Borders

Borders are useful when defining reports because they’re always rendered in the printed output (unlike div backgrounds, which are sometimes omitted).

For example, the “salesChart” report uses this HTML to build a bar chart where each bar is a border on an element with a variable width:

<div ng-repeat="invoice in salesperson.items" style="display:flex; padding-right:6pt">
<div style="width:600px">
<div style="height:1em; margin-top:.25em; border-top:.6em solid #007200" 
     ng-style="{width: invoice.ExtendedPrice * 100 / 18000 + '%' }">
    
  </div>
</div>
…

In this case, setting the background-color would not work. The chart appears correctly on the screen, but it does not render on the print document.

Using Controls in Reports

You can use plain HTML in your report definitions, but you can also go beyond that and include other controls such as charts and gauges.

For example, the “salesByCategory” report in the sample contains this HTML:

<div ng-repeat="categorySales in productSales.groups">
<div style="display:flex; font-weight:bold; font-size:200%">
  {{categorySales.CategoryName}}
 </div>
<div style="display:flex; page-break-inside:avoid">
<div>
   …
  </div>
  <wj-flex-chart 
   style="width:500px; height:350px; margin:12pt; border:4px solid #009be0"
   items-source="categorySales.items"
   binding-x="ProductName">
   <wj-flex-chart-series binding="ProductSales">
   </wj-flex-chart-series>
  </wj-flex-chart>
 </div>
</div>

The markup uses an ng-repeat to loop over the categories. For each category, it defines a flexible box with a table containing product names and sales on the left, and a FlexChart on the right.

The wj-flex-chart directive sets the items-source property of the chart to “categorySales.items”, which contains an array of objects with ProductName and ProductSales properties. We could easily customize the chart by adding more attributes to the markup.

Here is the result:

Display controls in a report

Display controls in a report

You can use any controls in your reports, including charts, linear and radial gauges, and bullet graphs.

Specialized Reporting Tools

The techniques discussed here can be very useful for generating relatively simple reports. But if your needs are more complex, then you should consider using specialized reporting tools. These tools provide advanced features like server-side rendering and caching, control over page headers and footers, cross-tabs, parameterized reports, and much more.

We’ll soon release the Wijmo ReportViewer control, which will work with server-side reporting tools including FlexReport, ActiveReports, and Microsoft Reporting Services.

To use the ReportViewer control, create the control and set a couple of properties as usual:

var viewer = new wijmo.viewer.ReportViewer('#flexViewer', {
 serviceUrl: serviceUrl,
 filePath: reportFilesCombo.value,
 reportName: reportNamesCombo.value,
});

The viewer contacts the service, retrieves and displays the report in a UI element similar to the one in the Adobe PDF viewer.

Users will then be able navigate through the report using outline or thumbnail views, zoom, search, select report parameters, set page size and orientation, and save or print the results.

Stay tuned for more details about FlexReport and the ReportViewer control.

Conclusion

Browsers are amazing applications. They have many features that can be easily be overlooked, but are really useful in many real-world scenarios. Printing support is one of these.

You may need a specialized component for creating reports, but if you use Wijmo and AngularJS, you already have all the tools you need to generate basic reports quickly and efficiently.

And when you outgrow the basic capabilities already in your toolbox, rest assured knowing that Wijmo also supports advanced and flexible server-based reporting.

View the Sample

The post Creating Simple Reports with AngularJS and Wijmo 5 appeared first on Wijmo.

Create Amazing Dynamic Charts using Wijmo

$
0
0

Good charts turn raw data into information that users can grasp easily. Great charts go beyond that. They tell engaging stories and invite exploration and discovery. This blog describes the process of implementing of one of the greatest charts I have ever seen using the Wijmo library.

The Chart

We will be implementing a bubble chart that was originally developed by GapMinder, and made famous by a memorable 2006 TED talk by Hans Rosling. The chart shows the evolution of life expectancy, income, and population in 178 countries over a 210-year period.

The same chart was later implemented by Mike Bostock using his D3 library.

The chart is amazing because it includes an animation feature that shows how each country evolved over time in terms of life expectancy, income, and population. As you watch the animation, you can track individual countries or see overall patterns emerge. The final result tells a fascinating story about the Wealth and Health of Nations.

Here is a static version of Mike Bostock’s version of the chart:

Mike Bostock's Wealth and Health of Nations

Mike Bostock’s Wealth and Health of Nations

The Data

Accurate data is at the core of all good charts. Collecting and updating this data is usually the hardest part of creating the charts. Fortunately for us, this part of the job was done by GapMinder and Mike Bostock. We use the same data file in Mike’s sample.

The data is stored in a one-megabyte json file containing information in this format:

 {
    "name": "United States",
    "region": "America",
    "income": [
      [ 1800, 1912.62 ],
      ...
      [ 2009, 41256.08 ]
    ],
    "population": [
      [ 1820, 9980510 ],
      ...
      [ 2008, 303824646 ]
    ],
    "lifeExpectancy": [
      [ 1800, 39.41 ],
      ...
      [ 2009, 79.43 ]
    ]
  }

The income, population, and life expectancy data are represented by arrays of year/value pairs. The data is sparse, especially prior to 1950, and the sample uses linear interpolation to fill in the gaps.

The Wijmo Implementation

Implementing this interactive, dynamic chart using Wijmo and the AngularJS framework was surprisingly easy.

The Controller

The first step was to declare a controller with the time span, the current year, and the data. The data was loaded using Wijmo’s httpRequest method and stored in a CollectionView:

// get reference to the app, create controller
var app = angular.module('app');
app.controller('appCtrl', function ($scope) {
    // nation data
    $scope.yrMin = 1800;
    $scope.yrMax = 2009;
    $scope.year = $scope.yrMin;
    $scope.data = new wijmo.collections.CollectionView(null, {
        sortDescriptions: [
            new wijmo.collections.SortDescription('yearPopulation', false)
        ],
        filter: function (item) {
           return item.population.length > 1 &&
                item.income.length > 1 &&
                item.lifeExpectancy.length > 1;
        }
    });
    // get data
    // https://bost.ocks.org/mike/nations/nations.json
    wijmo.httpRequest('nations.json', {
        success: function (xhr) {
            $scope.data.sourceCollection = JSON.parse(xhr.response);
            $scope.toggleAnimation(); // start animation when data is loaded
        }
    });
});

The “data” CollectionView is initialized without any data, but with a sort description and a filter.

The sort description ensures countries with large populations are plotted first, so they don’t obscure smaller countries.

The filter is used to remove items without enough data. In our data set, there are two countries in this category: Mayotte and Tokelau. This leaves 266 countries on the chart.

The “toggleAnimation” method is responsible for changing the “year” variable between its current value and the last year available, 2009. It was implemented using Wijmo’s animate method:

// animate the year
$scope.animating = 0;
$scope.toggleAnimation = function () {
    if ($scope.animating) {
        clearInterval($scope.animating);
        $scope.animating = null;
    } else {
        var min = ($scope.year < $scope.yrMax - 10) ? $scope.year : $scope.yrMin,
            max = $scope.yrMax,
            duration = 10000 * (max - min) / ($scope.yrMax - $scope.yrMin);
        $scope.animating = wijmo.animate(function (pct) {
            $scope.year = Math.round(min + (max - min) * pct);
            $scope.$apply();
            if (pct == 1) {
                $scope.animating = null;
                $scope.$apply();
            }
        }, duration);
    }
}

The last interesting part of the controller is the function that watches the “year” variable and updates the statistics to reflect the current year:

// update data for current year
$scope.$watch('year', function () {
    $scope.updateData();
});
$scope.updateData = function () {
    var year = $scope.year,
        items = $scope.data.items;
    for (var i = 0; i < items.length; i++) {
        var item = items;
        item.yearIncome = interpolate(item.income, year);
        item.yearPopulation = interpolate(item.population, year);
        item.yearLifeExpectancy = interpolate(item.lifeExpectancy, year);
    }
    $scope.data.refresh();
}

When the year changes, the code scans all the data items and sets “year*” properties to values obtained by interpolating the original data to get the current year’s value. After the loop, the code calls the “refresh” method on the CollectionView so any bound controls will be notified and updated.

At this point, the data is loaded and ready to be plotted. So let’s move on to the view.

The View

The view was implemented using Wijmo’s Angular directives.

It starts with a linear gauge used to show and select the current year, and a button to toggle the animation:

<wj-linear-gauge
    value="year"
    min="{{yrMin}}" max="{{yrMax}}"
    is-read-only="false"
    is-animated="false"
    thumb-size="30">
    <wj-range wj-property="face" thickness="0.08"></wj-range>
    <wj-range wj-property="pointer" thickness="0.08"></wj-range>
</wj-linear-gauge>
<button class="btn btn-success" ng-click="toggleAnimation()">
    <span ng-class="{ 'glyphicon-stop': animating … }"></span>
</button>

The gauge’s “value” property is bound to the “year” variable in the controller. Because the gauge’s “isReadOnly” property is set to false, it can be used to edit the year.

The button element uses the “ng-click” attribute to toggle the animation, and the “ng-class” attribute to show a “play” or “stop” glyph depending on the current state.

Finally, we get to the chart:

<wj-flex-chart
    items-source="data"
    chart-type="Bubble"
    options="{ bubble: { minSize: 5, maxSize: 100 } }"
    item-formatter="chartItemFormatter"
    binding-x="yearIncome"
    tooltip-content="<b>{item.name}</b><br/>{yearPopulation:g1,,} million people">
    <div class="watermark">
        {{ year }}
    </div>
    <wj-flex-chart-series
        binding="yearLifeExpectancy,yearPopulation">
    </wj-flex-chart-series>
    <wj-flex-chart-axis
        wj-property="axisX"
        title="income per capita (inflation-adjusted US dollars)"
        major-grid="false" axis-line="true" min="300" max="100000" log-base="10">
    </wj-flex-chart-axis>
    <wj-flex-chart-axis
        wj-property="axisY"
        title="life expectancy (years)"
        major-grid="false" axis-line="true" min="20" max="85" major-unit="10">
    </wj-flex-chart-axis>
    <wj-flex-chart-legend position="None">
    </wj-flex-chart-legend>
</wj-flex-chart>

The “itemsSource” property is set to the “data” variable in the controller. This is the sorted and filtered CollectionView that contains all the items. When the current year changes, the collection and the chart are automatically updated.

The “chartType” property is set to “Bubble”, and the “options” property is used to set the minimum and maximum size of the bubble symbols. The “itemFormatter” property points to a function used to customize the color of each bubble to reflect the item’s region. In our data set, countries are divided into six regions: Sub-Saharan Africa, South Asia, Middle East & North Africa, America, and Europe & Central Asia. The function is trivial, so we won’t list it here. Please refer to the sample’s source code for details.

The “tooltipContent” property is set to a string that represents an HTML template. In our example, the tooltip will show the country name in bold, followed by its population in the current year, scaled to millions.

Within the chart element, we added a div element that displays the current year as a watermark. The element is positioned behind the chart’s series and axes, and formatted as a large transparent number aligned to the bottom-right of the chart.

The chart series element has a “binding” property that specifies the properties of the data items that represent the Y value and bubble size. The X value was specified by the “bindingX” attribute on the chart element itself.

The axis elements specify the titles and scaling for the X and Y axes. By default, the scaling is calculated automatically, but in this case we wanted to keep it constant so the axes remain fixed as the current year changes.

The explanation is longer than the markup. The final result looks very similar to the original sample:

Wijmo version of the chart

Wijmo version of the chart

Final Touches

When I finished the first version of this sample, one of my colleagues made two really cool suggestions:

  1. Use opacity in order to improve the display of clustered bubbles. With semi-transparent bubbles, clusters with more overlapping bubbles appear as darker areas, improving the quality of the chart, and
  2. Turn on chart selection so users can pick a country they are interested in and track it through the animation.

I loved both suggestions, because they improve the sample a lot, and also because they were really easy to implement. Basically, all I had to do was set the chart’s “selectionMode” property and add a couple of CSS rules.

This image shows the final version of the sample, this time tracking Mexico as it moved across the screen:

Final version: Opacity and Filter

Use opacity to improve the display, and country selection to filter results

Conclusion

I love charts, and had been planning to implement a Wijmo version of this amazing chart for quite some time. When I finally got around to doing it, I was amazed at how easy it turned out to be. It took less than a day to put the whole thing together.

Of course, this was possible only because the idea and the data were made available by GapMinder and Mike Bostock, and I am very grateful to them.

Comparing this implementation to the original is hard, because that was a larger sample, written with Adobe Flash. The original version takes a while to load, but when it’s loaded it offers lots of options including the ability to show different indicators not included in this version.

Compared to the D3 implementation, the animation in our sample is not as smooth. That is because D3 creates the bubbles once, as SVG elements, and then animates smoothly them as they change values. Our sample, on the other hand, re-creates all the bubbles at each animation step. The animation works fine, but it is not as smooth.

The advantage of the Wijmo implementation is that it is extremely general and simple. It leverages the CollectionView class to provide sorting, filtering, and binding notifications as most Wijmo samples do. The markup used to create the chart is also standard, identical to the markup we use to create static business charts. It relies completely on the FlexChart’s performance to create the illusion of animation.

Comparing Wijmo to D3 would be like comparing apples and oranges. Wijmo is a library of UI components for business Web applications. It includes grids, charts, gauges, and input components that are powerful, easy to use, and easy to customize.

D3 is a library for manipulating documents based on data. It excels at creating custom data visualizations like the one described here. In general, creating charts using D3 requires more knowledge, talent, and dedication than using a charting control.

Whatever tool you choose, I hope you find these samples and charts as interesting and inspiring as I do.

View the Sample

Try out the sample for yourself: WealthHealth sample

The post Create Amazing Dynamic Charts using Wijmo appeared first on Wijmo.


Building Great Web Forms with Wijmo

$
0
0

Most web applications use forms to get data from users. Whether the form is made of text boxes, toggles, buttons, checkboxes, or custom controls, web developers need to be purposeful about forms to make users happy and increase conversions.

Our friends at Udacity and Google have put together a course called Building High Conversion Web Forms that covers the main aspects of creating effective web forms.

The course contains a lot of useful information, starting with the amount of information on the form and covering input types, labels, using autocomplete to save users from typing, HTML validation, location services, and touch support. We highly recommend it.

This document extends those basic, general concepts to Wijmo input controls, and how to use them to build highly effective forms.

Pro-active Validation

HTML 5 includes a validation API and validation attributes that allow you to specify if fields are required, minimum and maximum values, pattern-based constraints, and custom validation. You can find out more about the HTML 5 validation API in Mozilla’s Data form validation page.

Wijmo supports HTML 5 validation and extends it by providing “pro-active” validation. If you set the “min” and “max” properties on a Wijmo InputNumber or InputDate control, users will not be able to enter values outside the valid range at all. If a string field has a pre-defined list of acceptable values, use a ComboBox and set the “isEditable” property to false to ensure the value will be one of the options provided.

Formatting and Globalization

All Wijmo controls are localizable, so numbers, dates, and times are formatted and parsed according to the culture selected for the application. The globalization does not interfere with validation, because unlike HTML, Wijmo input controls use actual numbers and dates, not strings.

Touch support

Wijmo has touch support built-in, so in most cases you can forget about that completely. For example, if you click a button to drop-down a list of strings or a calendar, Wijmo will not show a soft keyboard on your phone or tablet. This may seem like a small thing, but it makes a huge difference in usability.

Pseudo-classes

CSS pseudo-classes are keywords added to selectors that specifies a special state of the element to be selected. For example, “:hover” will apply a style when the user hovers over the element specified by the selector.

Pseudo-classes are important in forms because they let you apply styles to elements not only in relation to the content of the document tree, but also in relation to external factors like whether the element has the focus (“:focus”) or is in an invalid state (“:invalid”).

Some of the standard pseudo-classes are limited in their usefulness because they apply only to specific elements, and not to the elements ancestors. For example, many Wijmo input controls contain input elements; when the input elements have the focus, they get the “:focus” pseudo-class, but the control host that contains it does not.

For this reason, Wijmo adds some pseudo-classes of its own to make building effective forms easier:

  • wj-state-focused: Added to control host elements when the control contains the focus (not necessarily when the host element has the focus).
  • wj-state-invalid: Added to control host elements when the control contains an input element in an invalid state.
  • wj-state-empty: Added to control host elements when the control contains an input element with no content (this is different from the “:empty” pseudo-class which is applied to elements that have no children.

Using the Wijmo Pseudo-classes

These pseudo-classes make it possible to build elements that behave like TextField components in Material Design Lite or paper-input elements in Polymer. These composite elements contain a label, an input control, and a validation message.

When the input control is empty and not focused, the label text moves over the input control, assuming the role of a “placeholder”. When the input control has the focus, or is not empty, the label moves to the top-left of the component. The result is a compact and attractive unit that is intuitive, easy-to-use, and very engaging on desktops and on mobile devices.

The image below shows a few input elements in various states:

01_form

The first field is being edited. Notice the blue underline. The second field contains an invalid e-mail address. Notice the red color and the message below the field. The second row of fields contains empty values, so the labels move over the input elements, playing the role of placeholders.

These components were created using HTML and CSS. Thanks to Wijmo’s pseudo-classes, no JavaScript code is required. Here is some of the markup to illustrate:

<div class="wj-labeled-input">
    <wj-combo-box autocomplete="name"
        is-required="true"
        text="item.name"
        id="name"
        accesskey="n">
    </wj-combo-box>
    <label for="name">Name</label>
    <div class="wj-error">We do need your name...</div>
</div>
<div class="wj-labeled-input">
    <wj-combo-box autocomplete="email"
        is-required="true"
        input-type="email"
        pattern="\S+@\S+\.\S+"
        text="item.email"
        id="email"
        accesskey="e">
    </wj-combo-box>
    <label for="email">E-mail</label>
    <div class="wj-error">We need a valid e-mail...</div>
</div>
  

Notice how the markup uses standard HTML features (autocomplete, accesskey, pattern) even though it uses Wijmo controls rather than regular input elements.

The “wj-labeled-input” class and the Wijmo pseudo-classes are used in the CSS to style the whole input elements, including the label, input control, and validation message. For example:

 .wj-labeled-input label {
    font-size: 16px;
    top: 24px;
    …
    color: rgba(0, 0, 0, 0.258824);
    transition-duration: .2s;
    transition-timing-function: cubic-bezier(.4,0,.2,1);
}
    /* move label out of the way when control is focused or not empty */
    .wj-labeled-input .wj-state-focused + label,
    .wj-labeled-input :not(.wj-state-empty) + label {
        font-size: 12px;
        top: 4px;
        color: rgb(63,81,181);
    }

This CSS can be used on any forms that contain any Wijmo input controls, and it can be easily customized to match any application styles. It was adapted from the CSS used to implement the TextField component in Google’s Material Design Lite.

View the Demo

Try this sample for yourself: InputLabels sample

The post Building Great Web Forms with Wijmo appeared first on Wijmo.

How to Filter Hierarchical Data in FlexGrid and Angular

$
0
0

Filtering is an important feature for large data sets and may vary depending on the structure of the data being filtered. In this post, we’ll walk through filtering hierarchical data in the FlexGrid control in an Angular application.

Get the Fiddle | Download Wijmo

FlexGrid provides support for filtering and allows you to define your own filter function as well. The most common way to do this through the ICollectionView interface, but ICollectionView was designed to handle only flat data, so to handle hierarchical data we’llneed a different approach.

The Problem

Imagine we have a hierarchical collection consisting of “state” objects that have a collection of “city” objects. This could be expressed in JavaScript as follows:

// some hierarchical data
var data = [
{
name: 'Washington', type: 'state', population: 6971, cities: [
{ name: 'Seattle', type: 'city', population: 652 },
{ name: 'Spokane', type: 'city', population: 210 }
]
}, {
name: 'Oregon', type: 'state', population: 3930, cities: [
{ name: 'Portland', type: 'city', population: 609 },
{ name: 'Eugene', type: 'city', population: 159 }
]
}, {
name: 'California', type: 'state', population: 38330, cities: [
{ name: 'Los Angeles', type: 'city', population: 3884 },
{ name: 'San Diego', type: 'city', population: 1356 },
{ name: 'San Francisco', type: 'city', population: 837 }
]
}
];

If you assigned this collection to a FlexGrid’s itemsSource property, the grid would automatically display the states, but not the cities.

If you then assigned the value “cities” to the grid’s childItemsPath property, the grid would show the states and then would add child items for each element in the “cities” array. Note that in this case we have only two levels, but this process could continue to any depth.

So far, so good. But the topic of discussion here is filtering this hierarchical data.

By default, the ICollectionView used internally by the FlexGrid only deals with flat data. So you could use it to filter the states only. But what if you wanted to filter by state AND city?

The Solution: Define Rules for the Filter

To do this, we start by defining a few rules for the filter:

  1. The filter will be applied to the “name” property only.
  2. If a state (top level item) satisfies the filter, all its cities will be displayed
  3. If a city (second level item) satisfies the filter, its parent state will be displayed.

Rule #1 is arbitrary. We could use more properties in the filter.

Rule #2 is also arbitrary. If you think showing states without their cities would be useful to users, the rule can be removed.

Rule #3 is the most important one. If a user searched for “Spokane”, the grid should display the city and also its parent state. Failing to do so would create a grid with orphan items.

We’ll apply these rules directly to the grid, by traversing all rows and setting their visible property to true only if they pass the filter. The code looks like this:

// update row visibility
function updateRowVisibility(flex, filter) {
var rows = flex.rows,
filter = filter.toLowerCase();
for (var i = 0; i < rows.length; i++) {
var row = rows,
state = row.dataItem,
rng = row.getCellRange();
// handle states (level 0)
if (row.level == 0) {
// check if the state name matches the filter
var stateVisible = state.name.toLowerCase().indexOf(filter) >= 0;
if (stateVisible) {
// it does, so show the state and all its cities
for (var j = rng.topRow; j <= rng.bottomRow; j++) {
rows[j].visible = true;
}
} else {
// it does not, so check the cities
for (var j = rng.topRow + 1; j <= rng.bottomRow; j++) {
var city = rows[j].dataItem,
cityVisible = city.name.toLowerCase().indexOf(filter) >= 0;
rows[j].visible = cityVisible;
stateVisible |= cityVisible;
}
// if at least one city is visible, the state is visible
rows.visible = stateVisible;
}
// move on to the next group
i = rng.bottomRow;
}
}
}

The code uses the GroupRow’s getCellRange method to retrieve an object that contains the group’s top and bottom rows, then uses those limits to loop through entire states or individual cities.

Implementing the Solution in Angular

Let’s get started.

  1. Create an index.html file.
  2. Add the references to the controls.
  3. Add the Angular Interop.js files.
  4. Add a layout for the template. You can copy and paste the code below:
<html>
<head>
<!-- Stylesheet -->
<link rel="stylesheet" type="text/css" href="http://cdn.wijmo.com/5.latest/styles/wijmo.min.css" />
<!-- Wijmo References -->
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.grid.min.js"></script>
<!-- Wijmo Angular Interop -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/interop/angular/wijmo.angular.min.js"></script>
<!-- Angular module -->
<script src="app.js" type="text/javascript"></script>
</head>
<body>
<div ng-app="app" ng-controller="appCtrl">
<wj-flex-grid
control="flex"
style="height:260px;width:320px"
items-source="data"
headers-visibility="Column">
</wj-flex-grid>
</div>
</body>
</html>

Since we’re building an Angular application, we need to create our Angular Module and Controller.

Create a new file called app.js and copy and paste the code below.  Note: the index.html markup already includes a script tag to reference this file. Be sure the file is in the right location on your machine.

'use strict';
// define app, include Wijmo 5 directives
var app = angular.module('app', ['wj']);
// controller
app.controller('appCtrl', function ($scope) {
});

We can now add our small data set to the controller:

 // some hierarchical data
var data = [
{
name: 'Washington', type: 'state', population: 6971, cities: [
{ name: 'Seattle', type: 'city', population: 652 },
{ name: 'Spokane', type: 'city', population: 210 }
]
},
{
name: 'Oregon', type: 'state', population: 3930, cities: [
{ name: 'Portland', type: 'city', population: 609 },
{ name: 'Eugene', type: 'city', population: 159 }
]
},
{
name: 'California', type: 'state', population: 38330, cities: [
{ name: 'Los Angeles', type: 'city', population: 3884 },
{ name: 'San Diego', type: 'city', population: 1356 },
{ name: 'San Francisco', type: 'city', population: 837 }
]
}
];
$scope.data = new wijmo.collections.CollectionView(data);

On the last line of code, we set the $scope.data object to a CollectionView object, passing the data variable as a parameter. As previously mentioned, the ICollectionView interface represents our data as a flat structure, like an array or list of Objects. If you open the index.html file in a browser, you’ll only see the states of each item in the CollectionView.

CollectionView flat structure

CollectionView flat structure

In order to display the cities, we need to assign the childItemsPath property of the FlexGrid to “cities.” In your index.html file, add the childItemsPath attribute to the wj-flex-grid element and set the attribute to cities like below:

<wj-flex-grid
control="flex"
style="height:260px;width:320px"
items-source="data"
child-items-path="cities"
headers-visibility="Column">
</wj-flex-grid>

If you save the file and refresh the browser, you’ll see the city rows under each state. This is called a Tree View.

Filtering in a TreeView

Filtering in a TreeView

With the Tree View enabled, it’s now time to add the filter! If we use the CollectionView filter, only the parent item’s data properties will be considered when filtering or sorting. Instead we’ll create our own filter function. We’ve already defined our filter function above, but there are a few more steps to finalize our application.

  1. In the index.html file, add an input element and the ng-model directive to allow Angular to detect changes in the input element:
     <p>
    <input ng-model="filter" />
    </p>
    
  2. In the app.js file, add a $watch function to listen for changes in the filter model.
    // update row visibility when filter changes
    $scope.$watch('filter', function() {
    updateRowVisibility();
    });
    
  3. Finally, add the function that filters! We’ll handle filtering by simply hiding the rows that don’t match the filter. So as the user is typing, the grid will automatically update based on our filter function. Copy the updateRowVisibility function from above to the Angular controller.

Now that you’ve successfully implemented Hierarchical filtering, try using a more complicated data set or modifying the rules/behavior of your filter function.

Check out full implementation here:http://jsfiddle.net/troy_taylor/etx8em7w/

The post How to Filter Hierarchical Data in FlexGrid and Angular appeared first on Wijmo.

Integrating Wijmo Controls with Module Loaders and Bundlers

$
0
0

We’ve recently received a barrage of questions regarding Wijmo integration with various module loaders and bundlers (like SystemJS, WebPack, Angular CLI, etc), which is possible, but requires a number of extra steps. We also received a question about Wijmo npm installation, which is tightly coupled with the former.

I’d like to share with you the status of our effort destined to eliminate this complexity.

You may check the things that I’ll describe below right now using the following (or more recent) prerelease build:

http://prerelease.componentone.com/wijmo5/Nightly_C1Wijmo_5.20162.222_2016.10.10.zip

External modules

The main trouble with settling Wijmo to the aforementioned tools is that the library core (non-Ng2) modules are not "external.” Rather, they’re "global" modules accessible via the global "wijmo" variable. Loaders/bundlers work smoothly only with true (“external”) modules by following the TS/ES6 “import” statements chain in order to load or collect all necessary modules, and require a special setup for global modules.

Because of this, we created true (“external”) versions of Wijmo core library modules that should be consumed using ES6/TS ‘import’ statement. For example, the following code that used Wijmo global module:

@ViewChild('flex1') flex1: wijmo.grid.FlexGrid;
let gr = new wijmo.grid.GroupRow();

looks like here with external modules:
import * as wjcGrid from 'wijmo/wijmo.grid';
@ViewChild('flex1') flex1: wjcGrid.FlexGrid;
let gr = new wjcGrid.GroupRow();

Being true modules, they can be placed to the node_modules/wijmo folder and consumed by various loaders/bundlers in a natural way, with minimal tunings, or without tuning at all.

Npm images

The Wijmo download zip now includes the NpmImages folder with wijmo-amd, wijmo-commonjs and wijmo-system subfolders containing Wijmo external modules in different module formats (AMD, CommonJS and System respectively).

An important point here: each of these subfolder is effectively an npm image that can be installed by a command like this:

npm install <some_path>/NpmImages/wijmo-amd

The command above will install Wijmo AMD modules in the node_modules/wijmo folder of the directory from which the command was issued.

Usage examples

All Wijmo Angular 2 samples are reworked to use these new modules, and have the following record in their package.json files:

"dependencies": {
   "wijmo": "../../../../../NpmImages/wijmo-amd",
    … another modules (Ng2 etc)
}

So, it’s just enough to run “npm install” in the project folder to install both Ng2 and Wijmo libraries. The only Wijmo file which is added to projects manually is wijmo.css, which is reasonable. The only downside: if you move a sample to another location, you have to update a path to wijmo npm image in package.json.

In addition, we plan to publish .tgz files with npm images on our site and reference them in the samples using this remote location. You may find this approach in the following prerelease build: http://prerelease.componentone.com/wijmo5/C1Wijmo-Enterprise-Eval_5.20162.222.zip

With this approach, projects can be freely moved to other locations without breaking the references to Wijmo npm image. Right now this is only available for evaluation versions. We’re considering whether we can apply such an approach to licensed versions, too.

WebPack

Here’s the Angular 2 CellTemplateIntro sample adapted for usage with WebPack: http://publicfiles.componentone.com/Wijmo%205%20Files/Angular2/CellTemplateIntro_Ng2_WP.zip

The only Wijmo-specific setting here is the

import '../styles/vendor/wijmo.min.css';

statement in the src/vendor.ts file that includes wijmo.css to a bundle.

You need to perform the following steps to build and run it.

Step 1: Unzip.

It has two root folders: CellTemplateIntro, which contains the sample itself, and wijmo_zip_image, which emulates Wijmo dowload zip image, but contains only the stuff necessary for this demonstration (namely wijmo-amd npm image).

Note that the sample doesn’t contain any Wijmo library file—neither .js nor .d.ts. The only exception is wijmo.min.css in the styles\vendor folder. Because .css always requires a special treatment, this is not a wijmo-specific issue.

Step 2: Run NodeJS command prompt.

Step 3: cd to the CellTemplateIntro\CellTemplateIntro folder.

Step 4: Run "npm install"

This installs all the necessary libraries to node_modules, including the wijmo folder retrieved from the aforementioned wijmo_zip_image\NpmImages\wijmo-amd folder. The folder contains all wijmo library modules, both Ng2 interop and core (both wijmo.angular2.grid and wijmo.grid). And for each module it contains both .min.js and .d.ts files.

Step 5: Run "npm run build"

This runs the WebPack that creates an app bundle in the dist folder.

Step 6: Open wpbundle.html page in a browser.

This file loads the bundle created on the previous step and should be hosted in some web server. If you use Visual Studio, then the simplest way to run it is to open the sample solution, set wpbundle.html as a default page, and run the project.

Angular CLI

Some remarks about Angular CLI: Wijmo can be integrated there in the same simple way as to WebPack as explained above. But the trouble here is that Wijmo-minified files has a min.js extension, while module names don’t naturally include “min” in their names.

In all the loader/bundler tools, this problem—that of mapping module names to files with “min.js” extension—can be resolved by means of trivial settings, but we didn’t find any way to achieve this in Angular CLI.

At the same time, we think (OK, still think!) that adding the “min” suffix to minified file names is the right way to go, so we suppose that this is a temporary limitation that will be resolved in Angular CLI in the near future. For the time being, you need to rename “.min.js” to just “.js” before installing them to your project.

True NPM Registry

Right now, we don’t provide a possibility to perform “npm install” using “wijmo” npm registry because we have the following problem: We have two types of Wijmo builds: evaluation (with Wijmo <version> popup (nag screen) and without sources), and licensed (without popup and with sources). Each have two have two different npm registry names, but both must be installed in the same node_modules/wijmo folder. Otherwise, module names like “wijmo/wijmo.grid” used with one build will be broken when you switch to the other. We have no an immediate solution for this issue.

The post Integrating Wijmo Controls with Module Loaders and Bundlers appeared first on Wijmo.

Data Validation in a JavaScript Data Grid

$
0
0

Data validation is an important task for any applications that accept user input. In build 212, we added data validation to the CollectionView class, which can be used by all Wijmo controls that support data collections, including the FlexGrid.

View the Data Validation sample

HTML5 has good support for forms validation. Wijmo leverages that support and extends it with custom pseudo-classes and validation directives. For details on Wijmo form validation, please see the following articles:

How to Implement Data Validation in FlexGrid

To add validation support to a CollectionView, set the new getError property to a callback function that takes a data item and a property name as parameters, and returns a string with an error description (or null if there are no errors).

For example:

var view = new wijmo.collections.CollectionView(data, {
 getError: function (item, property) {
  switch (property) {
   case 'country':
    return countries.indexOf(item.country) < 0
     ? 'Invalid Country'
     : null;
   case 'downloads':
   case 'sales':
   case 'expenses':
    return item[property] < 0
     ? 'Cannot be negative!'
     : null;
   case 'active':
    return item.active && item.country.match(/US|UK/)
     ? 'Active items not allowed in the US or UK!'
     : null;
  }
  return null; // no errors detected
 }
});

Once you define the getError callback on a CollectionView, any control bound to the collection may use it to validate items being loaded or edited.

For example, the FlexGrid will use the validation logic in the data source to:

  • Automatically highlight errors by adding the ‘wj-state-invalid’ pseudo-class to row headers and to any cells that contain errors, and
  • Prevent users from entering invalid data into cells when editing.

The image below shows a FlexGrid bound to some data that contains validation errors:

Data validation in FlexGrid

Data validation in FlexGrid

The appearance of the cells that contains errors is defined in CSS and is easily customizable.

Validation is also applied while editing the grid. If a user tried to enter an invalid country, for example, the grid would apply the error style to the cell and would keep it in edit mode until the user selected a valid country or pressed the Escape key to cancel the edits.

This default behavior can be disabled by setting the grid’s validateEdits property to false.

This simple mechanism makes it easy to identify and prevent errors in the grid data and provides a consistent look and feel for grid validation.

View the Data Validation sample

The post Data Validation in a JavaScript Data Grid appeared first on Wijmo.

How to Create a Dynamic Dashboard in React

$
0
0

A while ago one of our customers asked for a sample showing how to create a “dynamic dashboard”—one like those you can create in the Google Analytics app. The image below shows an example:

01_dynamicdashboard

The key features of interest to the customer were:

  • There is a catalog of pre-defined configurable tile types.
  • Tiles may contain arbitrary UI elements such as rich text, charts, grids and gauges.
  • Users can create custom dashboards by adding, removing, reordering, and configuring “segments” (aka “tiles”).
  • Mobile device users can drag tiles using touch.

View the sample

We thought many customers might be interested in a sample like this, so we created a Dynamic Dashboard sample and made that available to our users. Since then, we received a significant amount of feedback, including interest in the drag-drop implementation, touch support, and component design.

The original sample was implemented using Wijmo and Angular 1.x. When we released our Wijmo React interop a few weeks ago, we thought this would be a great React sample as well, and decided to create a React-based version of the sample.

The React version of the sample looks exactly like the original, but the implementation is quite different and illustrates some interesting aspects of React development.

React Implementation and TSX files

The React version of the Dynamic Dashboard application is a TypeScript application. It uses TSX files which are the TypeScript equivalent of React JSX files.

Each TSX file typically contains one React component. Adding TSX files to Visual Studio projects is trivial. Right-click the project node in the Solution Explorer, select “Add” and then “TypeScript JSX File”. You can then write regular TypeScript code with the usual DOM-like extensions typical of React code.

The tooling provided by Visual Studio for React and TypeScript is excellent. You don’t have to waste any time worrying about configuration and can get right into coding, at which point you will get all the design-time error checking and productivity tools you are used to.

The screen below shows the project with the TSX files and the options offered by Visual Studio to fine-tune the handing of TSX files should you want to do so:

02_tsx

Application Architecture

The Dynamic Dashboard app has two types of components: the dashboard frame and the tiles in it.

The dashboard frame is a stateful component. It defines a catalog of tile types available and a list of the tiles that make up the current dashboard. It also provides logic for adding, removing, and reordering the tiles.

The tiles have no state (in the React sense). They receive data from the frame via properties (passed in as element attributes). Tiles are quite simple; the app defines nine type of tiles, including various charts, gauges, bullet graphs, and a grid.

In a traditional OOP application, all tiles would extend a base tile class. In React (and many other JavaScript frameworks), you are encouraged to use composition instead of inheritance. I see this as a limitation. Composition and inheritance are different mechanisms, each has its uses, and one does not fully replace the other.

In our app, we followed the React team’s advice and implemented our tiles using composition rather than inheritance. We define a Tile component that provides the tile border (with a header and buttons). The Tile component has a “content” property that defines the actual tile content.

Dashboard Frame Component

The “App” component implements our dashboard frame. It is instantiated with the following standard snippet of HTML in application’s “default.htm” file:

<body&rt;
  <div id="app"&rt;</div&rt;
  <script&rt;
    ReactDOM.render(React.createElement(App), document.getElementById('app'));
  </script&rt;
</body&rt;

The App parameter in the call to React.createElement is our dashboard frame component. It is implemented as follows:

var App = React.createClass({
  // define the component’s initial state
  getInitialState: function () {
    // tile names and types
    var tileCatalog = [
      { name: 'Grid', tile: Grid },
      { name: 'Radial Gauge', tile: RadialGauge },
      { name: 'Linear Gauge', tile: LinearGauge },
     …
    ];
    // tiles currently in use
    var tiles = [],
         key = 0;
    for (var i = 0; i < 4; i++) {
      tiles.push({ name: tileCatalog.name, key: key++ });
    }
    // generate some data to show in the tiles
    var data = …;
    // this is our app state
    return {
      tileCatalog: new wijmo.collections.CollectionView(tileCatalog),
      tiles: tiles,
      key: key,
      data: new wijmo.collections.CollectionView(data)
    }
  },

The App component’s state has four elements:

  • tileCatalog: list of tile types that are available and can be added to the dashboard.
  • tiles: list of the tiles currently on the dashboard.
  • key: identifier to use when creating the next tile (more on this later)
  • data: data to be shown on the dashboard (passed as a prop to all tiles)

Let’s move on to the component’s render method to see how the state is used to generate the dashboard.

We start by rendering a header with the application title and a logo. Notice how the TSX syntax looks a lot like HTML, with some minor differences. Instead of “class”, for example, we must use “className”. That is because although it looks like HTML, this is really JavaScript code, and the DOM element’s property is called “className”, not “class”, The same applies to the “for” attribute of label elements, which in TSX must be specified as “htmlFor”.

// render the dashboard
render: function () {
  var data = this.state.data;
  return <div>
    <div className="header">
      <div className="container">
        <img src="resources/wijmo5.png" alt="Wijmo 5" />
        <h1>
          Dynamic Dashboard (React)
        </h1>
      </div>
    </div>

Next, we render a section that contains a drop-down where the user can select the type of tile he wants and a button to add the tile to the dashboard.

We use a Wijmo ComboBox to show the tile catalog and to keep track of the tile type currently selected. The itemsSource and displayMameberPath properties are used to populate the list and to determine which property of the items should be displayed on the list. The current tile type is exposed by the catalog’s currentItem property. Next to the combo, there is a button that invoked the “addTile” method on the component:

    <div className="container">
      <div className="container row">
        <label>
          Select a tile type: {' '}
          <Wj.ComboBox
            itemsSource={ this.state.tileCatalog }
            displayMemberPath="name" />
          {' '}
          <button
            className="btn btn-primary"
            onClick={ this.addTile }>
            Add Tile to Dashboard
          </button>
        </label>
      </div>

The “addTile” method is implemented as follows:

addTile: function () {
  var tiles = this.state.tiles.slice(),
      key = this.state.key + 1;
  tiles.push({ name: this.state.tileCatalog.currentItem.name, key: key });
  this.setState({ tiles: tiles, key: key });
},

The method starts by making a copy of the current tiles array and incrementing the key used to uniquely identify tile instances. It adds a new item to the tiles array with the name specified by the catalog’s currentItem, and calls setState to update the state with the new tiles array.

The call to setState causes React to update the UI showing the updated tiles array.

The code that renders the dashboard tiles is typical React. Is uses the array.map method to generate a list of components that make up the UI. In this case, the components are instances of Tile following properties:

  • header: name of the tile (displayed in the tile header).
  • content: component that represents the tile content (e.g. a chart or gauge).
  • remove: a callback invoked when the user clicks the “delete” button on the tile header.
  • index: index of the tile within the tile array.
  • key: item identifier used by React to optimize rendering.

Note that the key and index parameters are used for different purposes. The index parameter is used by the App component to identify tiles in the tiles array, specifically when deleting tiles. The index of a tile may change if tiles are removed or reordered. The key parameter, on the other hand, is used by the React framework to establish a mapping between array elements and components. The key does not change when tiles are removed or reordered.

      <div className="dashboard">
        {
          this.state.tiles.map((item, index) => {
            return <Tile
              header={item.name}
              content={this.getTileContent(item.name)}
              remove={this.removeTile}
              index={index}
              key={item.key} />;
          })
        }
      </div>
    </div>
  </div>;
}

The getTileContent method creates and returns a component of a given type. It looks up the component type based on the name and calls React.createElement to instantiate the tile:

getTileContent(name: string) {
  var arr = this.state.tileCatalog.items;
  for (var i = 0; i < arr.length; i++) {
    if (arr.name == name) {
      return React.createElement(arr.tile, { data: this.state.data })
    }
  }
  throw '*** tile not found: ' + name;
},

The removeTile method acts as an event handler. It is called by the Tile component when the user clicks the delete button on the tile header. The code uses the array.filter method to select all tiles except the one that was clicked, and calls setState to update the state with the new tiles array.

As before, the call to setState causes React to update the UI showing the updated tiles array.

removeTile: function (tileIndex) {
  var tiles = this.state.tiles.filter((item, index) => {
    return index != tileIndex;
  });
  this.setState({ tiles: tiles });
},

Tile Components

The Tile component represents a frame to hold tile content (of all types). It is a simple stateless component implemented as follows:

var Tile = React.createClass({
  remove: function () {
    this.props.remove(this.props.index)
  },
  render: function () {
    return <div className="tile" draggable="true">
      <div style={{ borderBottom: '1px solid #e0e0e0', … }}>
        <div style={{ flexGrow:1, color: '#005c9c', fontWeight: 'bold' }}>
          { this.props.header }
        </div>
        <div className="buttons">
          <span className="glyphicon glyphicon-pencil"></span>
          <span className="glyphicon glyphicon-remove" onClick={ this.remove }></span>
        </div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', … }}>
        <div>{ this.props.content }</div>
      </div>
    </div>
  }
});

The render method creates a frame with a header and content determined by the header and content properties. The header includes a “remove” span that when clicked invokes the remove callback which is also a property (this.props.remove).

Notice how the outer div has its draggable attribute set to true. This enables HTML drag/drop operations, which we will discuss later.

The Tile component’s most interesting property is content, which represents the child component that contains the tile information. Our application defines nine types of tile content component, including charts, gauges, grid, etc. They all have a data property that is set by the parent component and contains the data to be shown on the tile.

Tile components may be as simple or complex as you like. Adding new tile types is easy: create the component to show the data in “props.data” in whatever way you want, and add the new tile type to the application component’s tileCatalog array.

Tile components may contain other components, including Wijmo data visualization controls. For example, here is the implementation of the BarChart tile component:

var BarChart = React.createClass({
  render: function () {
    return <Wj.FlexChart
      chartType="Bar"
      itemsSource={this.props.data}
      bindingX="date"
      axisX={{ format: 'MMM-yy' }}
      series={[
        { name: 'Sales', binding: 'sales' },
        { name: 'Expenses', binding: 'expenses' },
        { name: 'Profit', binding: 'profit', chartType: 'LineSymbols' }
      ]} />
  }
});

And here is the implementation of the Grid tile component:

var Grid = React.createClass({
  render: function () {
    return <Wj.FlexGrid
      isReadOnly={true}
      headersVisibility="Column"
      selectionMode="ListBox"
      itemsSource={this.props.data}
      columns={[
        { binding: 'id', header: 'ID', width: 40 },
        { binding: 'date', header: 'Date', format: 'MMM yyyy' },
        { binding: 'sales', header: 'Sales', format: 'c' },
        { binding: 'expenses', header: 'Expenses', format: 'c' },
        { binding: 'profit', header: 'Profit', format: 'c' }
      ]} />
  }
});

The main advantage of the React implementation of this app is the neat encapsulation of the tile components. Each one is represented by a single TSX file that contains the logic and UI.

Dragging Tiles

We have shown how users can customize the dashboard by adding new tiles or removing existing ones. The part that is missing is the use of drag and drop to reorder tiles, which was one of the main initial requirements for the app.

We already had this code written for the Angular version of the app. Fortunately, the code used standard HTML5 drag/drop functionality which was very easy to port to React. This was done by moving the original drag/drop code into a method called enableItemReorder and calling that from the main component’s componentDidMount method:

componentDidMount() {
  // enable tile drag/drop
  var panel = document.querySelector('.dashboard');
  this.enableItemReorder(panel);
},

The enableItemReorder method adds handlers to the standard “dragstart”, “dragover”, and “drop” HTML5 events.

Because the HTML drag/drop events work with the actual HTML elements on the DOM (and not with the React virtual DOM), we must update the state when a drop operation is finalized. This is done when handling the “drop” event, as shown in the code snippet below:

enableItemReorder(panel) {
  var dragSource = null,
      dropTarget = null;
  // add drag/drop event listeners
  panel.addEventListener('drop', (e) => {
    if (dragSource && dropTarget) {
      // re-order HTML elements (optional here, we're updating the state later)
      var srcIndex = getIndex(dragSource),
          dstIndex = getIndex(dropTarget),
          refChild = srcIndex > dstIndex ? dropTarget : dropTarget.nextElementSibling;
      dragSource.parentElement.insertBefore(dragSource, refChild);
      // update state
      var tiles = this.state.tiles.slice();
      tiles.splice(srcIndex, 1);
      tiles.splice(dstIndex, 0, this.state.tiles[srcIndex]);
      this.setState({ tiles: tiles });
    }
  });

The final piece is touch support. Since the code relies on native HTML5 drag/drop events, we added drag/drop touch support simply by including the DragDropTouch polyfill in our project.

The screenshot below shows the running application, with a tile being dragged into a new position:

03_dynamicdashboard_react

Conclusion

Porting the Dynamic Dashboard sample to React was surprisingly easy given the relative complexity of the app. Creating new tiles of arbitrary types, supporting drag/drop operations, and encapsulating arbitrary components within tiles are not trivial tasks.

In my opinion, the most significant benefits of using React in this sample were:

  • The ability to use TSX and get full design-time error checking, IntelliSense, and rich debugging for the entire app (including the TSX markup!).
  • The clean state-driven architecture imposed by React (which may take a little getting used to, but tends to pay off later).
  • The ability to encapsulate tiles neatly into single-file components.

The Dynamic Dashboard sample could be used as a starting point for actual dashboard apps. Obvious missing features are:

  • The ability to save and restore dashboard layouts to local storage.
  • Adding state to tiles so they can be customized by users.

To learn more about Wijmo, please visit our home page. To learn more about using Wijmo in React applications, please visit our React page.

View the sample

The post How to Create a Dynamic Dashboard in React appeared first on Wijmo.

How to add HTML5 Report Viewer to a Web App

$
0
0

C1 Web API Report Services enables you to build HTTP services, which can be consumed by a variety of clients for viewing, loading and caching reports, including the Wijmo ReportViewer. These are REST-based API services, which communicated with HTML 5 ReportViewer control to display the report content on the web.

Available as Visual Studio template, C1 Web API enables you to create report services on Visual Studio. Client applications send a request to the report services application to load reports, export reports, and allow user to use parameters in the report. The service supports exporting your reports to PDF, Excel, HTML, RTF, OpenXML, and Image. 

01_diagram

Set up report services for the report viewer

Create a report services application by C1 Web API Project Templates in Visual Studio:

  1. Installed ASP.NET Web API Edition from here.
  2. Select a C1 Web API Application template in Visual Studio New Project dialog:

    02_visualstudiotemplate

  3. The project template wizard shows. Please check Report services and click OK:

    03_projectsettings

  4.  Add reports to this web application.
  • FlexReport or C1Report:
  1.  Copy the report definition file to the application. Please also copy the related database file and update the connect string of the report if necessary.

    04_reportdefinition

  2. Add a FlexReport disk storage in Configure method of Startup. For example:
    app.UseReportProviders().AddFlexReportDiskStorage("Root", System.IO.Path.Combine(System.Web.HttpRuntime.AppDomainAppPath, "ReportsRoot"));
  • Regarding SSRS reports: please register an SSRS report server in Startup:
    app.UseReportProviders().AddSsrsReportHost("ssrs", "http://ssrshost/ReportServer", new System.Net.NetworkCredential("username", "password"));
  • Run the application in VS, or publish it in IIS.
  • Wijmo’s ReportViewer has been launched as a control, and is available with Wijmo Enterprise. You’ll be able to view FlexReports in ReportViewer, and in order to generate a FlexReport—and connect the ReportViewer to the FlexReport— you’ll need GrapeCity’s Ultimate suite. Ultimate includes the code-free standalone report designer, FlexReport Designer, along with a Web API.

    Read more about GrapeCity’s Ultimate suite

    The post How to add HTML5 Report Viewer to a Web App appeared first on Wijmo.

    Rethinking the Periodic Table with Wijmo’s Sunburst

    $
    0
    0

    Designed to ease the process of visualizing hierarchical data, sunburst charts display categorical data “tiers” followed by the data points themselves radiating out from a central point. To put it more simply, sunburst charts portray data as categorized arcs. Conveniently, Wijmo 5 now ships with a Sunburst control that makes it easy to visualize data as a sunburst chart on the web. In this blog, we’ll adapt a .NET demo to display the periodic table of the elements as a sunburst chart on the web using only Wijmo and JavaScript (JS).

    View the New Sunburst Periodic Table

    Get the Sample on GitHub

    Before we go any further, let’s take a look at the finished product. Be sure to keep this in mind while moving through the tutorial so we can visualize the objective we want to reach.

    An animation showcasing the final Periodic Sunburst data visualization's function

    Now that we’ve visualized what we want our final to product to look like and do, let’s talk about why we would even want to do something like this and then how we can make it come to life.

    What’s Wrong with the Periodic Table?

    Hopefully you’ve keyed into the mind of a data visualizer by now and are asking the question I stressed so much a little bit ago: why? There’s already a perfectly good, working periodic table of the elements out there, and many of us have been familiar with it for a good portion of our lives. So why change it?

    As a former biochemist, I can sympathize with anyone who’s trying to learn the periodic table for the first time or trying to relearn it as an adult. As we all know, the traditional structure isn’t exactly the most intuitive. To a seasoned chemist or other basic science professional, the layout of the traditional periodic table makes perfect sense and is, in fact, very useful. To someone simply using it for reference or looking at it for the first time, however, its organization is often a mystery.

    So that’s what’s “wrong” with the traditional periodic table: it was designed for chemists, not teachers or students, or really anyone else for that matter. That’s why Wijmo’s Sunburst can help us here: it’ll let us display elements grouped by their properties in a visually obvious way.

    A traditional periodic table designed for children with color coded groups.

    A traditional periodic table designed for children with color coded groups.

    Building the Periodic Sunburst

    Before we get started, I want to point out that this tutorial doesn’t walk through every single step of the process. Although this is designed to be a complete project tutorial, our focus here is to demonstrate how we can link up datasets with the Wijmo Sunburst chart. If you want to view the complete project, it’s available on GitHub.

    Step 1: Initializing the Project

    As it goes in web development, there will be a near infinite amount of ways to set up this project. There are a number of frameworks, libraries and even programming languages that can be applied to solve this problem.

    That being said, I’m going to use vanilla (pure) JavaScript throughout the tutorial to make this transferable to any other JS-based solution. I also want to point out just how powerful and adaptable the Wijmo Sunburst control is. Look for notes pointing out sections where a framework or library would be useful, and rest assured that another tutorial focusing on building this project with a MVC framework is in the works.

    Next, I’ll talk about the project design considerations and how I approached them, but you can move on if you just want to check out the code.

    Aside from that consideration, there are a few other things to think about when setting up this project:

    1. We’re going to be loading JSON from a file. The easiest pure JS way to do this is by using an XMLHttpRequest (XHR). Since XHRs don’t work on the local file system, we’ll need a new way to test locally.
    2. We’re going to be writing a lot of data handling and access logic as well as view logic. I know, I know, JS isn’t technically object-oriented, but wouldn’t it be better to compartmentalize our code somehow?
    3. Since we want to walkthrough building a production-ready project from start to finish, how can we minify and package our files for production?

    I thought about each of these issues and tried to come up with a solution that would leave the tutorial accessible to everyone while also providing a full-fledged, standalone solution. You can read more about the full details in the project README, but here are my solutions in brief:

    1. If you don’t have a development web server set up, I recommend using Apache. It’s quick, easy, and that’s what I’ll be using for all of my testing, just to allow XHRs to load the JSON data.
    2. I’ve decided to write the logic for this project using JavaScript modules. Specifically, I’m going to use CommonJS module syntax and patterns. Because of this, I’m also using Browserify to package all of the modules into a single JS file for production. Browserify is easiest to use with js and NPM, so I’ll also be using those as dependencies.
    3. Even though I’ll be writing code in vanilla JS, I use a lot of new ES6 syntax. To minify JS files, I’m using babili since it supports ES6.

    So that’s pretty much it for my development dependencies! Again, you don’t have to use any of these, but I just wanted to give an overview of how I’m approaching things.

    Step 2: Setting up the Data Source

    To build out a new visualization of the periodic table, we’ll need data on the elements including their types so that we can correctly categorize them. Ultimately, we want this to be in JSON format so we can easily and natively work with and manipulate the data in JavaScript.

    Below, I’ll walk through the steps of downloading and cleaning the data from scratch, but if you want the final version you can grab it from GitHub.

    • Fortunately for us, Data Explorer offers a free dataset that is almost exactly what we need. The big caveat here is that Data Explorer provides their dataset in XML format with some extra schema information that we don’t need. Before we take care of that, though, let’s download the data.
    • Next we’ll convert the XML data we downloaded to JSON using a free online converter. Once we have the JSON representation of the data, we’ll save it in a file so we can clean things up a bit.
    • Now we have to trim away the excess schema information so we’re left with only a single root JSON entity that holds an array of element entities.
    • Lastly, believe it or not, some of the data provided by Data Explorer is little bit off! We’ll make some small corrections and save our final dataset.

    Step 3: Building the Data Access Layer (DAL) and Data Model

    Now that we have our cleaned-up data accessible to us, we have to build out the logic to load it and parse it. Just as it seems, this will require a two-step process in which we (1) load the JSON data from Step 2 into a JS object and (2) parse out the array of element data into formal Element objects and categorize them into Group and SubGroup objects as well. The second step can be broken down even further, as we have to develop a data model and an adapter to load data into it.

    Let’s start by building a utility to actually pull JSON from the file.

    JsonDataLoader.prototype.getObjectFromJson = function (jsonFilePath, callback) {
        readFileContents(jsonFilePath, function (eventArgs) {
             callback(JSON.parse(this.responseText));
        });
    };
    

    This is the most important function in the data loading module. It takes a file path and a callback function as arguments, and uses the below helper function to load the JSON then returns it as an object:
    function readFileContents(filePath, callback) {
        let reqClient = new XMLHttpRequest();
        reqClient.onload = callback;
        reqClient.open("get", filePath, true);
        reqClient.send();
    }
    

    And that’s it! We can now use these functions by requiring the JsonDataLoader module in any other code and using the getObjectFromJson function. If you want to see the full file contents and more documentation, follow the link up above. That goes for any code we talk about in the rest of the article, too!

    So now that we can load the data from a file, we need a model to store it in. Onto building the data model!

    Before we dive in, let’s conceptualize what we need to build. Ultimately, we want (as the finished product picture showed) a model containing root “group” nodes which contain “subgroup” child nodes which contain elements as terminal nodes. Briefly, that equates to something like this:

    Periodic Sunburst Data Model Schematic

    A schematic representation of the data model necessary for building the Periodic Sunburst

    So how do we enact that structure in our code? It’s probably easiest to just see it in action, so let’s get to it!

    var Element = function (elementJObj) {
        this.atomicNumber = elementJObj.properties['atomic-number']; // this and atomic-weight must be accessed using bracket notation because they have hyphens
        this.atomicWeight = elementJObj.properties['atomic-weight']; // this and atomic-weight must be accessed using bracket notation because they have hyphens
        this.elementName = elementJObj.properties.element;
        this.eleSymbol = elementJObj.properties.symbol; // rename this to eleSymbol since symbol is a reserved keyword in ES6
        this.type = elementJObj.properties.type;
        this.value = 1; // Set a uniform value that can be bound when initializing the chart to get equal arc angles
    };
    

    In Element.js, we just want to build a constructor that can take an element entity right from the JSON object and convert it into something more useful. It’s also important to note the final property setter:
    this.value = 1
    This gives each Element object a property equal to the same numeric value which will be important later for rendering our Sunburst chart.

    var SubGroup = function (subGroupName) {
        this.subGroupName = subGroupName;
        this.elements = [];
        this.characteristics = '';
    };
    

    In SubGroup.js, all that really matters is that we store a name property and set up an empty array that will ultimately hold Element objects. One “bonus” property that we set up here is the characteristics property. Eventually, this will hold a string representation of characteristics that we can display to the user.

    var Group = function (groupName) {
        this.groupName = groupName;
        this.subGroups = [];
    };
    

    Even simpler than the SubGroup module, Group.js simply holds a constructor that takes a name and sets up an empty array for holding SubGroups.

    The data model is all written and assembled now, we just have to load data into it! The last step is to write a data adapter that can take the raw data loaded from JSON and put it into the model we just created.

    As it would be a little overwhelming to post the entire DataSourceAdapter module here, follow the link above to view the documented code on Github. The primary function in this module is

    DataSourceAdapter.prototype.getChartDataSource = function (callback) { ... }
    which loads the element data using our JsonDataLoader utility module, parses it, and returns an array of Group objects.

    I highly recommend taking a look at the module to see exactly how the final data structure is generated, but the important result is that we are given an array of Groups which each contain SubGroups which each contain Elements. This can be directly loaded by our Sunburst chart in the view.

    And with that, we have a working data layer that can interface directly with our Sunburst chart!

    Step 4: Building the View and Displaying the Sunburst Chart

    The first step in displaying our Sunburst Chart in the view is by giving it a DOM host element in index.html:

    <!-- The main container where the Sunburst control is rendered -->
    <div id="periodic-sunburst" class="periodic-sunburst"></div>
    

    This gives us a DOM element to render the chart in, but it doesn’t actually handle any of the rendering. To generate the chart and place it in the element, we’ll initialize the control in the code-behind, contained in app.js:
    DataSourceAdapter.getChartDataSource(function (dataArray) {
    let mySunburst = new wijmo.chart.hierarchical.Sunburst('#periodic-sunburst'); // initialize!
        // Let the Sunburst Chart know we're going to start making changes
        mySunburst.beginUpdate();
        // Set some stylistic properties for the chart
        mySunburst.legend.position = 'None'; // hide the legend
        mySunburst.innerRadius = 0.3; // set up a relatively large space for displaying info
        mySunburst.selectionMode = 'Point';
        mySunburst.dataLabel.position = 'Center'; // center panel labels
        mySunburst.dataLabel.content = '{name}'; // the panel should display its name (derived from bindingName property)
        mySunburst.itemsSource = dataArray; // set the items source to the array generated by the DataSourceAdapter
        mySunburst.binding = 'value'; // bind each item to the constant 'value' property to get equal arc angles for all element panels
        mySunburst.bindingName = ['groupName', 'subGroupName', 'eleSymbol']; // set the property that gives the name we want to display for each chart level
        mySunburst.childItemsPath = ['subGroups', 'elements']; // set the property names that hold the children for each level (remember our data structure is Group.subGroups.elements)
        mySunburst.endUpdate();
    ...
    }
    

    The documented code above details the methods and properties we need to use to set up our Sunburst chart to get the final product we’re looking for. Especially important properties to notice are the itemsSource, binding, bindingName, and childItemsPath properties. These properties load the data we generated and formatted in Step 3, bind the arc sizing property for element panels to the uniform ‘value’ property, give the property names that the chart will look for to display data labels, and provide the property names for the arrays holding children, respectively.

    That alone should be enough to initialize the Sunburst chart and render it with all of the data we formatted into our model. But that’s really only half the job, right? If you think back to the demo we conceptualized earlier, we also want our Sunburst to display information about the selected object in the center. So how do we go about doing this? Just like with everything else, let’s break it down into steps:

    1. Handle click events on the chart (app.js)

        // Set up a function to listen for click events on the Sunburst Chart's parent DOM element
        mySunburst.hostElement.addEventListener('click', function (e) {
            // Perform a hit test to get a clicked panel's name then use it to set up the info panel via the ViewAdapter
            let ht = mySunburst.hitTest(e.pageX, e.pageY);
            myPropTile.showInfoPanel(ViewAdapter.getObjectFromChartName(ht.name, mySunburst.collectionView));
        });
    

    When the chart’s host DOM element is clicked, we’ll use the handy built-in Sunburst method of hitTest() to find out the name of the panel that was clicked. Next, we pass this name and the Sunburst’s collectionView to a function in the ViewAdapter module that maps the name to the proper Group, SubGroup or Element object. Finally, we get an object representation of what was clicked, and can use that to show the properties we’re looking for.

    2. Send the clicked Object to myPropTile and show the properties (lib/view/PropertiesTile.js)
    So what exactly is myPropTile? It’s simply an instance of the PropertiesTile object wrapped around a DOM element. The PropertiesTile module contains an important function, showInfoPanel that initializes and displays the correct property tile.

    Once the PropertiesTile is instantiated and hooked up to the DOM events we need to listen on, we’re done! There are quite a few intricacies around how the PropertiesTile works, and I encourage you to check them out in the source code.


    That about does it for all of the core functionality of our data visualization! As you’ll find in the GitHub repo, there are some additional steps taken that aren’t covered in-depth here. These include everything from creating a shim for browser compatibility to theme generation with CSS. I encourage you to take a look at the source code holistically to get a better understanding of the overall project.

    If you have any questions about this project or the Wijmo Sunburst Chart in general, don’t hesitate to let me know in the comments or by sending me an email. I’ll be actively and openly responding to all feedback, so don’t be shy!

    Thanks so much for reading, and I hope you enjoy!

    Download the source code for this sample: v0.1.1 Release (zip / tar)

    View the New Sunburst Periodic Table

    The post Rethinking the Periodic Table with Wijmo’s Sunburst appeared first on Wijmo.


    How to export selected rows of FlexGrid to a PDF file

    $
    0
    0

    Recently, I received an inquiry about exporting selected data from a FlexGrid to a PDF document. I found this interesting. While we often brag about the amount of data the FlexGrid can hold, in this case,the user needed only a portion of the data.

    Wijmo supports exporting data to a PDF Document, but the wijmo.grid.pdf module does not support the ability to omit rows of the FlexGrid when saved to the PDF file. The saving process simply copies the data from the control in the browser to the PDF document. Only minimal changes can happen here—like changing the font or background color.

    Currently, the wijmo.grid.pdf module is based on PDFKit API, so to get the desired functionality, we would need to create our own API for a PDF generator specifically tailored to the FlexGrid. Since our specialty resides with UI controls, creating a new PDF API was out of the question.  However, it is still possible to get the desired outcome.

    The solution is simple: use two FlexGrids.

    One FlexGrid contains all the data, and the other contains the selected data to export. Having the second FlexGrid appear in the application defeats the purpose, so we can hide the FlexGrid by setting the ‘display’ property to ‘none’ in markup. In pure JS, the HTML should appear something like this:

    <div id="theGrid" style="width:100%;height:350px;"></div>
    <div id="hiddenGrid" style="display:none;"></div>
    

    To handle selection, I used a ‘boolean’ field to in my data objects named “exportRow”. There are other ways to do this, but this approach is the simplest. Rows with ‘checked’ checkboxes in the “Export Row” column are copied to the hidden FlexGrid just before the data is exported.

    Here is the Javascript code:

    function exportSelectedRowsToPDF() {
    // copy selected rows of #theGrid to #hiddenGrid
    if (hidden == null) {
    hidden = new wijmo.grid.FlexGrid('#hiddenGrid');
    }
    var grid_cv = grid.itemsSource;
    var new_cv = new wijmo.collections.CollectionView(grid_cv);
    for (var i = 0; i < new_cv.items.length; i++) {
    if (!new_cv.items.exportRow) {
    new_cv.removeAt(i);
    i--;
    }
    }
    hidden.itemsSource = new_cv;
    //export
    wijmo.grid.pdf.FlexGridPdfConverter.export(hidden, 'FlexGrid.pdf', {
    scaleMode: wijmo.grid.pdf.ScaleMode.PageWidth,
    exportMode: wijmo.grid.pdf.ExportMode.All,
    maxPages: 10,
    styles: {
    cellStyle: {
    backgroundColor: '#ffffff',
    borderColor: '#c6c6c6'
    },
    headerCellStyle: {
    backgroundColor: '#eaeaea'
    }
    },
    documentOptions: {
    info: {
    title: 'Sample'
    }
    }
    });
    }
    

    The post How to export selected rows of FlexGrid to a PDF file appeared first on Wijmo.

    Extend Microsoft Dynamics 365 with Wijmo 5 Controls

    $
    0
    0

    Microsoft Dynamics 365, a popular enterprise business solution designed to manage business processes, has a plethora of features that fulfill most business needs. But because every business is different, each enterprise generally requires customization. Fortunately, the customizations are straightforward, and can be done through plugins, actions, and web resources.

    If you’d like to watch a video for this process, skip to the bottom.

    In this blog, we’ll look at using web resources to extend Microsoft Dynamics 365 to create a great user experience using client-side technologies like JavaScript and HTML5. Specifically, we’ll create an account dashboard.

    Dashboard01

    Since UI and UX are where Wijmo 5’s JavaScript controls really shine, and you can use them in Dynamics 365 to add functionality, improve the style and create a truly superb client relationship management system.

    Here are a few things we can do with Wijmo 5 and Dynamics 365:

    1. Display entity records in FlexGrid and perform Excel-like filtering, sorting, and grouping and display hierarchical data.
    2. Represent data in pie chart, bar chart, radar or a linear/radial/bullet graph
    3. Analyze and drill down data using Wijmo OLAP control
    4. Use custom input elements like calendar, autocomplete, multi-select, and drop-down

    Let’s get started.

    Create an Account Dashboard Using a JavaScript Grid and Chart

    First we’ll create a basic accounts dashboard using FlexGrid and FlexChart. As always, we’ll start with a list of requirements. The dashboard needs to:

    • Fetch data from an account entity and display it in the FlexGrid. Features include:
      • Sorting
      • Grouping
      • Filtering
    • Represent data from account records in a pie chart so we can see a pie graph of countries and their accounts
    • Users should be able to update records on FlexGrid, which should update the entity record in the CRM.

    Creating the dashboard is easy. First we’ll write the HTML and JavaScript code that uploads data to the CRM as web resources. In our example, we’re using AngularJS as our framework, but Wijmo’s controls allow you to easily substitute a chosen framework with Pure JS, React, Angular v2, or VueJS.

    Step 1: Creating the HTML Page

     

    Since our HTML page is going to need a FlexGrid and FlexChart to display the data. We are going to add them First and then move to add the JS code later. We have also added FlexGrid filter directive and Group Panel to provide Filtering and Grouping features.

    AccountDetailsWijmoView.html

    <html ng-app="crmApp">
    <head>
        <title>Using Wijmo with MSCRM </title>
        <script src="ClientGlobalContext.js.aspx"></script>
        <!-- AngularJS files  -->
        <script src="gc_angular.min.js" type="text/javascript"></script>
        <script src="gc_angularresource.min.js"></script>
        <!--  Other Framework files & Bootstrap  -->
        <script src="gc_jquery1.9.1.js"></script>
        <link rel="stylesheet" href="gc_bootstrap.min.css">
        <script src="gc_fontawesome.js"></script>
        <script src="gc_bootstrap.min.js"></script>
        <!-- Wijmo 5 Dependencies -->
        <link href="gc_wijmo.min.css" rel="stylesheet" />
        <script src="gc_wijmo.min.js"></script>
        <script src="gc_wijmo.chart.min.js"></script>
        <script src="gc_wijmo.grid.min.js"></script>
        <script src="gc_wijmo.input.min.js"></script>
        <script src="gc_wijmo.grid.filter.min.js" type="text/javascript"></script>
        <script src="gc_wijmo.grid.grouppanel.min.js" type="text/javascript"></script>
        <script src="gc_wijmo.angular.min.js"></script>
        <!-- Controller file -->
        <script src="gc_AccountDetailsController.js" type="text/javascript"></script>
    </head>
    <body onload="window.resizeTo(1400,800)" ng-controller="AppController" style="word-wrap: break-word;">
        <div class="container-fluid">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">
                        <i class="fa fa-bookmark" aria-hidden="true"></i> CRM Accounts DashBoard
                    </h3>
                </div>
                <div class="panel-body">
                    <div class="row">
                        <div class="col-xs-8 col-md-8">
                            <!-- Group Panel to let users drag Columns and group data based on them -->
                            <wj-group-panel grid="flex" placeholder="Drag columns here to create groups." style="height:60px;width:800px"></wj-group-panel>
                             <!-- This is our FlexGrid used to Populate data from CRM -->
                            <wj-flex-grid control="flex" items-source="data" allow-add-new="true" style="height:400px;width:800px;margin-top:10px">
                                <wj-flex-grid-filter></wj-flex-grid-filter>
                                <wj-flex-grid-column header="Account Name" binding="name"></wj-flex-grid-column>
                                <wj-flex-grid-column header="Street Address" binding="address1_line1"></wj-flex-grid-column>
                                <wj-flex-grid-column header="City" binding="address1_city"></wj-flex-grid-column>
                                <wj-flex-grid-column header="Postal Code" binding="address1_postalcode"></wj-flex-grid-column>
                                <wj-flex-grid-column header="Country" binding="address1_country"></wj-flex-grid-column>
                                <wj-flex-grid-column header="Call Allowed" binding="donotphone"></wj-flex-grid-column>
                            </wj-flex-grid>
                        </div>
                        <div class="col-xs-4 col-md-4">
                            <!-- This is our FlexPie used to show Countries of Accounts -->
                            <wj-flex-pie items-source="countriesofAccountCollection" binding="value" binding-name="name" selection-mode="Point" header="Countries of Account" selected-item-offset=0.10>
                            </wj-flex-pie>
                        </div>
                    </div>
                    <a style="margin-top:10px" class="btn btn-success btn-lg btn-block" ng-click="UpdateRecords()" ng-disabled="data.itemsEdited.length==0" role="button"><i class="fa fa-upload" aria-hidden="true"></i> Update ({{data.itemsEdited.length}} records need to be updated) </a>
                </div>
            </div>
        </div>
    </body>
    </html>
    

    Step 2: Add the JavaScript code and Perform Read and Write Operations on Accounts Entity

    We’re using Dynamic CRM’s Web API to read and write data on Accounts Entity. Data fetched from Web API will be displayed in the FlexGrid, and any edits in the FlexGrid will be updated back to Dynamics 365. We’re also creating a function to analyze data and show the resulting data in a FlexChart.

    AccountDetailsController.js

    // JavaScript source code
    // JavaScript source code
    var CrmApp = angular.module('crmApp', ['wj']);
    // Data Service to make an WebAPI call to CRM
    CrmApp.service('DataService', function ($q) {
        this.retrieveRecords = function () {
            return $q(function (resolve, reject) {
                var clientURL = Xrm.Page.context.getClientUrl();
                var req = new XMLHttpRequest()
                var query = "/api/data/v8.0/accounts?$select=name,address1_country,address1_composite,address1_city,address1_postalcode,donotphone,paymenttermscode&$top=100";
                req.open("GET", encodeURI(clientURL + query), true);
                req.setRequestHeader("Accept", "application/json");
                req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
                req.setRequestHeader("OData-MaxVersion", "4.0");
                req.setRequestHeader("OData-Version", "4.0");
                req.onreadystatechange = function () {
                    if (this.readyState == 4) {
                        req.onreadystatechange = null;
                        if (this.status == 200) {
                            var data = JSON.parse(this.response);
                            if (data && data.value) {
                                resolve(data.value);
                            }
                        }
                        else {
                            var error = JSON.parse(this.response).error;
                            reject(error);
                        }
                    }
                };
                req.send(null);
            });
        }
        // Web Api call to Update Accounts
        this.updateRecord = function (accountId, record) {
            return $q(function (resolve, reject) {
                var clientURL = Xrm.Page.context.getClientUrl();
                var req = new XMLHttpRequest()
                req.open("PATCH", clientURL + "/api/data/v8.0/accounts(" + accountId + ")", true);
                req.setRequestHeader("Accept", "application/json");
                req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
                req.setRequestHeader("OData-MaxVersion", "4.0");
                req.setRequestHeader("OData-Version", "4.0");
                req.onreadystatechange = function () {
                    if (this.readyState == 4) {
                        req.onreadystatechange = null;
                        if (this.status == 204) {
                            resolve("ok");
                        }
                        else {
                            var error = JSON.parse(this.response).error;
                            reject(error);
                        }
                    }
                };
                req.send(JSON.stringify(record));
            });
        }
    });
    /// create a controller for the page, and inject our DynamicsCRMService into it
    CrmApp.controller('AppController', function ($scope, DataService, $q, $window, $timeout) {
        // Get Data for Accounts
        var rawData = [];
        //Get Data for Account Records
        $scope.GetData = function () {
            var promise = DataService.retrieveRecords();
            promise.then(function (response) {
                rawData = response;
                $scope.data = new wijmo.collections.CollectionView(response);
                $scope.data.trackChanges = true;
                $scope.AnalyzeAccounts();
            }, function (reason) {
                alert(reason)
            });
        }
        // Create Data for Country Analysis and Show in Pie Chart
        $scope.AnalyzeAccounts = function () {
            var countriesofAccount = [];
            var unsortedCountriesofAccount = rawData.reduce(function (sums, entry) {
                sums[entry.address1_country] = (sums[entry.address1_country] || 0) + 1;
                return sums;
            }, {});
            angular.forEach(unsortedCountriesofAccount, function (value, key) {
                var countriesData = {
                    name: key,
                    value: value
                };
                countriesofAccount.push(countriesData);
            })
            $scope.countriesofAccountCollection = new wijmo.collections.CollectionView(countriesofAccount);
        }
        // Udpate Account Edits to CRM
        $scope.UpdateRecords = function () {
            var defer = $q.defer();
            var promises = [];
            var edittedItems = $scope.data.itemsEdited;
            angular.forEach(edittedItems, function (item) {
                var account = {
                    name: item.name,
                    address1_line1: item.address1_line1,
                    address1_country: item.address1_country,
                    address1_city: item.address1_city,
                    address1_postalcode: item.address1_postalcode,
                    donotphone: item.donotphone,
                    paymenttermscode: item.paymenttermscode
                };
                promises.push(DataService.updateRecord(item.accountid, account));
            })
            $q.all(promises).then($scope.GetData());
        }
        $scope.GetData();
    });
    

    This is all the code we need to create our Account Dashboard with Wijmo 5
    controls!

    Note: we need to provide relative URLs for our dependencies in the HTML page, as they also need to be uploaded as Web Resources. Uploading the dependencies is a one-time process, and once done, we can re-use the dependencies in other Web Resources as well.

    Now we’ll look into the second half of the process: deploying the code to Dynamics 365. Once we publish the files to the CRM, our Account Dashboard will be nearly complete.

    Step 3: Deploying Code & Dependencies to CRM

    Once our JavaScript and HTML5 code is ready, we’ll publish them to Dynamics 365 with the required dependencies (Wijmo, Angular, JQuery etc.). Please note that name and relative path of dependencies must match with the paths that have been specified in AccountDetailsWijmoView.html.

    The best practice is to create a new solution and upload the files there. (You can read about how to create a new solution here.)

    We’ve already created a new solution and have uploaded the mentioned files as Web Resources. Here are the steps:

    3.1 Navigate to the Settings Page

    02-031-magnify

    3.2 Select the Solution to Upload Resources

    02-032-Resized

    3.3 Upload the Files as Web Resources.

    If you would like to know how to upload Web Resources, then please visit here.

    02-033-Callouts

    Step 4: The Entry Point

    Take note of the URL field of AccountDetailsWijmoView.html. This serves as the entry point for the Account Dashboard.
    In our sample, the entry point is: https://demojs.crm8.dynamics.com//WebResources/gc_AccountDetailsWijmoView.html

    02-034-Resized

    Step 5: Adding a Ribbon Button using Ribbon Workbench & Ribbon Set Up

    Let’s add an Analyze Ribbon Button on the accounts home page. When we click it, we’ll see the Account Dashboard. It’s recommended to use the Ribbon Workbench to add ribbon buttons and associate commands with them. (If we wanted, we could open the entry point URL directly in our Dynamics 365 instance, and it would work just fine.)

    5.1 Set up Ribbon Button

    05-01-resized

    5.2 Set up Ribbon Button Command

    Here are the property names and corresponding values:

    Property

    Value

    Address

    /WebResources/gc_AccountDetailsWijmoView.html?

    PassParameters

    False

    Window Mode

    Modal Dialog

    Window Parameters

    width=1400;height=800;resizable=yes

    05-011-version2

    Step 6: Open the Accounts Dashboard

    Navigate to Accounts Home Page and click on the Analyze Accounts button. It should open the Account Dashboard as a Modal Dialog.

    06-resized

    Account Dashboard in Action: Group, Sort, Filter, Edit Data

    Lastly, we’ll look at the interactivity that makes FlexGrid such a powerful grid tool.

    Grouping: Drag any column to the section that reads “Drag columns here to create groups” and your groups will be created. We can create multiple groups as well.

    Filtering: Each column has a filter icon built-in. Click the icon and we can filter based on value or conditions.

    Sorting: Clicking on any of the columns sorts the data based on that column.

    Data Operations: Try editing any of the cells. Once the edit is complete, click on update to update records in the CRM. The data refreshes, updating FlexGrid and pie chart automatically.

    That’s all, folks! If you need more information about Wijmo 5 controls, check out our Sample Explorer and Docs. You can also download a free trial of Wijmo 5.

    Project Files:

    • Source Code Project: This project contains all the source files for Account Dashboard
    • MSCRM Solution: We also created a MSCRM solution which can be directly imported into your CRM Instance and you can see the Dashboard in action at your end.

    Watch the Full Video

    Try Wijmo 5 now

    The post Extend Microsoft Dynamics 365 with Wijmo 5 Controls appeared first on Wijmo.

    Create a Quick-Start Application with Angular and Wijmo

    $
    0
    0

    This blog was originally published on February 14, 2017 for Wijmo Japan.

    Angular not only extends framework features, but also has ability to improve the development efficiency. You can create an Angular application very easily by using a command line tool called Angular CLI. Since Wijmo has first-class Angular support, you can use Wijmo’s advanced UI components meant for enterprises—such as grid, input, and chart—with Angular’s standard methodology.

    This article walks through creating an Angular application using Angular CLI and Wijmo. The app manages data in a grid, and you can use it as a sample or a tutorial while developing Angular applications.

    In this article, we’re using the following library versions:

    • Angular 2.4.0
    • Angular CLI 1.0.0-beta.31

    01-image

    Creating an Angular Application

    If you haven’t installed Angular CLI, execute the following command to install the Angular CLI package globally.

    npm install -g @angular/cli

    Execute the ng new command to create an Angular application. After a while, the application source file and configuration file are generated automatically and the package gets installed.

    ng new quickstart

    Go to the application project folder and execute the ng serve command to run the application on the development server. The application can be displayed at http://localhost:4200, and the changes get reflected automatically when you change the source file.

    cd quickstart
    ng serve
    

    Add the Wijmo Component

    Execute the following command to install Wijmo package in the project. If you’re using the full version of Wijmo, refer to the NpmImages folder of the version.

    # In case of evaluation version
    npm install --save http://prerelease.componentone.com/wijmo5/npm-images/C1Wijmo-Enterprise-Eval-AMD-5.20163.254.tgz
    # In case of full version
    npm install --save xxx/NpmImages/wijmo-amd-min/
    

    Fetch the wijmo.min.css file from CDN or Wijmo full version and add it to the src folder of the project.

    Add wijmo.min.css file in the angular-cli.json file.

    {
      "apps": [
        {
          "styles": [
            "styles.css",
            "wijmo.min.css"
          ],
        }
      ],
    }
    

    Import the WjGridModule module in the src/app/app.modules.ts file.

    import { WjGridModule } from 'wijmo/wijmo.angular2.grid';
    @NgModule({
     :
      imports: [
     :
        WjGridModule
      ]
    })
    

    Add FlexGrid component in the src/app/app.component.html file.

    <wj-flex-grid [itemsSource]="data"></wj-flex-grid>

    Create the data to be displayed in the grid in the src/app/app.component.ts file.

    export class AppComponent {
      data: any;
      constructor() {
        this.data = [
          { id: 1, name: '果汁100%レモン', price: 100 },
          { id: 2, name: 'コーヒーマイルド', price: 100 },
          { id: 3, name: 'ピリピリビール', price: 200 },
          { id: 4, name: 'ホワイトソルト', price: 150 },
          { id: 5, name: 'だしこんぶ', price: 200 }
        ];
      }
    }
    

    These steps create a simple quick start application. Execute the ng serve command and connect to http://localhost:4200 to observe the FlexGrid component in the Angular application.

    02-image

    The post Create a Quick-Start Application with Angular and Wijmo appeared first on Wijmo.

    Angular Quick Start: Data Binding with Wijmo Controls

    $
    0
    0

    This blog was originally published on February 22, 2017 for Wijmo Japan.

    This article introduces how to bind data with Wijmo InputNumber (numeric input) component based on the Angular application we created in the previous article.

    Wijmo supports all three types of Angular data binding:

    1. Property binding: Value set in the parent component (“Main page”, in this case) is passed to the child component (InputNumber, in this case). This is also known as one-way data binding.
    2. Two-way data binding: Value set in the parent component is passed to the child component, and simultaneously, the value set in the child component is passed to the parent component. Hence, values of the parent and child components are always in sync.
    3. Event binding: Handles the event when a specific operation is performed in the child component.

    015-image2

    Adding InputNumber component

    Import the WjInputModule module in the src/app/app.modules.ts file.

    import { WjInputModule } from 'wijmo/wijmo.angular2.input';
    @NgModule({
     :
      imports: [
     :
        WjInputModule
      ]
    })
    

    Add the InputNumber component in the src/app/app.component.html file.

    <wj-input-number></wj-input-number>

    Property binding

    Bind the data with the step property of InputNumber, in the src/app/app.component.html file.

    <wj-input-number [step]="step"></wj-input-number>

    Set the properties to be bound and their values in src/app/app.component.ts file.

    export class AppComponent {
      step: number;
      constructor() {
        this.step = 100;
      }
    }
    

    When you run the application, you can see that the step property is set, and the value can be changed in increments of 100 by clicking the + or – button.

    01-image2

    Two-way data binding

    Set two-way data binding on the “text” property of InputNumber in the src/app/app.component.html file. In addition, add a text box and set the two-way binding on the same as well.

     <wj-input-number ... [(text)]="text"></wj-input-number> 
    <br><input [(ngModel)]="text"> 

    Set the properties to be bound and their values in the src/app/app.component.ts file.

    export class AppComponent {
      text: string;
      constructor() {
        this.text = '0';
      }
    }
    

    Now, run the application and change the value in InputNumber or text box to observe that the other value also gets changed at the same time.

    02-image2

    Event binding

    Define the handling of valueChanged event of InputNumber and determine the value whenever it changes.

    In the src/app/app.component.ts file, define the onValueChanged method that handles the event and the negative property that determines whether a value is negative or not. Also, import the wijmo/wijmo.input module for referencing the InputNumber class and its members.

    import * as wjcInput from 'wijmo/wijmo.input';
    export class AppComponent {
      negative: boolean;
      constructor() {
        this.negative = false;
      }
      onValueChanged(s: wjcInput.InputNumber) {
        this.negative = s.value < 0;
      }
    }
    

     When you import the wijmo/wijmo.input module, type definition file of the module is also imported, which enables IntelliSense while using the classes and members of that module.

    In the src/app/app.component.html file, set the event binding of valueChanged. Once you set the event, pass the component variable inputNumber to argument of the event handler method. In addition, add a string showing that the value entered is negative.

     <wj-input-number ... #inputNumber (valueChanged)="onValueChanged(inputNumber)"></wj-input-number> 
    <p *ngIf="negative">Value is negative.</p> 

     Although it's omitted here, you can even pass the event variable $event to argument of the event handler method.

    Run the application and enter a negative number to get the message “Value is negative.”

    03-image2

    The post Angular Quick Start: Data Binding with Wijmo Controls appeared first on Wijmo.

    Create a Web Application for Performing CRUD Operations Using JavaScript and Web API

    $
    0
    0

    This post was originally published on June 6, 2016 for Wijmo Japan

    This blog introduces you to performing CRUD operations on a database using JavaScript and Web API.

    AngularWebAPI1A

    Here, we create the view using JavaScript and HTML. We also use Wijmo’s FlexGrid (a datagrid control) and CollectionView (a utility class for managing changed data) for better data handling and productivity.

    The server is developed using the following frameworks and products.

    • ASP.NET Web API
    • SQL Server
    • Entity Framework
    • Visual Studio 2015

    The Web API provides CRUD operations and processes the database by sending HTTP requests from JavaScript.

    Here, CRUD refers to the four major database operations i.e., Create, Read, Update and Delete.

    We are using JSON data, which can be easily handled with JavaScript, for transferring data between the view and the server.

    AngularWebAPI1A

    1. Create Web API application

    First, create a Web API application that provides CRUD operations for the database.
    Create a new ASP.NET Web Application project in Visual Studio.

    AngularWebAPI2

    Use an “Empty” template when setting up the project.

    AngularWebAPI3

    Add the App_Data folder to the project.

    AngularWebAPI4

    Add a SQL Server database file in the App_Data folder. Here, we are using the NORTHWND.MDF file which is provided in the trial version of ComponentOne Studio.

    AngularWebAPI5

    Add an ADO.NET Entity Data Model to the project.

    AngularWebAPI6

    On the “Choose Model Contents” page of Entity Data Model Wizard, select “EF Designer from database“.

    AngularWebAPI7

    On the “Choose Your Data Connection” page, confirm that the MDF file is automatically selected.

    AngularWebAPI8

    Then, on the “Choose Your Version” page, select version of Entity Framework that you want to use.

    AngularWebAPI9

    On the “Choose Your Database Objects and Settings” page, select the database. Here, we have only selected the Products table.

    AngularWebAPI10

    This creates a model and the designer gets displayed.

    AngularWebAPI11

    In order to reflect the model settings, close the designer and build the project.

    Add scaffolded items to the project.

    AngularWebAPI12

    In the “Add Scaffold” dialog, select the “Web API 2 Controller with actions, using Entity Framework” option.

    AngularWebAPI13

    In the “Add Controller” dialog, select the Model class and Data context class from the dropdown.

    AngularWebAPI14

    With this, we have a Web API that provides CRUD operations.

    Details on how to create a Web application using ASP.NET Web API and the Entity Framework are also introduced in the tutorial provided on the official ASP.NET website.
    Using Web API 2 with Entity Framework 6 | The ASP.NET Site

    2. Create a View

    Next, create a view in which the end user can perform database operations.

    Here, we are creating a view on the index page of the Web API project.
    Add an HTML page to the Web API project and change the file name to “index.html“.

    AngularWebAPI15

    Add Wijmo references in the <head> section of index.html.

    <!-- Wijmo -->
    <link rel="stylesheet" href="http://cdn.wijmo.com/5.latest/styles/wijmo.min.css" />
    <script src="http://cdn.wijmo.com/5.latest/controls/wijmo.min.js"></script>
    <script src="http://cdn.wijmo.com/5.latest/controls/wijmo.grid.min.js"></script>

    In the <body> section of index.html, add an element to host the update button and the FlexGrid control.

    <button onclick="update()">Update</button>
    <div id="flexGrid" style="height: 300px;"></div>
    

    At the end of the <body> section of index.html, add the following JavaScript code to generate CollectionView and the FlexGrid control.

    <script>
    var cv = new wijmo.collections.CollectionView();
    var flexGrid = new wijmo.grid.FlexGrid('#flexGrid');
    flexGrid.itemsSource = cv;
    </script>
    

    When you run the project, an empty FlexGrid control and the “Update” button will appear on the index page.

    AngularWebAPI16

    3. Populate data

    Next, load data from the database and populate it in the FlexGrid.

    There are different methods used to call the Web API (to send an HTTP request) such as jQuery’s ajax function or XMLHttpRequest, but here, we are using Wijmo’s wijmo.httpRequest method. This method allows you to send HTTP requests by using much simpler code than XMLHttpRequest, even if you are not using jQuery.

    Add the following JavaScript code to send a GET request to the Web API. When the request is successful, it converts the loaded JSON data to a JavaScript array object and sets it to the CollectionView.

    wijmo.httpRequest('/api/Products', {
      success: function (xhr) {
        cv.sourceCollection = JSON.parse(xhr.response);
      }
    });
    

    The URL and HTTP methods of the Web API are mentioned in the comments of the automatically generated controller (ProductsController.cs).

    Run the project to populate the data in the FlexGrid control.

    AngularWebAPI17

    4. UPDATE

    Next, update the database with the data edited in FlexGrid.

    Here, we are using a batch update (where multiple edits are updated in the database in one go) instead of the normal update mode (where the database is updated every time a data record is edited).

    In order to perform a batch update, it is necessary to keep track of data that is changed and manage a list of changes. Since the CollectionView automatically handles such operations, there is no need to write complex code to perform the batch update.

    The following JavaScript code enables tracking of the changed data in CollectionView. It gets a list of updated data (CollectionView.itemsEdited property) and sends a PUT request to the Web API. In the PUT request, specify the ID of the updated data in the URL and data to be sent in the data.

    cv.trackChanges = true;
    function update() {
      for (var i = 0; i < cv.itemsEdited.length; i++) {
        wijmo.httpRequest('/api/Products/' + cv.itemsEdited.ProductID, {
          method: 'PUT',
          data: cv.itemsEdited
        });
      }
    }
    

    As only one data set can be updated at a time in the Web API created by this method, the Web API is called as many times as the number of updated data items. If we compare it with the normal update, though the number of calls to the Web API remains the same, the update can be performed at any point of time which is an advantage over the batch update.

    Run the project, edit multiple data records, and press the Update button. When you reload the page, you can see the updated data in the database.

    AngularWebAPI18

    5. CREATE

    Next, reflect the data added to the FlexGrid to the database.

    The following JavaScript code enables rows to be added to FlexGrid. Then, it gets a list of added data (CollectionView.itemsAdded property) and sends a POST request to the Web API. In the POST request, specify the added data in the data parameter.

    flexGrid.allowAddNew = true;
    function update()
      :
      for (var i = 0; i < cv.itemsAdded.length; i++) {
        wijmo.httpRequest('/api/Products/', {
          method: 'POST',
          data: cv.itemsAdded
        });
      }
    }
    

    A new row appears at the bottom of FlexGrid, and when you input in a cell, a new data record is added.

    AngularWebAPI19

    Run the project, add multiple data records, and press the Update button. When you reload the page, you can see the added data records in the database.

    AngularWebAPI20

    6. DELETE

    Next, reflect the data deleted from FlexGrid to the database.

    The following JavaScript code enables rows to be deleted from FlexGrid. Then, it gets a list of the deleted data (CollectionView.itemsRemoved property), and sends a DELETE request to the Web API. In the DELETE request, specify the ID of the deleted data in the URL.

    flexGrid.allowDelete = true;
    function update()
      :
      for (var i = 0; i < cv.itemsRemoved.length; i++) {
        wijmo.httpRequest('/api/Products/' + cv.itemsRemoved.ProductID, {
          method: 'DELETE'
        });
      }
    }
    

    In FlexGrid, you can easily delete a row by selecting it and pressing the Delete key. It is also possible to select multiple rows and delete them at once.

    Run the project, delete the data added in Step #5, and press the Update button. When you reload the page, you can see that those data records have been deleted from the database.

    Please note that it is not possible to delete the existing data in NORTHWND.MDF database because it has a relationship with other tables as well.

    AngularWebAPI21

    With the above implementation, we executed the database CRUD operations in a Web application that uses JavaScript and Web API.

    Download Wijmo 5

    The post Create a Web Application for Performing CRUD Operations Using JavaScript and Web API appeared first on Wijmo.

    Viewing all 93 articles
    Browse latest View live