Adding HTML characters in cells

clock April 27, 2017 19:40 by author htmltreegrid

As most of you know, the HTML TreeGrid allows you to embed custom HTML content within the cells in a very conveinient manner. This can be just pure HTML, or interactive HTML as described in this blog post:

http://blog.htmltreegrid.com/post/How-to-add-custom-interactive-html-from-a-labelFunction.aspx

What this allows you to do, is to return any HTML in string format and the grid will render it in the cells. With this convenience, comes a limitation - if you have special characters you want to render, they get converted to HTML and are not rendered as text. Today, a customer reached out with a query about how to handle scenarios where you want to show special characters but not render any custom HTML. The solution is to use a special item renderer:

(function () {

    "use strict";

    var EncodedItemRenderer;

    EncodedItemRenderer = function (tag) {

 

        flexiciousNmsp.Label.apply(this, [tag]);

    };

    flexiciousNmsp.EncodedItemRenderer = EncodedItemRenderer; //add to name space

    EncodedItemRenderer.prototype = new flexiciousNmsp.Label(); //setup hierarchy

    EncodedItemRenderer.prototype.typeName = EncodedItemRenderer.typeName = "EncodedItemRenderer";//for quick inspection

    EncodedItemRenderer.prototype.getClassNames = function () { //for support of "is" keyword

        return ["UIComponent", this.typeName];

    };

    EncodedItemRenderer.prototype.setText = function (val) {

             this.domElement.textContent = val;

    };

}());

 

 

And attached is a running example:

 

test.html (4.51 kb)



Best WebComponents DataGrid DataTable

clock March 13, 2017 02:04 by author htmltreegrid

We're please to announce the general release of the WebComponents wrapper for our powerful HTML DataGrid.

With this, we now support the following technologies:

React:
http://blog.htmltreegrid.com/post/React-DataGrid-initializing-HTMLTreeGrid-in-componentDidMount-of-a-React-Component.aspx
http://reactdatagrid.com [Pure React DataGrid]

Angular 1:
http://blog.htmltreegrid.com/post/AngularJS-DataGrid-Component-Why-our-Angular-DataGrid-is-better.aspx

Angular 2 (&4):
http://blog.htmltreegrid.com/post/Angular-2-HTML-TreeGrid.aspx

 

Web Components:
http://blog.htmltreegrid.com/post/Best-WebComponents-DataGrid-DataTable.aspx

In this post, we are going to look at how to integrate the webcomponents wrapper for HTML Datagrid.

Instructions

* git checkout https://github.com/flexicious/flxs-webcomponents-data-grid/
* bower install
* Place your licensed copy of html treegrid (v 3.xx) in lib_private 


In your head section:
```
    <script src="./bower_components/webcomponentsjs/webcomponents-lite.js"></script>
    <link rel="import" href="./bower_components/polymer/polymer.html">
    <link rel="import" href="src/flxs-webcomponents-data-grid.html" />
    <link rel="import" href="src/flxs-webcomponents-data-grid-column.html" />
    <link rel="stylesheet" href="http://www.htmltreegrid.com/demo/flexicious/css/flexicious.css" type="text/css" />
```
And then in your body section:
```
    <template id="tpl" is="dom-bind">
        <flxs-webcomponents-data-grid dataProvider="{{ donuts }}" forcePagerRow="true" enablePaging="true" enableExport="true" style="width:800px;height:400px"
            creationComplete="[[creationComplete]]">
            <flxs-webcomponents-data-grid-column type="checkbox"></flxs-webcomponents-data-grid-column>
            <flxs-webcomponents-data-grid-column dataField="id" headerText="ID" filterComboBoxDataProvider="{{donuts}}"></flxs-webcomponents-data-grid-column>
            <flxs-webcomponents-data-grid-column dataField="type" headerText="Type"></flxs-webcomponents-data-grid-column>
        </flxs-webcomponents-data-grid>
    </template>
```    
 And then in your script section:
```
    <script>
    
         var donuts = [
                            { "id":"5001", "type":"None None None" },
                            { "id":"5002", "type":"Glazed" },
                            { "id":"5005", "type":"Sugar" },
                            { "id":"5007", "type":"Powdered Sugar" },
                            { "id":"5006", "type":"Chocolate with Sprinkles" },
                            { "id":"5003", "type":"Chocolate" },
                            { "id":"5004", "type":"Maple" }
                        ];
    window.addEventListener('dom-change', function () {
      var tpl = document.getElementById('tpl');
      tpl.donuts = donuts;
      tpl.creationComplete =  function(evt){
            alert("Created " + evt.id)
        }
    });
    </script>
    
    

 



Angular 2 HTML TreeGrid

clock February 25, 2017 20:13 by author htmltreegrid

As most of you are aware, we have supported Angular for a longtime:

Here are a couple blog posts in regards to our Angular 1.x support:

http://blog.htmltreegrid.com/post/AngularJS-DataGrid-Component-Why-our-Angular-DataGrid-is-better.aspx
http://blog.htmltreegrid.com/post/Angular-JS-Support.aspx

We had Angular 2 support built a few months ago, and have been trying it out with some of our customers. With the release of Angular 4, this same approach will continue to work.

So, without further ado, here are the steps you will need:

 

  • 1- Import the directive import {TreeGridDirective} from './treeGrid.directive'
  • 2- List it in the directive list inside your component directives: [TreeGridDirective]
  • 3- Create a bindable property that can be bound to your template  gridOptions = {    dataProvider: [],   delegate: this }
  • 4- In your template use directive like this: <div fd-grid ...
  • 5- Bind your option similar to our angular 1 directive
  • 6- Bind the grid options like [(model)]="gridOptions" 
Below, is a full example of this approach. 
To run this example,
  • 1) create a folder and unzip the zip file below into that folder
  • 2) npm install
  • 3) npm start

angular2.zip (269.62 kb)



Programatically control cell borders in HTML DataGrid

clock January 17, 2017 23:52 by author htmltreegrid

Example attached:

Use of cellBorderFunction and iconClick

levelsAndIconClick.html (6.01 kb)



Export Timing out issue

clock October 31, 2016 01:05 by author htmltreegrid

Recently had an issue reported by a long time customer. 

 

 

While using Export to excel in Htmltreegrid, We have implemented “Excel2007” option  to export gridData in “.xls” format.

We are implementing this using Excel2007Exporter.js file(see attached) and added following code in our controller file in onGridCreationComplete function.

 

$scope.onGridCreationComplete = function(evt) {

                                                                                                                                var grid = evt.target;

                                                                                                                                grid.excelOptions.exporters = exporters = [new flexiciousNmsp.CsvExporter(), new flexiciousNmsp.DocExporter(),

                                                                                                                                new flexiciousNmsp.HtmlExporter(),new flexiciousNmsp.XmlExporter(),new flexiciousNmsp.TxtExporter(),

                                                                                                                                 new flexiciousNmsp.Excel2007Exporter()

                                                                                                                                 ];

                                                                                                                                 grid.excelOptions.enableLocalFilePersistence=false;

                                                                                                                                grid.validateNow();

                                                                                                                };

 

 

 

But while Exporting the data of the grid which is having more than large records(1000+ records), It redirects  to Flexicious homepage and shows error message whithout generating excel.

 

Please suggest on this.

=========================================================

Answer :

This customer was using sample code from an old version of the product that did not have support for file saver. It was using the flexicious server echo. When you do a export , we basically build a string on the client application. If Flash player is available, we will use it via the downloadify library. If not, we need to go through the traditional http File Buffering process. So what we do is this : We build the excel/word/html string, and send it to the server, which simply writes it back, in addition to setting the content type. Now, we advise that you implement your own url to buffer this string back, but do provide our own url - the one mentioned above to perform the buffering. There is more information here : http://blog.htmltreegrid.com/post/Excel-Word-and-Html-Export-and-the-Echo-URL.aspx 

However, with the newer versions, we have added support for file saver. On modern browsers, you can do file save without the need for having flash. So the download mechanism will check to see if filesaver exists and is supported, if so, will use that. If it is not there or is not supported, it will fall back to flash. All you have to do is to use the new release and include FileSaver.js. If you include our PDF support, FileSaver is automatically included.

<script type="text/javascript" src="http://htmltreegrid.com/demo/external/js/thirdparty/jspdf-combined.js"></script>

You can also import filesaver independently:

https://github.com/eligrey/FileSaver.js/ 

Complete working example below:

index.zip (2.74 kb)



Copy Cell Issue with custom HTML in cells

clock October 5, 2016 03:57 by author htmltreegrid

As most of you know, the grid provides an extremely convenient mechanism to write out custom HTML in cells, labelFunction and labelFunction2. This gives you complete control over what html you want to appear within each cell. However, with this flexibility comes a little bit of a issue in that the same code is executed when the grid renders the cell, or the cell export or copy mechanism inspect the cells to figure out the text to export or to copy. 

One of our customers was trying to implement the copy cell functionality described in this blog post:

http://blog.htmltreegrid.com/post/Adding-Custom-Right-Click-functionality-to-HTMLTreeGrid.aspx 

However, when they had custom HTML in the cell, there were two issues they encountered:

1.       While using label-Function2, and try to use this Copy cell it is giving below error, And it is not doing anything :

minified-compiled-jquery.js:1300 Uncaught TypeError: Cannot read property 'implementsOrExtends' of null

2.       While using Copy Table functionality, It is giving below error, And it is not doing anything:

minified-compiled-jquery.js:472 Uncaught ReferenceError: isIncludedInExport is not defined

 

 In In a nutshell, the problem is this - when you do copy cell, we need to identify which cell your mouse is on. We use the mouse event target to find out which FlexDataGridCell object the mouse event dom element belongs to. In this case, since we have custom HTML within the cell, we need to navigate to the DIV domelement first and then use that to get to the FlexDataGridCell object. Attached is a working test case that demonstrates fix for the above issue. 

HTML5_FleixiciousGrid.zip (8.44 kb)



Some Recent FAQs

clock October 4, 2016 06:07 by author htmltreegrid

Recently had a couple interesting questions:

Question : I am using flexicious HTMLTree grid in one of my project and I am not able to figure how to retrieve filtered rows anytime on grid. I need all rows which are actually filtered and not just rows appearing on screen at any instant. Please let me know how can I achieve that and it will great if you could share sample example of it.

Answer :   var filterData = grid.getFilteredPagedSortedData({},true,false,false,false);

 

Question : We are using HTMLTreeGrid with angularJS.  In our applications we have added buttons to our grid using the ToolBarActions but need more control when to enable a button than simply saying a row has been picked at a level.  For example, we only want to enable the button based on data in the selected row.  Is that possible?  Can you send an example how to do this?  Or do we need to create a Custom PagerControl to do this?  And how easy is it to extend the PagerControl to additional functions?

It is very easy to extend the pager control:

http://blog.htmltreegrid.com/post/How-to-Customize-the-Pager-(Toolbar)-Export-Options-Settings-and-Save-Settings-Popups.aspx

The toolbar actions are built within the pager control. You can do something like this:

 toolbarActionValidFunction="isValidToolbarAction" 

Here is the default implementation:

/**
 * Evaluates whether the given toolbar action is valid or not.
 *
 * If toolbarActionValidFunction is not null, returns the result of the function passing in the given ToolbarAction.
 * Else returns true.
 * @method isToolbarActionValid
 */
isToolbarActionValid = function (action, currentTarget, extendedPager) {
    if (action.requiresSingleSelection) {
        if (this.getSelectedKeys().length == 1) {
            var appliesToLevel = action.level;
            var itemLvl = this.getLevelForItem(this.getSelectedObjects()[0]);
            if (appliesToLevel == -1 || (itemLvl && (itemLvl.getNestDepth() == appliesToLevel)))
                return true;
            else
                return false;
        }
        return false;
    } else if (action.requiresSelection) {
        return this.getSelectedKeys().length > 0;
    }
    return true;
};
Finally, two attached examples demonstrate how to accomplish this with Angular JS:

angular (1).html (5.12 kb)

Index_hierarchy.html (6.24 kb)

And can you explain how to set the grid so picking a top level row does not automatically pick all nested next levels rows?  We can pick a row from the next level row and it does not auto pick the parent row.  We need the user to explicitly pick the nested rows even when the parent row is selected.

 

è     Just set enableSelectionCascade to false. 



How to use third party components in HTMLTreeGrid

clock July 5, 2016 07:06 by author htmltreegrid

This is a question that has come up before, and its a hard one to answer. As you are aware, we provide API hooks to give you complete control over the contents of each cell. There are some easy way to do this - for example, you can simply return some custom HTML in a labelFunction, and even make it interactive, like we show in this blog post: http://blog.htmltreegrid.com/post/How-to-add-custom-interactive-html-from-a-labelFunction.aspx 

However, the question becomes, how about when you have to use custom third party components. While we cannot guarantee the product will work with every single third party component, nor can we offer support for components that we have not authored, we certainly can show you how this can be done with a sample component. For this example, we are going to use the powerful and very popular select2 jquery auto complete component. 

Let's dive into the code:


/**
* Flexicious
* Copyright 2011, Flexicious LLC
*/
(function(window)
{
"use strict";
var AutoCompleteRenderer, uiUtil = flexiciousNmsp.UIUtils, flxConstants = flexiciousNmsp.Constants;
/**
* A CheckBoxRenderer is a custom item renderer, that defines how to use custom cells with logic that you can control
* @constructor
* @namespace flexiciousNmsp
* @extends UIComponent
*/
AutoCompleteRenderer=function(){
//make sure to call constructor
flexiciousNmsp.UIComponent.apply(this,["div"]);//second parameter is the tag name for the dom element.



var html='<select class="js-example-basic-single"> <option value="AL">Alabama</option><option value="AL">Alaska</option><option value="CO">Colorado</option></select>';
this.domElement.innerHTML=html;
this.select = this.domElement.firstChild;
var $eventSelect =$(this.select);
$eventSelect.select2();
$eventSelect.on("change", this.onChange.bind(this));

/**
* This is a getter/setter for the data property. When the cell is created, it belongs to a row
* The data property points to the item in the grids dataprovider that is being rendered by this cell.
* @type {*}
*/
this.data=null;

};
flexiciousNmsp.ItemRenderers_AutoCompleteRenderer = AutoCompleteRenderer; //add to name space
AutoCompleteRenderer.prototype = new flexiciousNmsp.UIComponent(); //setup hierarchy
AutoCompleteRenderer.prototype.typeName = AutoCompleteRenderer.typeName = 'AutoCompleteRenderer';//for quick inspection
AutoCompleteRenderer.prototype.getClassNames=function(){
return ["AutoCompleteRenderer","UIComponent"]; //this is a mechanism to replicate the "is" and "as" keywords of most other OO programming languages
};

/**
* This is important, because the grid looks for a "setData" method on the renderer.
* In here, we intercept the call to setData, and inject our logic to populate the text input.
* @param val
*/
AutoCompleteRenderer.prototype.setData=function(val){
flexiciousNmsp.UIComponent.prototype.setData.apply(this,[val]);
var cell = this.parent; //this is an instance of FlexDataGridDataCell (For data rows)
var column = cell.getColumn();//this is an instance of FlexDataGridColumn.
if(this.data[column.getDataField()])
this.select.value=this.data[column.getDataField()];
};
/**
* This event is dispatched when the user clicks on the icon. The event is actually a flexicious event, and has a trigger event
* property that points back to the original domEvent.
* @param evt
*/
AutoCompleteRenderer.prototype.onChange=function(evt){

//in the renderer, you have the handle to the cell that the renderer belongs to, via the this.parent property that you inherit from flexiciousNmsp.UIComponent.

var cell = this.parent; //this is an instance of FlexDataGridDataCell (For data rows)
var column = cell.getColumn();//this is an instance of FlexDataGridColumn.
console.log('setting value to' + this.select.value)
this.data[column.getDataField()]=this.select.value;//we use the dom element to wire back the value to the data object.
};
//This sets the inner html, and grid will try to set it. Since we are an input field, IE 8 will complain. So we ignore it since we dont need it anyway.
AutoCompleteRenderer.prototype.setText=function(val){

};
}(window));

We are defining an itemRenderer here, that simply wraps a select2 component. In its constructor, we initalize it.
In the set data method, we populate it. And we listen for its change event, where we write the data back to the 
data provider.
Below is the complete running example:

third-party-item-renderer.html (7.22 kb)

 

And this is what this will look like:

 



Selected Index Question

clock June 9, 2016 20:49 by author htmltreegrid

Recently got a question about the selected index property.


the question read something like this


The function

grid.getSelectedIndex()

returns the actual index of the selected row, which is correct when no filter is set.

But if I set a filter (which, of course, reduces the amount of actually displayed data) this function returns still the same number, which is not correct.

Is there a function that returns the index of the selected row while considering any active filters?

For example: I have 10 rows in my grid. When I click on the 5th row then getSelectedIndex() returns 4 (because it’s a zero-based index).

But if I set a filter causing that just this one row is visible and the others rows are not visible anymore (grid.getTotalRecords returns 1), then by clicking on this row the function getSelectedIndex() still returns 4, but should now return 0.


===

The short answer to this question is that  it is possible to do it if you really want the selectedIndex, do grid.getFilteredPagedSortedData() and then do an indexOf grid.getSelectedItem() on that array.


 var filterCnt = grid.getFilteredPagedSortedData({},true,false,true);

  And then

 filterCnt.indexOf(grid.getSelectedItem())

 

The longer answer is a little more involved.  and the primary idea is if  in reality what you need is the item that is selected just use the getSelectedItem method.  we made a conscious decision to deviate from the way some other products store  the selected state of the grid.  depending on what you set as the value for your selectedKeyField,  we will either store the actual object that is selected or a key property on the object that is selected.  internally we never store the index of the object that selected.  this is always calculated.  this allows us to maintain selection regardless of the state of the data provider if it's filters sorted, or paged in any manner.

 

The selectedIndex is not a reliable method of identifying the selected object, because that index changes everytime you do a sort or a filter or page. In other words. If the selected index is on page 0, and you move to page 2, the selectedIndex means nothing because the object is no longer on the page. This gets further complicated when server paging is invovled. So our recommendation is always use grid.getSelectedItem instead of grid.getSelectedIndex, because majority of the time, you are using the index to get to the actual item anyway.



Calling methods on Angular Scope

clock May 31, 2016 02:03 by author htmltreegrid

Recently a few customers have asked the same question:

We are using HTMLTreegrid with angularJS. We are expecting code snippet with angularJS.

In angularJS controller we are unable to call scope function which mentioned in previous mail.

 

At Angular contoller

 

$scope.saveStatus= function(rowData, column){

                var data='<div ><a href="javascript:void(0);" class="launchEditor" ng-click= "updateStatus('+rowData+')"><i class="fa fa-check"></i></a></div>';

         return data;

       

 }

 

 

 

Answer is to get scope from the item being clicked.  

For example:

myCompanyNameSpace.ItemRenderers_getNextHTML=function(item,column){

                       

            return "<img src='resources/app/assets/next.png' class='custom-hover' onclick='itemClickEvent(this)' title='Go to Item Info'>";

 

};

 

itemClickEvent =function(item){

        var scope = angular.element(document.getElementById("MainWrap")).scope();

                

        scope.$apply(function () {

              var itemObj = item.parentNode.component.data;

              console.log("itmeObj "+ itmeObj);

              scope.gotoItemInfo(itmeObj);

            });

};