Идея
По моим наблюдениям, Advanced mode фильтрации сразу осваивают процентов 10 пользователей. Остальные предпочитают пользоваться группами или простыми фильтрами.Предлагаю расширить быструю фильтрацию и упростить её использование, чтобы каждый пользователь (или администратор на всех) мог настроить в любом разделе, какие поля объекта использовать для быстрой фильтрации. Таким образом, верхняя строка не будет так перегружена (что сейчас иногда бывает в разделе Activity, например), а пользователь получит расширенный, более простой и быстрый инструмент для простой фильтрации.
Одобрена
2 комментария

Маловата картинка - увеличу

Здравствуйте, Владимир!

Я передал Ваше пожелание аналитикам продукта, на рассмотрение возможности внедрения в будущих релизах приложения.

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Иногда и такое нужно. Как пример -- есть окно с несколькими гридами на основе записей меморидатасет. Записей много -- поэтому у клиента возникает необходимость их быстро искать.
Сам фильтр сложно реализовать(потому что при закрытии, как известно, меморидатасет очищается. тем более, если функционал сложный, то при "собирании заново" тратится время на проверку всех условий и т.п.), но можно сделать иначе: просто выделять нужные записи.

Как это работает -- ищет по полям, где содержится слово, введенное в поле (то есть, принцип тот же, что и в обычном поиске, тип поиска можно поменять в системных настройках) -- и выделяет найденные записи. При нажатии на "крестик"(то есть "убираем" быстрый поиск) оно снимает выделение.

Этот код можно добавить прямо в скрипт scr_BaseMemDSGridArea, а в окошке wnd_BaseMemDSGridArea прописать на гриде события grdDataOnQuickFilter (запуск быстрого фильтра) и grdDataOnClearFilter (снятие быстрого фильтра).
Еще момент -- код "ориентируется" на поле ID в мемори датасете, поэтому, если у Вас такого поля нет, то нужно или добавить его, или соответствующе изменять функции.

//-------- quick filter  --------------

function grdDataOnQuickFilter(DataGrid, DataField, Value, QuickFilterLikeType, DoFilter, DoQuickFilter) {
        DataGrid.DisableEvents();  //debugger;
        var QuickFilterLikeType = GetSystemParameterValueEx('QuickFilterLikeType');            
        LastSearchRecordID = LocateOnSearchRecord(DataGrid, dlData.Dataset,DataField.Name,Value,QuickFilterLikeType);
        DataGrid.EnableEvents();
        if (!!LastSearchRecordID) {
                if (dlData.Dataset('ID') != LastSearchRecordID) {
                        DataGrid.UnSelectRow(dlData.Dataset('ID'));
                }
        } else {
            DataGrid.UnSelectRow(dlData.Dataset('ID'));
        }
}



function LocateOnSearchRecord(Grid, DS, DataFieldName, DataFieldValue, FilterType) {
        //debugger;
        var Count = DS.RecordsCount;
        if (!Count) {
                return;
        }      
        var SelectedIDsCount = Grid.SelectedIDs.Count;
        if (!!SelectedIDsCount) {
                Grid = UnSelectSelectedIDs(Grid);
        } else {    
                 Grid.UnSelectRow(DS('ID'));
        }
        DS.GotoFirst();
        var SearchArray = new Array();
        for (var i = 0; i Count; i++) {
                if (IsSearchValueInCurrentDSRecord(DS,DataFieldName,DataFieldValue, FilterType)) {
                         SearchArray.push(DS('ID'));
                }
                DS.GotoNext(); 
        }
        var LastSearchRecordID = null;
        if (!!SearchArray.length) {
                SelectSearchRecords(Grid, SearchArray);
                LastSearchRecordID = SearchArray[SearchArray.length - 1];
        }
        return LastSearchRecordID;
}

function  UnSelectSelectedIDs(Grid) {           //
        var Count = Grid.SelectedIDs.Count;
        var SelectedIDs  =  GetArrayByCollection(Grid.SelectedIDs);
        for (var i=0; i Count; i++) {
                Grid.UnSelectRow(SelectedIDs[i]);
        }
        return  Grid;
}
function IsSearchValueInCurrentDSRecord(DS,DataFieldName,DataFieldValue, FilterType) {   //debugger;
        var CurrentDataFieldValue = DS(DataFieldName);
        CurrentDataFieldValue = CurrentDataFieldValue.toString();
        DataFieldValue = DataFieldValue.toString();
        var Result = false;
        switch (FilterType.toString()) {
                case qfltEqual:
                        Result = (CurrentDataFieldValue == DataFieldValue);     //поле равно значению
                break;         
                case qfltDefault:
                case qfltContain:
                        Result = (CurrentDataFieldValue.indexOf(DataFieldValue) != -1);  //значение содержится в поле
                break;
                case qfltStartsWith:
                        Result = (CurrentDataFieldValue.substr(0,DataFieldValue.length) == DataFieldValue);  //поле начинается со значения
                break;          
                case qfltEndsWith:
                        Result = (CurrentDataFieldValue.substr(CurrentDataFieldValue.length-DataFieldValue.length+1, DataFieldValue.length) == DataFieldValue);  //поле заканчивается значением
                break;
        }
        return Result;
}

function SelectSearchRecords(Grid, SearchArray) {
        for (var i=0; i SearchArray.length; i++) {
                Grid.SelectRow(SearchArray[i]);
        }
}

function grdDataOnClearFilter(DataGrid) {
        DataGrid.DisableEvents();
        UnSelectSelectedIDs(DataGrid)  ;
        DataGrid.EnableEvents();
}

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Мы часто пользуемся быстрым фильтром и привыкли к такой удобной функциональности. Но при работе в деревом такой функциональности нет.
Привожу пример, как, с моей точки зрения, возможна реализация функциональности быстрого фильтра в дереве. Это только один из возможных вариантов. Вы можете предложить большее.

Мельникова Екатерина на эту тему даже создала идею: community.terrasoft.ua/node/3032.
Главная идея - дерево может находится в двух режимах - дерево и список. При работе с деревом фильтрация невозможно. При работе со списком - мы можем осуществлять поиск нужной нам записи, и при переключении обратно в режим дерева мы позиционируемся на найденной записи.

Основа - режим переключения из дерева в список. В приведенном примере переключение между деревом и списком осуществляется по горячей клавише Ctrl-Q. Включение / отключение фильтра осуществляются по горячей клавише Ctrl-S.

Открываем окно с DataTreeGrid (в данном примере отображены все папки из директория "Program Files", Вы можете загрузить подобную структуру по кнопке "Загрузить папки из директория"):
Дерево для поиска

Допустим, в дереве Вам необходимо найти библиотеку картинок программы Skype. В поле ввода быстрого фильтра набираем текст "Skype" и нажатием Ctrl-S включаем бытрый фильтр, который будет включен при переходе в режим отображения список.
Ввод параметров быстрого фильтра

Переключение просмотра в режим "Список" нажатием Ctrl-Q, после чего можно выбрать необходимую запись:
Переключение в режим

После того, как Вы нашли искомую запись - переключаемся в режим просмотра "Дерево" (Ctrl-Q):
Переключение в режим дерево и позиционирование на найденной записи

Пример сервисов для работы быстрого фильтра в дереве Вы можете найти в присоединенном архиве TreeQuickFilter_Example.rar.

Основные моменты реализации:

Переключение режима "Дерево / Список" осуществляется подстановкой значения свойства "ParentDataFieldName" компонента DataTreeGrid поля "ParentID" если мы хотим видеть дерево или "ID", если нам нуже список (в данном случае возможно переключение без перезапроса данных в базе данных):

function SwitchTreeListViewType() {
        var ParentDataFieldName = grdData.ParentDataFieldName;
        if (ParentDataFieldName == 'ParentID') {
                grdData.ParentDataFieldName = 'ID';
                cbQuickFilter.IsEnabled = true;
        } else {
                grdData.ParentDataFieldName = 'ParentID';
                cbQuickFilter.IsEnabled = false;
        }
        UpdateQuickFilter();
}

Выбор директория для загрузки в таблицу структуры папок:

function LoadFoldersFromDirectory() {
        var FolderNameObject = System.CreateObject('TSObjectLibrary.Value');
        if ((System.SelectDirectory("Выберите папку", '', FolderNameObject))) {
                var FolderName = FolderNameObject.Value;
                var Dataset = dlData.Dataset;
                LoadDirectoryItemsFromFolder(FolderName, Dataset);
        }
}

Загрузка структуры директория осуществляется с помощью рекурсивной функции:

function LoadDirectoryItemsToDataset(Path, Dataset, ParentID) {
        try {
                var Folder = FileSearchGridArea.FSO.GetFolder(Path);
                var Folders = new Enumerator(Folder.SubFolders);
                for (Folders.moveFirst(); !Folders.atEnd(); Folders.moveNext()) {
                        var Item = Folders.item();
                        var Name = Item.Name;
                        var Path = Item.Path;
                        var ID = AddFolderToDataset(Dataset, ParentID, Name, Path);
                        LoadDirectoryItemsToDataset(Path, Dataset, ID);
                }
        } catch(e) {
                ShowErrorDialog(e.message);
        }
}

Обработка горячих клавиш осуществляется в событии OnKeyDown DataTreeGrid:

function DoKeyDown(Control, Key, Shift) {
        var CtrlDown = (Shift & 4) > 0;
        if (CtrlDown) {
                var QKeyCode = 81;
                if (Key.Value == QKeyCode) {
                        SwitchTreeListViewType();
                }
                var SKeyCode = 83;
                if (Key.Value == SKeyCode) {
                        cbQuickFilter.IsChecked = !cbQuickFilter.IsChecked;
                }
        }
}

Данный вариант работы с деревом имеет свои ограничения:

    * Он быстро работает, когда количество записей не больше нескольких тысяч.
    * Когда не используется режим подгрузки узлов дерева по требованию.

Конечно, реализовывать такое в конфигурации трудоемко, но можно. Лучшим решением было бы реализовать быстрый фильтр в ядре в компоненте DataTreeGrid.

Используйте на здоровье.

Поделиться

5 комментариев

Автору - спасибо!
Разработчикам - быстрый фильтр в ядре для компоненты DataTreeGrid!

--
γνῶθι σεαυτόν

А в чем сложности при организации подгрузки узлов дерева по требованию? И с большими объемами бы тогда работалось нормально.

Есть несколько способов построения дерева. В данном примере я использую загрузку полного дерева на сторону клиента. Если в отфильтрованной выборке быстрого фильтра Вы нашли запись, то при следующем построении дерева мы спозиционируемся на нее в дереве и увидим, где именно в дереве находится наша запись.

При большом количестве записей данный вариант не подходит. В таком случае применяют режим загрузки по требованию. В таком режиме при раскрытии узла дерева, если узел еще не был подгружен, идет запрос в базу данных для формирования выборки всех записей, которые являются подчиненными раскрывающимся узлу и дерево формируется по мере раскрытия. Для такого варианта поиск необходимой записи останется таким же как в приведенном примере, а для отображения записи в дереве необходимо применить другой механизм - либо в выборке выбирать все записи по иерархии от найденной до самого верхнего уровня, либо по иерархии принудительно открывать все узлы от родительского до найденного узла.

В данном примере такая задача не решается. Это я и поразумевал фразой "Вы можете предложить большее".

Спасибо. Пригодилось!

Мне тоже пригодилось. Спасибо :smile:

Войдите или зарегистрируйтесь, чтобы комментировать