Search code examples
qtlistviewqmlqt5repeater

Access ListView model within the Repeater component in the delegate


I am using a ListView with a model and a delegate.

The model is a simple ListModel with three items. Each item has a value with the key myFirstRole.

The delegate contains a Repeater component to create an arbitrary number of Labels. The Labels have to use data from the model.

The model of the repeater can not be set to the Listview's model as I have the Repeater using other data.

Here is a minimal example of what I am trying to achieve:

//MyDelegate.qml
Component {

    Item {
        id: root

        width: childrenRect.width
        height childrenRect.height

        Repeater {
            model: 5 //It's not an option to set the repeaters model to the ListViews model. This example just illustrates my problem.

            Label {
                text: root.ListView.view.model.myFirstRole //This is the line where I want to be able to access the ListView's model, but I can't figure out how to properly reefer to it.
            }
        }
    }
}

//MyListView.qml
ListView {
    id: root

    delegate: MyDelegate {}
    model: ListModel {
        ListElement {
            myFirstRole: "one"
        }
        ListElement {
            myFirstRole: "two"
        }
        ListElement {
            myFirstRole: "three"
        }
    }
}

Using Qt 5.7.0 with MSVC2015 32bit


Solution

  • I think that you can't access the roles via the special model property mentioned here (which is what I'm assuming you were trying to do) from the scope of the Repeater. Instead, you can declare a property at the root level of the component that can then be used in nested scopes:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
    
        ListView {
            anchors.fill: parent
            model: ListModel {
                ListElement { myFirstRole: "Dog" }
                ListElement { myFirstRole: "Cat" }
            }
    
            delegate: Item {
                id: root
    
                width: childrenRect.width
                height: childrenRect.height
    
                property string myFirstRoleData: myFirstRole
    
                Repeater {
                    model: 5
    
                    Text {
                        text: myFirstRoleData
                    }
                }
            }
        }
    }
    

    This might get a bit tedious if you have a lot of properties though. From some quick playing around, it looks like it's also possible to store the entire model object in a property:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
    
        ListView {
            anchors.fill: parent
            model: ListModel {
                ListElement { myFirstRole: "Dog" }
                ListElement { myFirstRole: "Cat" }
            }
    
            delegate: Item {
                id: root
    
                width: childrenRect.width
                height: childrenRect.height
    
                property var modelData: model
    
                Repeater {
                    model: 5
    
                    Text {
                        text: root.modelData.myFirstRole
                    }
                }
            }
        }
    }
    

    modelData is probably not the best name to use though, seeing as Qt uses that name for models with only one role, but... if you're going with this approach, you're gonna have more than one role anyway. :)

    It looks like Qt Quick Controls' (1) Tumbler does this too.