Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filtering based on unique values of dynamic properties of the model #67

Open
Letrab opened this issue Jul 17, 2019 · 1 comment
Open

Comments

@Letrab
Copy link

Letrab commented Jul 17, 2019

What would be the most efficient/appropriate way to achieve a model based on the contents of the model itself.
To give an example what I try to achieve: https://www.amazon.com/s?i=electronics-intl-ship&bbn=16225009011&rh=n%3A%2116225009011%2Cn%3A1266092011%2Cn%3A172659&dc&fst=as%3Aoff&qid=1563278627&rnid=1266092011&ref=sr_nr_n_13

Eg: Having a list of "products" which have properties like: "brand", "type", "size" , ...
I would like to be able to filter them based on the contents of these properties.
This should be performed dynamically, as I am not aware of all possible values/categories available.
Also, values may change as filters are being applied dynamically.

Do you have a suggestion on how to achieve this?
I can iterate through the resulting Proxy Model, making a list per property containing all its unique values (and count, to sort).
With this list I could generate QML CheckBoxes, and create ValueFilter's on the fly?

Not sure though if this is the most memory efficient/performant though.

Thanks!

@Letrab
Copy link
Author

Letrab commented Jul 17, 2019

Answer from @oKcerG via email:

There are two problems to solve for your usage that are not supported by the SFPM lib

The first one is getting unique values for the different fields of your model. I've already thought about this one but I believe it is out of scope of my lib.
The solution would need to listen for changes in the model (rowInserted/Removed, dataChanged, ...) and either iterate through the model each time or maintain a local representation of the role it should track.

A possible api would look like:

UniqueModel {
    id: uniqueBrandModel 
    sourceModel: productModel
    roleName: "brand"
}

With UniqueModel being a QAbstractListModel (making it a QAbstractProxyModel doesn't make much sense from my perspective, there won't be any mapping) exposing a single role (value, it could also alias the passed roleName to it) with a row for each unique value.
You could alternatively make it a single object, exposing a list or model for each role of the sourceModel, but I feel that it is less flexible.

The other problem is adding ValueFilters dynamically to the SFPM.
That's a solution I plan to support (although I don't have much time now to work on the lib).

If you want to implement it, I don't mind a PR :)

The way I see it, there are 4 possibles API:
1.

Instantiator {
    model: roleNames
    ValueFiter {
        roleName: modelData
        container: filterContainer // new property; should work with proxyModel and any other filter containers like AnyOf or SwitchRole; maybe limit writing to this property to Filters created outside a SFPM to avoid edge cases?
    }
}
Instantiator {
    model: roleNames
    ValueFiter {
        roleName: modelData
        FilterContainer.container: filterContainer // new attaching type with attached property. similar behaviour to the above property. Can maybe ease the coding logic and has the advantage of not adding container logic in the Filter
    }
}
Instantiator {
    model: roleNames
    ValueFiter {
        roleName: modelData
    }
    onObjectAdded: filterContainer.appendFilter(object) // new to expose this method
    onObjectRemoved: filterContainer.removeFilter(object)
}
SortFilterProxyModel {
    // ...
    FilterRepeater { // too complex to implement, not flexible enough I believe 
        model: roleNames
        ValueFiter {
            roleName: modelData
        }
    }
    // ...
}

From a theroical point of view, I prefer solution 2 with the attached property. It doesn't make the filter aware of its container.
It has some drawbacks compared to 1, attached property vs normal property syntax and it instantiates another QObject.

3 is maybe the simplest to do, if you want to do this internally (not contributing it), and don't care about supporting edge cases, I guess that's what I would recommend.
I'm not a fan of the imperative API though.

4 is too hard and not flexible enough.

In your use case you might want to have a Repeater of ComboBox, and instantiate a ValueFilter in each ComboBox, 1, 2, 3 can do that (3 with ugly Component.onCompleted/onDestruction). With 4 you can't. You'd have to have a Repeater of ComboBox and a FilterRepeater of ValueFilter, and somehow link them.

If your list of roles is not know in advance, you can use my QmlModelHelper lib to query it : https://github.com/oKcerG/QmlModelHelper (look at the tests to figure out what it does, or read this unfinished readme : https://gist.github.com/oKcerG/eeea734bdacc51b3ae58650de5f05943 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant