Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
jcbowyer
Frequent Visitor

How to multiSelect with selection manager in power bi custom visual

I am using a kendo multi select in power bi custom visual but it appears that only the first selection is sticking.

My code is below:

 

    $("#myMultiSelect").kendoMultiSelect({
                dataTextField: "value",
                dataValueField: "identity",
                dataSource: viewModel.categories,
                change: function(e) {                 
                    var selectionDeffered = this.value().map(id => selectionManager.select(id, true));                       
                    if (this.value().length == 0)
                    {
                        selectionManager.clear()
                    }
               }
            });

A full gist with the kendo core is here:

https://gist.github.com/jcbowyer/5df55d4758a7614ca08d71eaf640fc57

Is there a simple way to achieve multi-select? I may be making an obvious mistake but the chiclet sample is very complex and uses a different method called selectionhandler. I am unclear how to use selection handler with kendo.

4 REPLIES 4
jcbowyer
Frequent Visitor

I am developing an advanced search custom visual that creates a list of multi select filters based on the categories that the user drags into the visual. Unfortunately, the way that selection manager works creating ids is that it appears to create the ids for the lowest grain of all dimensions/categories added. So for instance, when I select not recommended category in the attached example, instead of selecting the one dimension, the selection manager performs hundreds of selects for the lowest grain of developer. If I choose a broad group for the select, I receive the error: The specified query is too complex to be evaluated as a single statement

 

xxO7c

 

The gist of the current version of my visual is here:

https://gist.github.com/jcbowyer/5df55d4758a7614ca08d71eaf640fc57

How can I resolve this error and support large numbers of dimensions/combinations?

Instead of selecting each data-point's SelectionId, which results in the selection of the intersection of those data-points, you can try composing your own SQExpr(SemanticQuery Expression) objects that describe the selection you want to perform, and pass a SelectionId object made from these objects to the SelectionManager.

 

In order to do so, you can use the data.SQExprBuilder module, which contains various functions that allow you to create simple SQExpr objects(E.g. ones that represent a specific value) and more complex ones(E.g. ones that represent logical operations on provided SQExprs).

 

 

In the hope that I understood the issue you encounter correctly, I believe that the following guidelines should help you overcome it:

1. You want to select data-points that come from different categories, so you don't need to create your own simple SQExpr to represent those data-points. Instead, what you need is to obtain the SQExprs that represent those data points. As you probably know, Power BI provides a DataViewScopeIdentity object for each data-point. The DataViewScopeIdentity object has an "expr" property of the type ISQExpr, which is the SQExpr object you need. Note that since it is of type ISQExpr, you'll have to type-assert it into an SQExpr object.

So if you created two data-point objects, d1 and d2, each having a DataViewScopeIdentity property called"identity" then you'll have to write something like-

 

var d1SQExpr: data.SQExpr = <data.SQExpr>d1.identity.expr;
var d2SQExpr: data.SQExpr = <data.SQExpr>d2.identity.expr;

2. Then, since you want to select accodring to the union of those data-points, you should use the SQExprBuilder.or() method, as follows:

 

 

var d1_or_d2SQExpr = data.SQExprBuilder.or(d1SQExpr, d2SQExpr);

3. Create a DataViewScopeIdentity object from the newly created SQExpr:

 

 

var identity = data.createDataViewScopeIdentity(d1_or_d2SQExpr);

4. Create a SelectionId object using the newly created DataViewScopeIdentity object.

 

5. Select that SelectionId with the selectionManager.

 

Few things to note here:

1. I had to do some trial and error in order to make things work for me using this technique, and you'll probably have to do some as well.

2. The above guidelines might not be tailored exactly to your needs(since I havn't read too much of your code and have no idea what "kendo multi select" is). Therefore, I would recommend you to both check out what other functionality the SQExprBuilder module provides and look for some real-life usage examples in other visuals' source code(For example, you can see a usage example for the SQExprBuilder.between() function in the Timeline custom visual's source).

Thanks so much for your detailed response.  I had already tried a similar approach using

 

	var selectionId = SelectionId.createWithIds.apply(SelectionId, categoryIdentities);

 

I implemented your approach and it seems to work the same as my createWithId options.   However, I may be doing something dumb but this approach does yield an error it just generates the wrong results when multiple items are selected.

 

Perhaps, it is because I am trying to use apply to create the comma delimited list of parameters?  I am not really familar with using apply but I am using it because it was the only way I could figure out to dynamically pass a large number of parameters.

 

	var SQExpr = data.SQExprBuilder.or.apply(data, categoryIdentitiesExpr);
        var identityExpr  = data.createDataViewScopeIdentity(SQExpr);
        var selectionIdExpr = SelectionId.createWithId(identityExpr);

 

So i have now tried this 3 ways, 1) The default granular approach 2) aggregating with SelectionId.CreateWithIds and 3) aggregating with SQExprBuilder.

 

I have updated the public gist with the last approach at:  https://gist.github.com/jcbowyer/5df55d4758a7614ca08d71eaf640fc57

 

I think this could be a really valulable custom visualization for the community if I we could solve this.   If you have some spare time and want to discuss a small part day consulting engagement to help me through this, please pm me.  I would be very grateful and don't know where else to go for expert guidance/help.   Thanks again.

I have several remarks:

First of all, there is absolutely no need to invoke these functions using the apply() method:

The apply() method is used to set the "this" value of the invoked function to the one of the first argument passed to apply.

Both the or() function and the createWithIds() function don't even use their "this" value.

Also, passing a module("data") or a class("SelectionId") to the apply() method as the "thisArg" is wrong for so many reasons.

Another thing to note here is that if the invoked function accepts arguments, then any item in the "argsArray" passed the n-1 index will just be ignored by it(Unless it was specifically designed to handle a varying amount of arguments).

 

The or() function accepts two arguments, so If you want to create an "or" SQExpr between all items in an SQExpr objects collection, you should do something like this-

 

var myOrExpr = exprs[0];
for (var i = 1; i < exprs.length; i++) {
   myOrExpr = data.SQExprBuilder.or(myOrExpr, exprs[i]);
}

 

Note: This example is a bit simplified. You may have to type-assert the SQExprs(E.g. <data.SQExpr>expr) so you won't get compiler errors.

 

The SelectionId.createWithIds() method only accepts two DataViewScopeIdentityObjects as arguments and an optional highlight boolean value, so if you pass it an array of DataViewScopeIdentity objects in the apply() method, only the first two will be used, and if there is a third one, it will set the highlight boolean to true/false, depending on its value. The rest will be ignored.

The SelectionId class has no create method that accepts more than two DataViewScopeIdentity objects. Fortunately for you, you can also create an instance of this class by using the "new" keyword. The class' constructor, declared as follows-

 

constructor(selector: Selector, highlight: boolean);

accepts a Selector object as its first argument. The Selector interface defines a property called "data" of type DataRepetitionSelector[], which is an array of DataRepetitionSelector objects, which is a type defined as follows-

 

export type DataRepetitionSelector = DataViewScopeIdentity | DataViewScopeWildcard | DataViewRoleWildcard;

meaning that you can set its value to an array of DataViewScopeIdentity objects of any reasonable size.

 

Note: I noticed that order has a meaning when settings this array(I.e. different order results in different selection behavior), so keep that in mind.

 

Regarding the consulting engagement, I appreciate the offer, but unfortunately I don't have enough spare time to commit to this project at the moment(And also, I don't regard myself as an expert...). But feel free to ask more questions in the community if you encounter any more problems. I usualy try to help where I can.

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.