Report Viewer  A Creative Component Demo


What Is It?

The Report Viewer allows user's to render entire grids & graphics as a single report, by simply dragging & dropping icons into a view area.

  • While viewing, keep in-mind this application is meant for larger screens & NOT phones.

Why Do It?

Many people focus on using individual technologies, and as such, their problem-solving is tied to that single technology.    However, I feel it is important to understand not only what individual technologies can do, but how to bring multiple technologies together in ways that solve problems creatively.

Technologies Used

  • C#
  • ASP.NET MVC
  • Web API
  • JavaScript
  • jQuery
  • jQuery UI
  • Bootstrap
  • Require JS
  • Deferreds

How Does It Work?

The idea is to use Deferreds to create & manage a custom life-cycle for any report.    The custom life-cycle would (then) utilize RequireJS within the Deferred's to bring-in, databind & render assets on-demand using a single method-call.

Simple to use...

var options = { ... };
var report = new SampleReport(options);

report.gather(); //<-- Simply call GATHER
                                

Life Cycle

The life-cycle breaks-down as follows:

  • BIRTH
    • Gather  - connects a series of DFD's into a single promise
    • Require  - collects-up all asset DEPENDENCIES
    • Load  - collects-up all the DATA
    • Render  - initializes the HTML ASSETS
    • DataBind  - binds loaded data to the HTML assets
  • LIFE
    • Refresh  - reloads, re-renders & re-binds all HTML assets
  • DEATH
    • Destroy  - can be used to delete & clear JavaScript variables

Yet, sensical in construction...

// This is merely a portion of the overall class (itself)
// I purposely did NOT minimize the report JavaScript in case folks want to look at it.
function SampleReport(options) {

	// BIRTH
	this.gather = function () {

		var dfd = $.Deferred(function (dfd) {

                        // GATHER connects a series of DFD's into a single promise
			$.when(dfd.then(that.require)
				.then(that.load)
				.then(that.render)
				.then(that.databind))
				.then(function (args) {
					// SUCCESS
				}, function (args) {
					// FAILED
				});
		});

		dfd.resolve();
	};
	this.require = function () {

		var dfd = $.Deferred(function (dfd) {

                        // REQUIRE collects-up all asset DEPENDENCIES
			try {
				var dependencies = ['lib.kendoui/kendo.all.min'];
				require(dependencies, function () {
					dfd.resolve();
				});
			}
			catch (ex) {
				dfd.reject();
			};
		});

		return dfd.promise();
	};
	this.load = function () {

		var dfd = $.Deferred(function (dfd) {

                        // LOAD collects-up all the DATA
			try {

				var chart = on.load.chart(); //<-- Normal AJAX call
				chart.done(function (data, status, xhr) {
					// Success
					that.data.chart.items = data.items;
					dfd.resolve();
				});
				chart.fail(function (xhr, settings, thrownError) {
					// Error
					that.data.chart.items = [];
					dfd.reject();
				});
			}
			catch (ex) {
				dfd.reject();
			};
		});

		return dfd.promise();
	};
	this.render = function (data) {

		var dfd = $.Deferred(function (dfd) {

                        // RENDER initializes the HTML ASSETS
			try {
				var templates = {
					chart: 'template goes here'
				};

				// APPLY Templates
				var $chart = $(templates.chart.format(dictionary.templateIds.controls.chart));
				var $addons = $(templates.addons.format(dictionary.templateIds.controls.addons));
				var $grid = $(templates.grid.format(dictionary.templateIds.controls.grid));

				// APPEND Controls
				dictionary.elements.parent.chart.append($chart);
				dictionary.elements.parent.addons.append($addons);
				dictionary.elements.parent.grid.append($grid);

				dictionary.elements.controls.chart = $(dictionary.selectors.controls.chart, dictionary.elements.parent.chart);
				dictionary.elements.controls.addons = $(dictionary.selectors.controls.addons, dictionary.elements.parent.addons);
				dictionary.elements.controls.grid = $(dictionary.selectors.controls.grid, dictionary.elements.parent.grid);

				dfd.resolve();
			}
			catch (ex) {
				dfd.reject();
			};
		});

		return dfd.promise();
	};
	this.databind = function () {

		var dfd = $.Deferred(function (dfd) {

                        // DATABIND binds loaded data to the HTML assets
			try {
				// CHART
				var series = [];
				$.each(that.data.chart.items, function (i, item) {
					var instance = { x: item.xAxis, y: item.yAxis, size: item.size, category: item.text }
					series.push(instance);
				});

				dictionary.elements.controls.chart.kendoChart({ ... });

				// GRID
				dictionary.elements.controls.grid.kendoGrid({ ... });


				dfd.resolve();
			}
			catch (ex) {
				dfd.reject();
			};
		});

		return dfd.promise();
	};

	// LIFE
	this.refresh = function () {

		var dfd = $.Deferred(function (dfd) {

                        // REFRESH reloads, re-renders & re-binds all HTML assets
			$.when(dfd.then(that.load)
				.then(that.render)
				.then(that.databind))
				.then(function (args) {
					// SUCCESS
				}, function (args) {
					// FAILED
				});
		});

		dfd.resolve();
	};

	// DEATH
	this.destroy = function () {

		var dfd = $.Deferred(function (dfd) {

                        // DESTROY can be used to delete & clear JavaScript variables
			try {
				dfd.resolve();
			}
			catch (ex) {
				dfd.reject();
			};
		});

		return dfd.promise();
	};
};