Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Defining a function in ListElement - Not working with append



  • Hi all,

    I want to assign a function declaration to a role in a ListElement in a ListModel. I understand from the docs that this has been allowed since 5.11. "Beginning with Qt 5.11 ListElement also allows assigning a function declaration to a role. This allows the definition of ListElements with callable actions." - ListElement QML Type

    Searching around I found a few places where people were having issues with this, including:
    https://stackoverflow.com/questions/50622945/calling-javascript-object-method-from-qml-listview-delegate/
    https://bugreports.qt.io/browse/QTBUG-80041
    https://forum.qt.io/topic/95918/problem-dynamically-adding-items-in-a-listmodel

    My current findings are:

    1. Defining function as a role inside a ListElement declaration works
    2. Defining function inside JS object that is appended to ListModel, does not work
    3. From this forum post, adding function as a role to existing ListElement by using setProperty works

    Here is some sample code (portions borrowed from links above) that tries to illustrate the scenarios. Item 1 and Item 3 work. Item 2/Scenario 2 gets the following error: Can't assign to existing role 'func' of different type [VariantMap -> Function].

    If you comment out the first and third ListElement declarations, this error doesn't happen. But the typeof model.func == object and not function. And I'm not sure if there's a way to invoke the function or define it differently so that it would be invocable.

    Any thoughts?

    import QtQuick 2.14
    import QtQuick.Controls 2.14
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("TestListElement")
    
        ListView {
            id: myListView
            anchors.fill: parent
            spacing: 2
            model: ListModel {
                id: myListModel
                ListElement {
                    name: "Item 1"
                    func: function(){ console.log("Item 1 clicked"); }
                }
            }
            Component.onCompleted: {
                myListModel.append({ name: "Item 2", func: function (){ console.log("Item 2 clicked");} });
    
                myListModel.append({ name: "Item 3"});
                myListModel.setProperty(myListModel.count-1, "func", function (){ console.log("Item 3 clicked");});
            }
    
    
            delegate: Rectangle {
                height: 30
                color: "#EFEFEF"
                border { width: 1; color: "#CCC" }
                width: parent.width
                Text {
                    text: name
                    anchors.centerIn: parent
                }
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        if(typeof model.func === "function")
                            model.func();
                        else
                            console.error("Click handler not defined. Func typeof == " + typeof model.func);
                    }
                }
            }
        }
    }
    


  • @bkeller came here looking for a example of a function declaration in a ListElement, so thanks for that.

    Haven’t tried the code but reviewing it, here’s my suggestion.

    I would suggest the answer to this topic that function declarations can only be made in a ListElement when it’s initialised in a model and not dynamically as your code suggests.

    Therefore the probably solution is a functionid element holding an integer or enumeration, and use a switch function to execute the code you are after.


Log in to reply