Schody zaczęły się, gdy dla wybranych wierszy checkbox miał być wyłączony (disabled = true). Biblioteka ExtJS nie przewiduje takiej sytuacji. Można wyłączyć tylko całą kolumnę (wszystkie checkboxy). Potrzebowałem rozwiązania, które sprawi, że dla części wierszy nie będzie można kliknąć na checkbox w kolumnie oraz nie popsuje to kolumny checkcolumn w innych gridach i drzewach.
Konfiguracja własnego renderera dla kolumny nie wchodziła w grę - psuje to wyświetlanie całej kolumny. Nie jest też to zalecane przez programistów Sencha.
W sieci można odszukać mnóstwo tego typu problemów. Żadne z przedstawionych rozwiązań nie spełniało jednak moich potrzeb. Pominę tutaj wszystkie próby, który podjąłem i przedstawię działające rozwiązanie (na razie dla ExtJS 5.1 - wkrótce też dla wersji 4.2).
Rozwiązaniem okazało się przygotowanie overrida dla klasy Ext.grid.column.CheckColumn, dokładnie do dwóch metod: processEvent (odpowiada ona za obsługę zdarzeń dla checkboxa) oraz defaultRenderer (odpowiada za tworzenie elementu w kolumnie - konkretnego checkboxa).
Ext.grid.column.CheckColumn.override({
processEvent: function(type, view, cell, recordIndex, cellIndex, e, record, row) {
var me = this,
key = type === 'keydown' && e.getKey(),
mousedown = type == 'mousedown';
if (!me.disabled && (mousedown || (key == e.ENTER || key == e.SPACE))) {
var checked = !me.isRecordChecked(record);
if(record.get(me.dataIndex) === null){
return false;
}
if (me.fireEvent('beforecheckchange', me, recordIndex, checked) !== false) {
me.setRecordCheck(record, checked, cell, row, e);
me.fireEvent('checkchange', me, recordIndex, checked);
if (mousedown) {
e.stopEvent();
}
if (!me.stopSelection) {
view.selModel.selectByPosition({
row: recordIndex,
column: cellIndex
});
}
return false;
} else {
return !me.stopSelection;
}
} else {
return me.callParent(arguments);
}
},
defaultRenderer : function(value, cellValues) {
var cssPrefix = Ext.baseCSSPrefix,
cls = cssPrefix + 'grid-checkcolumn';
if (this.disabled) {
cellValues.tdCls += ' ' + this.disabledCls;
}
if (value === null) {
cellValues.tdCls += ' ' + this.disabledCls;
}
if (value) {
cls += ' ' + cssPrefix + 'grid-checkcolumn-checked';
}
return '<img class="' + cls + '" src="' + Ext.BLANK_IMAGE_URL + '"/>';
}
});
Na czerwono oznaczyłam kod, który został dodany. W metodzie processEvent został dodany warunek, który sprawdza, czy pole powiązane z kolumną ma wartość null. Dzięki temu po kliknięciu w komórkę z checkboxem, nic się nie dzieje. Zmiana w metodzie defaultRenderer odpowiada wyłączenie konkretnego elementu. Jeżeli wartość zmiennej value jest nullem, to do stylu CSS komórki zostaje dodana klasa CSS, która wyszarza element.
Ostatnim etapem jest utworzenie stora i komponentu Tree.
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [
{ text: "Office", leaf: true, isWorking: true },
{ text: "Finances", expanded: true, isWorking: false, children: [
{ text: "Personal", leaf: true, isWorking: null},
{ text: "Corporate", leaf: true, isWorking: false}
] },
{ text: "Legal Department", leaf: true , isWorking: null}
]
}
});
Ext.create('Ext.tree.Panel', {
title: 'CheckColumn Tree',
store: store,
height: 400,
rootVisible: false,
renderTo: Ext.getBody(),
columns: [{
xtype: 'treecolumn',
text: 'Name',
flex: 2,
sortable: true,
dataIndex: 'text'
},{
xtype: 'checkcolumn',
text: 'Working',
flex: 1,
sortable: true,
dataIndex: 'isWorking',
align: 'center',
listeners: {
checkchange: {
fn: function(checkcolumn, rowIndex, checked, eOpts ){ console.log('Row %s checked change', rowIndex); }
}
}
}]
});
W konfiguracji kolumny "checkolumn" w polu dataIndex wpisujemy 'isWorking' (lub inną nazwę pola z konfiguracji modelu dla TreePanel).
Teraz wystarczy, aby serwer w metodzie do wypełniania drzewa zwracał null w wartości konkretnego pola.
Załączonym przykładzie odbywa się to przez ustawienie pola root dla stora.
W produkcyjnej aplikacji oczywiście do stora przypisany byłby konkretny model.
Ważne jest, aby model został skonfigurowany, tak aby przyjmował wartość null (domyślnie, jeżeli serwer zwróci w polu wartość null, zostanie ona zastąpiona przez false). W tym celu w modelu, w konfiguracji pola ustawiamy useNull na true.
Ext.define('MyExampleApp.model.tree.exampleTreeModel', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.Field'
],
fields: [
{
name: 'text',
type: 'string'
},
{
name: 'leaf',
type: 'boolean'
},
{
name: 'expanded',
type: 'boolean'
},
{
name: 'isWorking',
type: 'boolean',
useNull: true
},
]
});
Od teraz wybrane checkboxy w drzewie lub gridzie będą nieaktywne (tak, jak na załączonym zrzucie).
Link do pobrania plików z działającym przykładem: disable-tree-checkcolumn.zip
Brak komentarzy:
Prześlij komentarz