Home > Back-end >  ListView.view is always null in ListView's delegate
ListView.view is always null in ListView's delegate

Time:11-04

The setup

I have a ListView with some general model and myDelegate component.

ListView {
    id: myListView
    delegate: myDelegate
    ...
}

In myDelegate component, I want to set ListView's currentItem. I currently do it like this:

Component {
    id: myDelegate
    ...
    MouseArea {
        onClicked: myListView.currentIndex = model.index
    }
}

Everything works as expected.

The issue

As commonly known, it's bad practice to use ListView's id inside a delegate, since there could be multiple ListView using the same delegate component. So, ListView.view attached property should be used instead.

But if I change the delegate's code like this:

Component {
    id: myDelegate
    ...
    MouseArea {
        onClicked: ListView.view.currentIndex = model.index
    }
}

I get a TypeError: Value is null and could not be converted to an object.

With the following console.logs, I discovered that ListView.view is always null. I don't understand why. Setting currentIndex on ListView itself fails too.

onClicked: {
    console.log("ListView:", ListView)
    console.log("ListView.view:", ListView.view)
    console.log("ListView.currentIndex:", ListView.currentIndex)
}
...
qml: ListView: QQuickListViewAttached(0x6db0b30)
qml: ListView.view: null
qml: ListView.currentIndex: undefined

Minimal reproducible example

Qt v6.2.1
Empty Qt Quick project in Qt Creator
main.qml:

import QtQuick
import QtQuick.Window

Window {
    width: 150
    height: 350
    visible: true

    Component {
        id: myDelegate

        Rectangle {
            color: ListView.isCurrentItem ? "pink" : "lightblue"
            implicitWidth: 150
            implicitHeight: 50

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    ListView.view.currentIndex = model.index
                    console.log("ListView", ListView)
                    console.log("ListView.view", ListView.view)
                }
            }

            Text {
                anchors.centerIn: parent
                text: model.index
            }
        }
    }

    ListView {
        id: myListView
        anchors.fill: parent
        spacing: 2
        model: 6
        delegate: myDelegate
    }
}

CodePudding user response:

The attached properties are set in the root of the delegate so if you want to access from a child item then you must use the root as reference:

    Component {
        id: myDelegate

        Rectangle {
            id: root_delegate // <---

            color: ListView.isCurrentItem ? "pink" : "lightblue"
            implicitWidth: 150
            implicitHeight: 50

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    root_delegate.ListView.view.currentIndex = model.index;
                    console.log("ListView", root_delegate.ListView);
                    console.log("ListView.view", root_delegate.ListView.view);
                }
            }

            Text {
                anchors.centerIn: parent
                text: model.index
            }

        }

    }
  • Related