Drag and Drop in Wijsuperpanel

The wijsuperpanel widget allows us to add elements to it and replace the browsers scrollbars with it’s own scrollbars. You can read more about the wijsuperpanel here. Wouldn’t it be good if we could drag and drop elements from and to the wijsuperpanel.

In this article I’m going to explain how to do just that using jQueryUI’s draggable and droppable functionalities.

Making elements draggable and droppable

First of all, lets add some div elements to the wijsuperpanel.

Div 1
Div 2
Div 3
Div 4
Div 5
Div 6
Div 7

To enable draggability or droppability of the div elements, we just need to set the elements as draggable and the container as droppable in the following way:

$(".elements div").draggable();
$(".element").droppable();

We’re going to drag elements from the wijsuperpanel to the document and from the document to wijsuperpanel, hence we need to define the object where the elements would be dragged. We do this by using the containment option and setting its value to ‘document’. We can define whether the element itself should be dragged or a clone by using the helper option.

$(".elements div").draggable({
   containment: "document",
   helper: 'clone'
});

Drag and Drop

The drag and drop functionality is pretty easy to implement. To be able to drop the ‘div’ element in the relevant container, we need to handle the drop event. In this event we check if the position where the element is being dropped is acceptable or not. If it is, we can append the element to the relevant container otherwise we can cancel the event. The ui.draggable gives us the current element being dragged.

$(".elements").droppable({
   revert: 'valid',
   greedy: true,
   hoverClass: "dropHover",
   tolerance: 'pointer',
   drop: function (event, ui) {
      if (ui.position.left >= left && ui.position.left <= outerwidth && ui.position.top >=       top && ui.position.top <= outerheight) {
         if (ui.draggable.parents(".elements").length == 0) {
            ui.draggable.insertAfter($(".elements").children()[$(".elements").children().length - 1]);
            ui.draggable.css('top', ui.position.top);
            ui.draggable.css('left', ui.position.left);
            ui.draggable.draggable('destroy').draggable(); /* need to reset the draggability */
         }
      }
      else {
         event.preventDefault();
      }
   }
});

$("body").droppable({
   revert: 'valid',
   tolerance: 'pointer',
   hoverClass: "dropHover",
   drop: function (event, ui) {
      if ((ui.position.left < left || ui.position.left > outerwidth) || (ui.position.top < top ||    ui.position.top > outerheight)) {
         $(this).append(ui.draggable);
         ui.draggable.css('top', ui.position.top);
         ui.draggable.css('left', ui.position.left);
         ui.draggable.css('position', 'absolute');
         ui.draggable.draggable('destroy').draggable({
            containment: 'document',
            helper: 'clone'
         });
      } /* need to reset the draggability */
      else {
         event.preventDefault();
      }
   }
});


Conclusion

I’m sure this drag and drop functionality would be helpful in many ways. You can always modify it as per your requirements.

You can download the given sample for complete implementation.

Download Sample

SpreadJS Alpha has landed

I am proud to announce the Alpha release of SpreadJS: the fastest and easiest way to deploy powerful spreadsheets in your web applications!

SpreadJS is a new product derived from the Spread Product Family, which is a set of spreadsheet components for application development on a variety of platforms. SpreadJS is sure to bring value to your web applications with time-saving features.

Based on HTML5, jQuery, and CSS3, SpreadJS brings all the data visualization and calculation features into your web applications. Create calculators, dynamic interactive dashboards, rich colorful reports, and much more! The rich JavaScript API for SpreadJS provides a complete object model for the spreadsheet document, and a rich set of user interface events which your application can handle to customize the user experience. SpreadJS is designed to provide an Excel-like user interface for spreadsheet navigation, editing, formula calculation, column/row resizing, range drag-drop and drag-fill, and other powerful spreadsheet UI elements such as table sorting and filtering.

   1040 Form Use Case   Schedule Use Case

Highlight Features

Data Visualization and Analysis Support

Let your data tell a story through the enhanced data visualization support in SpreadJS! Recognize trends, isolate out-of-range values, and gain a picture clear understanding of your data. SpreadJS data visualization support includes: Sparklines,Conditional Formatting, Color Gradients, Excel-style Grouping, and more.

Data Visualization

Formula

Powerful Excel compatible formula and ability to data aggregation and analysis, 320+ functions, cross sheet reference, and custom name support.

Data Operation

Rich data interaction, flexible data editing, Excel-style Filter, Row/Column Freeze, Row/Column Resize, and Drag-Fill and Drag-Drop.

Sparklines

For even richer data analysis, add sparklines: tiny lightweight charts that are drawn in cells to provide a visual representation of data. SpreadJS supports the Column, Line, and Win/Loss sparkline types.

Sparkline

Filtering

View only the data you are interested in by filtering using the familiar Excel-style filter dialog.

Filter

Range Grouping

Use Excel-style range grouping to logically group ranges, and nested ranges of data.

Group

Rich Data Interaction & Display Support

Customize the look and feel of SpreadJS within your application. Data is integral to your application. The colors, borders, fonts, and table-layout elements used to layout your data should support a high level of customization. SpreadJS provides extensive customization at the row, column, and cell level. In addition, SpreadJS provides Excel-style theme support to allow you to create the presentation you desire.

Styling

Multiple Header Styling

Define any number of rows and columns for the headers. You can also fully customize the appearance of header cells, including the text, styles, spans, and height/width.

Header

Row/Column Freezing

You can freeze (make non-scrolling) any number of rows, columns, or both in a sheet.

Freeze

Cell Borders

Customize the appearance of the cells by setting borders for a cell or range of cells. A border can be displayed on the left, right, top, or bottom, or around all four sides of a cell or cell range. You can specify more than one style and color for the same cell, column, row, or block of cells. Different border styles let you set different options.

Border

Get Started!

SpreadJS is powered by HTML5, jQuery, and CSS3. We provide a widget, which gives you an easy way to use the control. To use SpreadJS, follow these three simple steps:

1. Add References

First, we need to reference the necessary scripts.

<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js" type="text/javascript"></script>
<!-- SpreadJS CSS and script -->
<link href="http://cdn.wijmo.com/spreadjs/gcfilter-ui.css" rel="stylesheet" title="metro-jqueryui" type="text/css" />
<link href="http://cdn.wijmo.com/themes/wijmo/jquery.wijmo.wijsuperpanel.css" rel="stylesheet" type="text/css" />
<link href="http://cdn.wijmo.com/themes/cobalt/jquery-wijmo.css" rel="stylesheet" type="text/css" title="rocket-jqueryui" />
<script src="http://cdn.wijmo.com/spreadjs/jquery.wijmo.wijspread.full.min.js" type="text/javascript"></script>

2. Create the Markup

Next, we add markup for the SpreadJS control to our document. We need to define this markup like so:

<div id="ss" style="width:100%;height:400px;"></div>

3. Initialize the Spreadsheet

Finally, we need to create a Model & Controller by adding a small piece of JavaScript code:

<script type="text/javascript">
    $(document).ready(function(){
        $("#ss").wijspread({sheetCount:1}); // create wijspread control
        var spread = $("#ss").wijspread("spread"); // get instance of wijspread control
        var sheet = spread.getActiveSheet(); // get active worksheet of the wijspread control
        // initializing the active worksheet here...
    });
</script>

Go Get It!

Download SpreadJS Alpha and try the online sample. We have also published some documentation for the widgets to help you get started. The docs will be updated during the Alpha process so please be patient if something is missing momentarily.

If you have any feedback or questions, please post them in the SpreadJS Alpha forum. Note that this is our first step: alpha of version 1.0 release. We’ll continue to improve SpreadJS in the future. Your feedback is very important to us.

Wijmo Wednesday: Server Side Grid Magic

In a previous post, we discussed how to add a whole bunch of awesome features to a standard HTML table and transform it into a “grid”.  What I’d like to do today is show you how to move a lot of this functionality over to the server.

By harnessing the server to do a lot of the “heavy lifting”, we can give our users a smooth experience.  What heavy lifting would need to be done?  Assume you have a data set of 1 million rows.  That’s a lot of data to send to the client, and then sort/page/filter.  If we ask the server to sort/page/filter the data before sending it to the client, we can quickly reduce the overhead of the client.

I’m going to be using the example from my webcast, which you can access here.

The Server

For data, I’m using the Chinook database.  It’s quick and easy to set up, and gives me good data to use in my examples.  I’m using ASP.NET MVC 3 for my examples, and we’ll only be implementing sorting and filtering.

        public JsonResult GetAlbumList()
        {
            int pageSize = Request.Params["paging[pageSize]"] != null ? Convert.ToInt32(Request.Params["paging[pageSize]"]) : 0;
            int pageIndex = Request.Params["paging[pageIndex]"] != null ? Convert.ToInt32(Request.Params["paging[pageIndex]"]) : 0;

            string sortColumn = Request.Params["sorting[0][dataKey]"];
            string sortDirection = Request.Params["sorting[0][sortDirection]"];

            if (string.IsNullOrEmpty(sortColumn)) sortColumn = String.Empty;
            if (string.IsNullOrEmpty(sortDirection)) sortDirection = String.Empty;

            using (var entity = new ChinookEntities())
            {
                var allAlbums = from al in entity.Albums
                                join ar in entity.Artists on al.ArtistId equals ar.ArtistId
                                select new AlbumResult()
                                           {
                                               AlbumName = al.Title,
                                               ArtistName = ar.Name
                                           };

                var totalRowCount = allAlbums.Count();

                if (pageSize == 0)
                    pageSize = totalRowCount;

                if (sortColumn.ToLower() != "album")
                    allAlbums = sortDirection.ToLower() == "descending"
                                    ? allAlbums.OrderByDescending(p => p.ArtistName).Skip(pageSize*pageIndex).Take(pageSize)
                                    : allAlbums.OrderBy(p => p.ArtistName).Skip(pageSize*pageIndex).Take(pageSize);
                else
                    allAlbums = sortDirection.ToLower() == "descending"
                                    ? allAlbums.OrderByDescending(p => p.AlbumName).Skip(pageSize*pageIndex).Take(pageSize)
                                    : allAlbums.OrderBy(p => p.AlbumName).Skip(pageSize*pageIndex).Take(pageSize);

                var result = new WijmoGridResult { Items = allAlbums.ToList(), TotalRowCount = totalRowCount };

                return Json(result, JsonRequestBehavior.AllowGet);
            }
        }

Let’s walkthrough what this code does, because it does a lot.  The first six lines pulls out Request parameters that Wijmo will send.  Because it is possible for these values to be null, a little bit of self checking needs to take place.

Starting at the using statement, we’re opening a connection to our database with Entity Framework.  We use the idea of lazy loading to create a structured query so our round trip to SQL Server only happens once.  The first query creates a query for all the albums in the database.  This is needed to get the total row count.  Wijmo will use that to determine the paging requirements.

For sorting, you’ll probably be drawn to the epic IF..ELSE statement.  All this is doing is determining what column we want to sort by and how we want to sort it (ascending or descending), and apply the correct LINQ filter.  These calls are also using the Skip() and Take() technique for pagination. 

Finally, you might notice I don’t have the definitions for AlbumResult and WijmoGridResult.  Here is the code for those classes:

    public class AlbumResult
    {
        public string AlbumName { get; set; }
        public string ArtistName { get; set; }
    }

    public class WijmoGridResult
    {
        public List Items { get; set; }
        public int TotalRowCount { get; set; }
    }

The Client

Now that the server is configured, we need to change our Wijmo configuration a little bit to use the new settings.

	$(document).ready(function () {

		var dataReader = new wijarrayreader([
				{ name: "Artist", mapping: "ArtistName" },
				{ name: "Album", mapping: "AlbumName" }
			]);

		var dataSource = new wijdatasource({
			proxy: new wijhttpproxy({
				url: "@Url.Action("GetAlbumList")",
				dataType: "json"
			}),
			dynamic: true,
			reader: {
				read: function (datasource) {
					var count = datasource.data.TotalRowCount;
					datasource.data = datasource.data.Items;
					datasource.data.totalRows = count;
					dataReader.read(datasource);
					}
			}
		});

		$("#remoteTable").wijgrid({
			pageSize: 15,
			data: dataSource,
			allowPaging: true,
			allowSorting: true
		});
	});

At the top, we’re going to declare a new datareader for the JSON coming from the server.  This tells Wijmo how to map JSON properties to Columns in the grid. 

Next is the datasource.  This is a proxy for a URL.  Wijmo will do a GET on this URL to pull information.  The dynamic keyword tells Wijmo that the server will accept sorting, filtering, and paging requests.  If this is false or not set, Wijmo will not send the request parameters we mentioned earlier.  The reader tells WIjmo how to interpret the data coming in, and decipher row counts and then finally apply the datareader.

The last call is the actual WijGrid creation.  This shouldn’t be too different from what you’ve seen in the past.  The only thing that makes Wijmo use the server to gather data is the datasource. 

I hope this serves as an introduction to doing server side calls with Wijmo.  If you have any questions at all, feel free to post them to the comments or email me!

Kevin Griffin
keving@componentone.com

Follow Me On Twitter