PDA

View Full Version : [CLOSED] GridPanel Column Locking: Odd Issue



cwolcott
Oct 10, 2013, 4:05 PM
I have several gridpanels that display details in my application that work just fine when I assign certain columns Locked="true". But my primary GridPanel in my viewport has a strange issue when I assign any columns Locked="true".

When I assign the first and second column Locked="true" all the headers for the grid are displayed correctly, but only the data in the locked columns are displayed. The other columns are blank. When I click a row and perform an action against the row the data that normal passes correctly is null.

I know this is impossible to dubug without an example, but wasn't sure if you have heard or seen this before. The gridpanel is buried deep within the code. It is being populated by a store that has:


PageSize="25" AutoLoad="false" RemoteSort="true" OnReadData="RequestsRefreshData" ViewStateMode="Enabled"

Again everything is just fine if I don't try to lock any columns.

Any thoughts on where to look? I might try to dig in the Column code to see what it does when Locked="true".

cwolcott
Oct 10, 2013, 6:53 PM
Here is a little more information. The first column (#3) that stops displaying the data has a renderer defined. If I take away the renderer on column #3 data is displayed for all rows through column #6. Column #6 also has a renderer. Remove Column #6 renderer and all the data shows up.

Now column #4 has a renderer, but it is not causing any problems. The renderers for #3 and #6 are performing some action on the data and then calling a common method that highlights (bold and underscore) the text in the column based on any filtering.

Again all of this works when none of the columns has Locked="true". I think I can reproduce the error tonight when I get home.

Baidaly
Oct 10, 2013, 9:02 PM
Hello!

Really, strange issue.

You said you do some manipulation with data in the renderers. Is it possible to do them using Convert Handler of Model:



<ext:ModelField Name="SomeField">
<Convert Fn="prepareSomeField" />
</ext:ModelField>


Also, I don't know maybe refreshing the Grid's view can help as well.

We would be happy to investigate a sample of this issue.

cwolcott
Oct 10, 2013, 9:12 PM
Hopefully I will have one out in a couple of hours.

cwolcott
Oct 11, 2013, 1:02 AM
Here is an example. I used the GridPanel --> Locking Grid --> Simple example and added the following:


New ModelField name "ticker"
New Column to display "ticker"
Added Locked="true" to Company Name column
Added Renderer to tickeer column





<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
this.GridPanel1.Store.Primary.DataSource = new object[]
{
new object[] { "3m Co", "MMM", 71.72, 0.02, 0.03, "9/1 12:00am" },
new object[] { "Alcoa Inc", "AA",29.01, 0.42, 1.47, "9/1 12:00am" },
new object[] { "Altria Group Inc", "MO",83.81, 0.28, 0.34, "9/1 12:00am" },
new object[] { "American Express Company", "AXP",52.55, 0.01, 0.02, "9/1 12:00am" },
new object[] { "American International Group, Inc.", "AIG",64.13, 0.31, 0.49, "9/1 12:00am" },
new object[] { "AT&T Inc.", "T",31.61, -0.48, -1.54, "9/1 12:00am" },
new object[] { "Boeing Co.", "BA",75.43, 0.53, 0.71, "9/1 12:00am" },
new object[] { "Caterpillar Inc.", "CAT",67.27, 0.92, 1.39, "9/1 12:00am" },
new object[] { "Citigroup, Inc.", "C",49.37, 0.02, 0.04, "9/1 12:00am" },
new object[] { "Exxon Mobil Corp", "XOM",68.1, -0.43, -0.64, "9/1 12:00am" },
new object[] { "General Electric Company", "GE",34.14, -0.08, -0.23, "9/1 12:00am" },
new object[] { "General Motors Corporation", "GM",30.27, 1.09, 3.74, "9/1 12:00am" },
new object[] { "Hewlett-Packard Co.", "HP",36.53, -0.03, -0.08, "9/1 12:00am" },
new object[] { "Honeywell Intl Inc", "HON",38.77, 0.05, 0.13, "9/1 12:00am" },
new object[] { "Intel Corporation", "INTC",19.88, 0.31, 1.58, "9/1 12:00am" },
new object[] { "International Business Machines", "IBM",81.41, 0.44, 0.54, "9/1 12:00am" },
new object[] { "Johnson & Johnson", "JNJ",64.72, 0.06, 0.09, "9/1 12:00am" },
new object[] { "JP Morgan & Chase & Co", "JPM", 45.73, 0.07, 0.15, "9/1 12:00am" },
new object[] { "McDonald\"s Corporation", "MCD", 36.76, 0.86, 2.40, "9/1 12:00am" },
new object[] { "Merck & Co., Inc.", "MRK", 40.96, 0.41, 1.01, "9/1 12:00am" },
new object[] { "Microsoft Corporation", "MSFT", 25.84, 0.14, 0.54, "9/1 12:00am" },
new object[] { "Pfizer Inc", "PFE", 27.96, 0.4, 1.45, "9/1 12:00am" },
new object[] { "The Coca-Cola Company", "KO", 45.07, 0.26, 0.58, "9/1 12:00am" },
new object[] { "The Home Depot, Inc.", "HD", 34.64, 0.35, 1.02, "9/1 12:00am" },
new object[] { "The Procter & Gamble Company", "PG", 61.91, 0.01, 0.02, "9/1 12:00am" },
new object[] { "United Technologies Corporation", "UTX", 63.26, 0.55, 0.88, "9/1 12:00am" },
new object[] { "Verizon Communications", "VZ", 35.57, 0.39, 1.11, "9/1 12:00am" },
new object[] { "Wal-Mart Stores, Inc.", "WMT", 45.45, 0.73, 1.63, "9/1 12:00am" }
};

this.GridPanel1.Store.Primary.DataBind();
}
}
</script>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title>GridPanel with Locking Columns - Ext.NET Examples</title>
<script>
var template = '<span style="color:{0};">{1}</span>';

var change = function (value) {
return Ext.String.format(template, (value > 0) ? "green" : "red", value);
};

var pctChange = function (value) {
return Ext.String.format(template, (value > 0) ? "green" : "red", value + "%");
};
var highlightFilterRenderer = function (value, grid, sFilter) {
var filter = grid.getFilterPlugin().getFilter(sFilter);
var renderValue = value;

// Removed the guts ...

return renderValue;
}
</script>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<ext:GridPanel ID="GridPanel1" runat="server" Title="Locking Grid" Width="600" Height="350">
<Store>
<ext:Store ID="Store1" runat="server">
<Model>
<ext:Model ID="Model1" runat="server">
<Fields>
<ext:ModelField Name="company" />
<ext:ModelField Name="ticker" />
<ext:ModelField Name="price" Type="Float" />
<ext:ModelField Name="change" Type="Float" />
<ext:ModelField Name="pctChange" Type="Float" />
<ext:ModelField Name="lastChange" Type="Date" DateFormat="M/d hh:mmtt" />
</Fields>
</ext:Model>
</Model>
</ext:Store>
</Store>
<ColumnModel>
<Columns>
<ext:RowNumbererColumn ID="RowNumbererColumn1" runat="server" />
<ext:Column runat="server" Text="Company" DataIndex="company" Width="200"Sortable="false" Locked="true" />
<ext:Column runat="server" Text="Ticker" DataIndex="ticker" Width="200" Lockable="false">
<Renderer Handler="return highlightFilterRenderer(value, #{GridPanel1}, 'ticker');" />
</ext:Column>
<ext:Column ID="Column2" runat="server" Text="Price" DataIndex="price" Width="125"
Lockable="false">
<Renderer Format="UsMoney" />
</ext:Column>
<ext:Column ID="Column3" runat="server" Text="Change" DataIndex="change" Width="125">
<Renderer Fn="change" />
</ext:Column>
<ext:Column ID="Column4" runat="server" Text="% Change" DataIndex="pctChange" Width="125">
<Renderer Fn="pctChange" />
</ext:Column>
<ext:DateColumn ID="DateColumn1" runat="server" Text="Last Updated" DataIndex="lastChange"
Width="135" />
</Columns>
</ColumnModel>
<Features>
<ext:GridFilters runat="server" Local="true">
<Filters>
<ext:StringFilter DataIndex="ticker" />
</Filters>
</ext:GridFilters>
</Features>
</ext:GridPanel>
</body>
</html>


The issue is when I perform:

var filter = grid.getFilterPlugin().getFilter(sFilter);

When a column has the property Locked="true" the filter is null, but when Locked is not assigned Filter is valid.

Put a break point and jump into the function getFilterPlugin(), which is an override from src/grid/Panel.js and for some reason the this.features is null when Locked is assigned, but it is valid when Locked is not used.

Baidaly
Oct 11, 2013, 1:51 AM
Try the following one:


var highlightFilterRenderer = function (value, grid, sFilter) {
var filter = grid.lockedGrid == null ? grid.getFilterPlugin().getFilter(sFilter) : grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
var renderValue = value;

// Removed the guts ...

return renderValue;
};

We will discuss this issue.

cwolcott
Oct 11, 2013, 1:42 PM
Thanks for the workaround, but (There is always a but) there is one more problem. The filter is now being found with columns defined as Locked="true" or no columns defined with Locked="true", but if any of the columns have Locked="true" and I am filtering the ticker column the filter.active is false, but if none of the columns have Locked="true" and I am filtering the ticker column the filter.active is true.



var highlightFilterRenderer = function (value, grid, sFilter) {
var filter = grid.lockedGrid == null ? grid.getFilterPlugin().getFilter(sFilter) : grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
var renderValue = value;

if (filter && filter.active) {

// Removed the guts ...
renderValue = "FAKE";
}

return renderValue;
};

cwolcott
Oct 12, 2013, 7:32 AM
Try the following one:


var highlightFilterRenderer = function (value, grid, sFilter) {
var filter = grid.lockedGrid == null ? grid.getFilterPlugin().getFilter(sFilter) : grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
var renderValue = value;

// Removed the guts ...

return renderValue;
};


At the suggestion of JSLint I changed grid.lockedGrid == null to grid.lockedGrid === null.
I then had to change null to undefined and thus the final check is grid.lockedGrid === undefined.

The issue in Thread #7 still exists. I was just running JSLint through my code and it suggested the above.

Baidaly
Oct 13, 2013, 8:09 AM
Sorry for the delay.

Try the following:

Add one more parameter - column of the grid.


<ext:Column runat="server" Text="Ticker" DataIndex="ticker" Width="200" Lockable="false">
<Renderer Handler="return highlightFilterRenderer(value, #{GridPanel1}, 'ticker', metadata.column);" />
</ext:Column>

And use it in your renderer:

var highlightFilterRenderer = function (value, grid, sFilter, column) {
var filter;
if (grid.lockedGrid !== undefined && column.isLocked())
filter = grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
else
filter = grid.normalGrid.getFilterPlugin().getFilter(sFilte r);

var renderValue = value;

// Removed the guts ...
if (filter && filter.active) {

// Removed the guts ...
renderValue = "FAKE";
}

return renderValue;
};

cwolcott
Oct 14, 2013, 2:39 AM
Thank you for your suggestion. Here is the final solution that works for me:

7037

I do have one issue if I still want to use this javascript function on a grid that does not use locked columns it breaks because grid.normalGrid is undefined. I guess I was hoping that grid.getFilterPlugin() would be able to return the correct value based on the grid configuration.



<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
this.GridPanel1.Store.Primary.DataSource = new object[]
{
new object[] { "3m Co", "MMM", 71.72, 0.02, 0.03, "9/1 12:00am" },
new object[] { "Alcoa Inc", "AA",29.01, 0.42, 1.47, "9/1 12:00am" },
new object[] { "Altria Group Inc", "MO",83.81, 0.28, 0.34, "9/1 12:00am" },
new object[] { "American Express Company", "AXP",52.55, 0.01, 0.02, "9/1 12:00am" },
new object[] { "American International Group, Inc.", "AIG",64.13, 0.31, 0.49, "9/1 12:00am" },
new object[] { "AT&T Inc.", "T",31.61, -0.48, -1.54, "9/1 12:00am" },
new object[] { "Boeing Co.", "BA",75.43, 0.53, 0.71, "9/1 12:00am" },
new object[] { "Caterpillar Inc.", "CAT",67.27, 0.92, 1.39, "9/1 12:00am" },
new object[] { "Citigroup, Inc.", "C",49.37, 0.02, 0.04, "9/1 12:00am" },
new object[] { "Exxon Mobil Corp", "XOM",68.1, -0.43, -0.64, "9/1 12:00am" },
new object[] { "General Electric Company", "GE",34.14, -0.08, -0.23, "9/1 12:00am" },
new object[] { "General Motors Corporation", "GM",30.27, 1.09, 3.74, "9/1 12:00am" },
new object[] { "Hewlett-Packard Co.", "HP",36.53, -0.03, -0.08, "9/1 12:00am" },
new object[] { "Honeywell Intl Inc", "HON",38.77, 0.05, 0.13, "9/1 12:00am" },
new object[] { "Intel Corporation", "INTC",19.88, 0.31, 1.58, "9/1 12:00am" },
new object[] { "International Business Machines", "IBM",81.41, 0.44, 0.54, "9/1 12:00am" },
new object[] { "Johnson & Johnson", "JNJ",64.72, 0.06, 0.09, "9/1 12:00am" },
new object[] { "JP Morgan & Chase & Co", "JPM", 45.73, 0.07, 0.15, "9/1 12:00am" },
new object[] { "McDonald\"s Corporation", "MCD", 36.76, 0.86, 2.40, "9/1 12:00am" },
new object[] { "Merck & Co., Inc.", "MRK", 40.96, 0.41, 1.01, "9/1 12:00am" },
new object[] { "Microsoft Corporation", "MSFT", 25.84, 0.14, 0.54, "9/1 12:00am" },
new object[] { "Pfizer Inc", "PFE", 27.96, 0.4, 1.45, "9/1 12:00am" },
new object[] { "The Coca-Cola Company", "KO", 45.07, 0.26, 0.58, "9/1 12:00am" },
new object[] { "The Home Depot, Inc.", "HD", 34.64, 0.35, 1.02, "9/1 12:00am" },
new object[] { "The Procter & Gamble Company", "PG", 61.91, 0.01, 0.02, "9/1 12:00am" },
new object[] { "United Technologies Corporation", "UTX", 63.26, 0.55, 0.88, "9/1 12:00am" },
new object[] { "Verizon Communications", "VZ", 35.57, 0.39, 1.11, "9/1 12:00am" },
new object[] { "Wal-Mart Stores, Inc.", "WMT", 45.45, 0.73, 1.63, "9/1 12:00am" }
};

this.GridPanel1.Store.Primary.DataBind();
}
}
</script>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title>GridPanel with Locking Columns - Ext.NET Examples</title>
<script>
var template = '<span style="color:{0};">{1}</span>';

var change = function (value) {
return Ext.String.format(template, (value > 0) ? "green" : "red", value);
};

var pctChange = function (value) {
return Ext.String.format(template, (value > 0) ? "green" : "red", value + "%");
};
var highlightFilterRenderer = function (value, grid, sFilter, column) {
var filter;
if (grid.lockedGrid !== undefined && column.isLocked())
filter = grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
else
filter = grid.normalGrid.getFilterPlugin().getFilter(sFilte r);

var renderValue = value;

// Removed the guts ...
if (filter && filter.active) {

// (2013-02-14) Escape the Open and Closed Round/Squared Brackets
searchString = filter.getValue().replace(/\(/g, '\\(');
searchString = searchString.replace(/\)/g, '\\)');
searchString = searchString.replace(/\[/g, '\\[');
searchString = searchString.replace(/\]/g, '\\]');

// Find where the case insensitive match starts and ends.
startIndex = value.search(new RegExp('(' + searchString + ')', 'i'));
endIndex = startIndex + filter.getValue().length;

renderValue = value.substring(0, startIndex);
renderValue = renderValue + '<b><u>' + value.substring(startIndex, endIndex) + '</u></b>';
if (endIndex !== value.length) { renderValue = renderValue + value.substring(endIndex); }
}

return renderValue;
}
</script>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<ext:GridPanel ID="GridPanel1" runat="server" Title="Locking Grid" Width="600" Height="350">
<Store>
<ext:Store ID="Store1" runat="server">
<Model>
<ext:Model ID="Model1" runat="server">
<Fields>
<ext:ModelField Name="company" />
<ext:ModelField Name="ticker" />
<ext:ModelField Name="price" Type="Float" />
<ext:ModelField Name="change" Type="Float" />
<ext:ModelField Name="pctChange" Type="Float" />
<ext:ModelField Name="lastChange" Type="Date" DateFormat="M/d hh:mmtt" />
</Fields>
</ext:Model>
</Model>
</ext:Store>
</Store>
<ColumnModel>
<Columns>
<ext:RowNumbererColumn ID="RowNumbererColumn1" runat="server" />
<ext:Column runat="server" Text="Company<br>Name" DataIndex="company" Width="200"
Sortable="false" />
<ext:Column runat="server" Text="Ticker" DataIndex="ticker" Width="200" Lockable="false">
<Renderer Handler="return highlightFilterRenderer(value, #{GridPanel1}, 'ticker', metadata.column);" />
</ext:Column>
<ext:Column ID="Column2" runat="server" Text="Price" DataIndex="price" Width="125"
Lockable="false">
<Renderer Format="UsMoney" />
</ext:Column>
<ext:Column ID="Column3" runat="server" Text="Change" DataIndex="change" Width="125">
<Renderer Fn="change" />
</ext:Column>
<ext:Column ID="Column4" runat="server" Text="% Change" DataIndex="pctChange" Width="125">
<Renderer Fn="pctChange" />
</ext:Column>
<ext:DateColumn ID="DateColumn1" runat="server" Text="Last Updated" DataIndex="lastChange"
Width="135" />
</Columns>
</ColumnModel>
<Features>
<ext:GridFilters runat="server" Local="true">
<Filters>
<ext:StringFilter DataIndex="ticker" />
</Filters>
</ext:GridFilters>
</Features>
</ext:GridPanel>
</body>
</html>

Baidaly
Oct 15, 2013, 12:14 AM
I guess I was hoping that grid.getFilterPlugin() would be able to return the correct value based on the grid configuration.

We will discuss this.


I do have one issue if I still want to use this javascript function on a grid that does not use locked columns it breaks because grid.normalGrid is undefined.
Try the following function:


var highlightFilterRenderer = function (value, grid, sFilter, column) {
var filter;
if (grid.lockable) {
if (grid.lockedGrid !== undefined && column.isLocked())
filter = grid.lockedGrid.getFilterPlugin().getFilter(sFilte r);
else
filter = grid.normalGrid.getFilterPlugin().getFilter(sFilte r);
} else {
filter = grid.getFilterPlugin().getFilter(sFilter);
}
var renderValue = value;

// Removed the guts ...
if (filter && filter.active) {

// (2013-02-14) Escape the Open and Closed Round/Squared Brackets
searchString = filter.getValue().replace(/\(/g, '\\(');
searchString = searchString.replace(/\)/g, '\\)');
searchString = searchString.replace(/\[/g, '\\[');
searchString = searchString.replace(/\]/g, '\\]');

// Find where the case insensitive match starts and ends.
startIndex = value.search(new RegExp('(' + searchString + ')', 'i'));
endIndex = startIndex + filter.getValue().length;

renderValue = value.substring(0, startIndex);
renderValue = renderValue + '<b><u>' + value.substring(startIndex, endIndex) + '</u></b>';
if (endIndex !== value.length) { renderValue = renderValue + value.substring(endIndex); }
}

return renderValue;
}

cwolcott
Oct 15, 2013, 1:27 AM
Perfect. Thanks for stepping me through this. I will watch future revisions to see if there are any changes to grid. You are welcome to close this whenever you want.

Daniil
Jan 14, 2014, 5:52 AM
Finally, we decided to warn a developer:

Ext.grid.Panel.override({
getFilterPlugin : function () {
if (this.lockedGrid) {
Ext.log({
msg: Ext.String.format("You are calling the getFilterPlugin method on a locking grid ({0}). Please use grid.normalGrid.getFilterPlugin() to get a filter plugin of a normal grid and grid.lockedGrid.getFilterPlugin() for a locked grid", this.id),
level: "warn"
});
}

if (this.features && Ext.isArray(this.features)) {
for (var i = 0; i < this.features.length; i++) {
if (this.features[i].isGridFiltersPlugin) {
return this.features[i];
}
}
} else {
if (this.features && this.features.isGridFiltersPlugin) {
return this.features;
}
}
},

getFeature : function (name) {
if (this.lockedGrid) {
Ext.log({
msg: Ext.String.format("You are calling the getFeature method on a locking grid ({0}). Please use grid.normalGrid.getFeature() to get a filter plugin of a normal grid and grid.lockedGrid.getFeature() for a locked grid", this.id),
level: "warn"
});
}

name = "feature." + name;
if (this.features && Ext.isArray(this.features)) {
for (var i = 0; i < this.features.length; i++) {
if (this.features[i].alias == name) {
return this.features[i];
}
}
} else {
if (this.features && this.features.alias == name) {
return this.features;
}
}
}
});

The warning messages appears only with ScriptMode="Development".

Chris, do you think the warning messages are clear enough?

cwolcott
Jan 15, 2014, 12:15 AM
I looked back in my web.config and have always had ScriptMode="Debug". I will change it to ScriptMode="Development", add the override and produce an issue to see what it looks like.

The messages read OK, just not sure how it will be presented to the developer.

The Getting Started --> Introduction --> Overview (http://examples2.ext.net/#/Getting_Started/Introduction/Overview/) says:

scriptMode : ScriptMode
Whether to include the Release (condensed) or Debug (with inline documentation) or Development (with inline things to debug) Ext JavaScript files.
Default is "Release". Options include [Release|Debug|Development]

So I would guess during development you would always suggest to have ScriptMode="Development" and when in production have ScriptMode="Release" (or leave out). When would ScriptMode="Debug" make sense?

Daniil
Jan 15, 2014, 3:42 AM
The messages read OK, just not sure how it will be presented to the developer.


Ok, I will wait your conclusion before committing that.



So I would guess during development you would always suggest to have ScriptMode="Development" and when in production have ScriptMode="Release" (or leave out).

That is right.


When would ScriptMode="Debug" make sense?

Well, I am not sure. For me it is kind of legacy. I mean that previously there were the two only - Debug and Release. Then the Development one appeared. I switched to that mode and, seems, now I don't use the Debug mode at all. Now the "Debug" name is a bit confusing.

Just to clarify:

"Release" mode renders the minified version of JavaScript and CSS resources.

"Debug" mode renders the non-minified, formatted version of JavaScript and CSS resources.

"Development" mode renders the non-minified, formatted version of JavaScript and CSS resources and JavaScript files contain some things helping to debug (mostly, more error and warning messages).

cwolcott
Jan 17, 2014, 2:06 AM
Go ahead and include this in the next release. I am skiing with the family and may not get to it until next week. I will try tomorrow during a lunch break when we get back to the condo, but I didn't want to hold you up any longer.

Daniil
Jan 17, 2014, 5:02 AM
Ok, committed in revision #5608 and closing the thread.

Though, please feel free to post here if needed.

Thank you again for pointing the problem out.

cwolcott
Jan 20, 2014, 1:52 AM
Had a chance to look at it. Looks good. I have never selected the Console tab in Firebug or the Chrome Debugger. This will be fun to see the other issues that are being logged in my application.

Daniil
Jan 20, 2014, 3:47 AM
Thank you for the feedback!

Those JavaScript consoles are very useful. IE9 and higher have the same one in their Developer Tools.