qtlistviewmodelqmlsailfish-os

QML: Update a nested ListView


I'm making a TV-Guide on Sailfish OS, and have met an - for now - obstacle. As I want to have the possiblity to mark each entry for a customized list I need to modify the model behind. I have tried modifying the model directly: model.favorite = true but that doesn't work. I have tried to modify the underlying arrayOfObjects, but that isn't reflected in the UI, and I can't trigger an update because I can't access the ListView. I have tried to make a customized model, but since I can't reference it's instance, to no avail.

Below is a very simplified representation of the layout using mostly basic QML.

Page {
    Flickable {
        Column {
            SlideshowView { // PathView
                model: arrayOfObjects
                delegate: channelDelegate
            }
        }
    }

    Component {
        id: channelDelegate
        ListView {
            id: channelList
            // ProgramModel just iterates thru arrayOfObjects and appends them
            model: ProgramModel {
                programs: arrayOfObjects
            }
            delegate: programDelegate
            Component.onCompleted: {
                // I can't reference channelList from here.
            }
        }
    }

    Component {
        id: programDelegate
        ListItem {
            Button {
                onClicked: {
                    // How do I reference channelList?
                    // Doing it by name doesn't work.
                }
            }
        }
    }
}

I have tried calling ApplicationWindow (which works), to send a signal that I connect to in channelList.onCompleted (which also works), but since I can't reference the list from there it doesn't help.

I'm on QT 5.6 so some solutions may not work. And I would really prefer keeping it pure QML; no C++.


Solution

  • I can't reproduce your case exactly, but maybe this quick example help you somehow.

    import QtQuick 2.6
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.2
    
    Window {
        id: mainWrapper
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        signal updateModel(int id, string name)
    
        Component {
            id: listWrapper
    
            ListView {
                id: list
    
                model: [
                   { name: "name0" },
                   { name: "name1" },
                   { name: "name2" }
               ]
    
                delegate: Loader {
                    width: parent.width
                    property variant model: modelData
                    property int modelIndex: index
                    sourceComponent: listDelegate
                }
    
                function updateModelName(id, name) {
                    var listModel = list.model
                    listModel[id].name = name
                    list.model = listModel
                }
            }
        }
    
        Loader {
            id: loadedList
            x: 0
            anchors.fill: parent
            sourceComponent: listWrapper
    
            Component.onCompleted: {
                mainWrapper.updateModel.connect(loadedList.item.updateModelName)
            }
        }
    
        Component {
            id: listDelegate
    
            Rectangle {
                id: listRow
                width: 200
                height: 80
                Text {
                    text: model.name
                }
    
                Button {
                    x: 100
                    text: "update"
                    onClicked: {
                        mainWrapper.updateModel(modelIndex, "better_name"+modelIndex)
                    }
                }
            }
        }
    }
    

    The clue of this example is to use signal and function to update model.