Multiple filter string search on RadDropDownTree

1 Answer 115 Views
DropDownTree Filter
Clark
Top achievements
Rank 1
Iron
Iron
Clark asked on 21 Dec 2021, 10:10 PM | edited on 31 Mar 2022, 12:30 AM

Hello,

I want to filter my RadDropDownTree using multiple strings delimited by a space.

I have modified a script but it isn't working quite right.

Note the pic below.  I want to match on both "balances" and "sspro" or "ssedge" or "ss.com"

 

When I add a space and an "s" then nothing is retrieved:

 

 

However, when I type in "balances t" I get some results but actually should get all lines that have "balances" and "t".  There should be a lot more results:

 

Here is the script I'm using:


 var $T = Telerik.Web.UI;
    Telerik.Web.UI.RadDropDownTree.Manager.prototype._filterNodes = function (text) {
        var nodes = this._embeddedTree.get_allNodes(),
            count = nodes.length,
            regEx,
            i;

       
        var EnteredText = text.split(" ");

        if (EnteredText[1] == null) {

            EnteredText[1] = "";
        }

        if (this._filter == $T.DropDownTreeFilter.StartsWith)
           /* regEx = new RegExp("^\\s*" + $T.RadDropDownTree.Manager._regExEscape(text), "im");*/
            regEx = new RegExp("^\\s*(?=.*" + EnteredText[0] + ")(?=.* " + EnteredText[1] + ").*$", "im");
        else
           /* regEx = new RegExp($T.RadDropDownTree.Manager._regExEscape(text), "gim");*/
            regEx = new RegExp("^(?=.*" + EnteredText[0] + ")(?=.* " + EnteredText[1] + ").*$", "gim");

       /* alert(regEx);*/

        for (i = 0; i < count; i++) {
            var currentNode = nodes[i];
            var matchIsFound;

            if (currentNode.get_level() !== 2)
            {
                matchIsFound = false;
                /*alert(currentNode.get_text());*/
            }
            else
            {                
                matchIsFound = this._matchNode(currentNode, EnteredText, regEx);
              //  alert(currentNode.get_text());

            }
            if (matchIsFound)
            {
                this._handleVisibleParents(currentNode);
                this._filteredVisibleNodes.push(currentNode);
            }
            else
            {
                this._handleHiddenNode(currentNode);
            }
        }

        this._hideNodes(this._filteredHiddenNodes);
        this._showNodes(this._filteredVisibleNodes);

        this._filteredVisibleNodes = [];
        this._filteredHiddenNodes = [];
    }

    

Thanks!

--Clark

Clark
Top achievements
Rank 1
Iron
Iron
commented on 22 Dec 2021, 08:28 PM | edited

To clarify, here is what the script isn't doing that it should be doing.:

  1.   EnteredText[1] appears to be applied as "StartsWith" rather than a "Contains" like EnteredText[0]
  2.   EnteredText[1] doesn't search the first level like EnteredText[0] does:  Example:  First: Second: Third.  Text entered in EnteredText[1] only searches Second and Third, not First

In summary, EnteredText[1] isn't doing what EnteredText[0] is doing.

Thanks!

--Clark

 


Peter Milchev
Telerik team
commented on 24 Dec 2021, 09:56 AM

Hi Clark, the issue you have with the hardcoded logic is that you only allow two parameters. What I can recommend is just splitting the search string by a space and you would have an array of strings. 

Then, you would check the node for each of the search strings and if even one filter matches, you would set the matchIsFound=true

if (currentNode.get_level() !== 2)
            {
                matchIsFound = false;
                /*alert(currentNode.get_text());*/
            }
            else
            {     
                // no need to use complex regEx and internal matchNode (unless the highlight is needed)           
                //matchIsFound = this._matchNode(currentNode, EnteredText, regEx);
              //  alert(currentNode.get_text());
                 // iterate each filter string and check if the currentNode's text contains it
                 // if it does, set the matchIsFound and break the loop
            }

Clark
Top achievements
Rank 1
Iron
Iron
commented on 03 Jan 2022, 09:46 PM

Hi Peter,

Thanks!  I'm  now working on implementing it.

Will let you know how it goes.  :-)

--Clark

 

 

Clark
Top achievements
Rank 1
Iron
Iron
commented on 04 Jan 2022, 03:14 PM | edited

Hey Peter,

I implemented it and ran in to two issues, mostly due to me not being clear on my preferences.

The two issues are:

1.  I'm only searching the node text and want to also search the "hiddenContent" label

2.  I want an "AND" not an "OR" for multiple filter strings

For the "hiddenContent", my control is set up like this:

<telerik:RadDropDownTree ID="CatRadDropDownTree" runat="server" AutoPostBack="false" OnEntryAdded="CatRadDropDownTree_EntryAdded" FilterSettings-MinFilterLength="3"
    DefaultMessage="Please select" ExpandNodeOnSingleClick="True" Skin="Default" TextMode="FullPath" FullPathDelimiter=": " CheckNodeOnClick="true"
    EnableFiltering="True" CollapseAnimation-Duration="0" ExpandAnimation-Duration="0" OnNodeDataBound="CatRadDropDownTree_NodeDataBound"  >
     <ButtonSettings ShowCheckAll="true" ShowClear="false" />
            <Localization Clear="Clear All" />
    <DropDownSettings OpenDropDownOnLoad="false" CloseDropDownOnSelection="false" AutoWidth="Enabled" Height="300px" />
    <FilterSettings Highlight="Matches" EmptyMessage="Type here to filter" FilterTemplate="ByContent" Filter="Contains" />
    <DropDownNodeTemplate>
        <div class="nodeTemplate">
            <span>
                <%# DataBinder.Eval(Container, "Text") %>
            </span>
            <asp:Label Text="" ID="hiddenContent" CssClass="hiddenContent" runat="server" />
        </div>
    </DropDownNodeTemplate>
</telerik:RadDropDownTree>

As a note, this line which is in the original script I posted does search both the node text and the hiddenContent:

matchIsFound = this._matchNode(currentNode, EnteredText, regEx);

Can the "regEx = new RegExp("^\\s*" + $T.RadDropDownTree.Manager._regExEscape(text), "im")" line be modified to include multiple search strings that imply an "AND"?

For the "OR vs. AND" question, I want to find all nodes that contain multiple filter strings.

Example of filter:  Web Trade Mobile

In this case I want all nodes where the node text + hiddenContent contain all 3 of the above terms.

The idea is the more users type, the less results they should see as they add to the filter.

That's pretty much it.

Thanks for your help Peter!

--Clark

 

 

 

 

 

Clark
Top achievements
Rank 1
Iron
Iron
commented on 04 Jan 2022, 06:54 PM

I made a little progress.  What this will do is find account OR mobile.

I want it to be AND.

I tried & and && but that didn't work.

 if (this._filter == $T.DropDownTreeFilter.StartsWith)
            regEx = new RegExp("account|mobile", "im");
        else
            regEx = new RegExp("account|mobile", "gim");

 

Clark
Top achievements
Rank 1
Iron
Iron
commented on 06 Jan 2022, 03:47 PM | edited

Hey Peter,

I believe I have it working. 

var $T = Telerik.Web.UI;
    Telerik.Web.UI.RadDropDownTree.Manager.prototype._filterNodes = function (text) {
        var nodes = this._embeddedTree.get_allNodes(),
            count = nodes.length,
            regEx,
            i;


        var TextEntered = text.split(" ");

        var Exp0 = "";

        if (this._filter == $T.DropDownTreeFilter.Contains) {

            for (icount = 0; icount < TextEntered.length; icount++)
            {
                var Exp = "^\\s*(?=.*" + TextEntered[icount] + ")";

                var Exp0 = Exp0 + Exp;

                regEx = new RegExp(Exp0 + ".*$", "gim");
               
            }
        }

        //Original section
        //if (this._filter == $T.DropDownTreeFilter.StartsWith)
        //    regEx = new RegExp("^\\s*" + $T.RadDropDownTree.Manager._regExEscape(text), "im");
        //else
        //    regEx = new RegExp($T.RadDropDownTree.Manager._regExEscape(text), "gim");


        for (i = 0; i < count; i++) {
            var currentNode = nodes[i];
            var matchIsFound;

            if (currentNode.get_level() !== 2) {
                matchIsFound = false;


            }
            else {

                matchIsFound = this._matchNode(currentNode, text, regEx);

            }
            if (matchIsFound) {

                this._handleVisibleParents(currentNode);
                this._filteredVisibleNodes.push(currentNode);
            }
            else {
                this._handleHiddenNode(currentNode);
            }
        }


        this._hideNodes(this._filteredHiddenNodes);
        this._showNodes(this._filteredVisibleNodes);

        this._filteredVisibleNodes = [];
        this._filteredHiddenNodes = [];
    }  

Do you have any thoughts about this approach?

Thanks!

--Clark

 

 

 

Peter Milchev
Telerik team
commented on 07 Jan 2022, 10:42 AM

Hi Clark, this seems like a good approach, you can use it if it meets your requirements.

Another simpler approach would be to make a manual check for each of the "TextEntered" entries if they are contained inside the texts of the node, without RegEx. To make it case insensitive, you can use the toLowerCase() method for both the text and the filter strings.

That would save you the RegEx build and you might skip the built-in _matchNode method and determine yourself if a match is found.

 

Clark
Top achievements
Rank 1
Iron
Iron
commented on 07 Jan 2022, 02:52 PM | edited

Hi Peter,

I would use your method except I'm not just comparing against the text of the nodes.  I'm also comparing against the "hiddenContent" label that's integrated by using the nodeTemplate attribute in the control itself (see a couple blocks up for my dropdown control in my aspx).

If you can tell me how to search both the node text and the hiddenContent I'm all ears!

Thanks so much for your on-going support.  

--Clark

 

Peter Milchev
Telerik team
commented on 12 Jan 2022, 02:56 PM

Hi Clark, You can search based on all properties and elements of the node. To make them easier to search, you can wrap the elements or text with a <span> and add some custom CSS class, e.g. searchable-field:

<DropDownNodeTemplate>
    <div class="nodeTemplate">
        <span class="searchable-text-field">
            <%# DataBinder.Eval(Container, "Text") %>
        </span>
        <asp:Label Text="" ID="hiddenContent" CssClass="hiddenContent searchable-hidden-field" runat="server" />
    </div>
</DropDownNodeTemplate>

var $contentElement = $telerik.$(currentNode.get_contentElement());
var textFieldText = $contentElement.find(".searchable-text-field").text().trim();
var hiddenFieldText = $contentElement.find(".searchable-hidden-field").text().trim();

Clark
Top achievements
Rank 1
Iron
Iron
commented on 19 Jan 2022, 06:12 PM

Thanks Peter!  Let me try to implement that.

1 Answer, 1 is accepted

Sort by
0
Accepted
Clark
Top achievements
Rank 1
Iron
Iron
answered on 31 Mar 2022, 12:39 AM
This has already been answered by Peter Milchev.
Tags
DropDownTree Filter
Asked by
Clark
Top achievements
Rank 1
Iron
Iron
Answers by
Clark
Top achievements
Rank 1
Iron
Iron
Share this question
or