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

component loaded with Loader inside a delegate, how to access model?



  • Inside a delegate that has a Loader, how the component loaded by Loader can access the model?

    ComponentBase.qml:

    Item {
       ...
       property Component insideDelegateComponent
       ...
       ListView {
          ...
          delegate: Item {
              ...
              Loader {
                  sourceComponent: insideDelegateComponent
              }
              ... 
          }
       }
       ...
    }
    

    ComponentPaintDelegate.qml

    Text {
        text: model.name
    }
    

    DrawView.qml

    ComponentBase {
       insideDelegateComponent : ComponentPaintDelegate {
          ...
       }
    }
    

    Gives the error: Cannot read property 'name' of undefined



  • @lqsa Loader has a signal 'loaded' so you could make a signal handler:

    Loader {
       ...
       onLoaded: {
          item.role1 = role1;
          item.role2 = role2;
       }
    }
    

    Obviously the component that you load must have these properties roleX.



  • @sylc It doesn't work with the model. I suppose that the problem is that the model is attached from the context when the component is created and created bindings of their properties.



  • Well, the problem is the model's roles aren't visible from the loader inside the delegate. Here's a code snippet where I've shown properties trick.

    Does it fix the issue?

    import QtQuick 2.7
    
    Item {
        width: 640
        height: 480
    
        ListModel {
            id: peopleModel
            ListElement { name: "Samantha"; age: "21" }
            ListElement { name: "Joe"; age: "33" }
            ListElement { name: "Alex"; age: "32" }
        }
    
    
        Column {
            anchors.fill: parent
            Repeater {
                anchors.fill: parent
    
                model: peopleModel
    
                Loader {
                    sourceComponent: aDelegate
                    onLoaded: { item.name = name; item.age = age; }
                }
            }
        }
    
        Component {
            id: aDelegate
            Text {
                property string name
                property int age
                x: 5
                height: 15
                text: name + "," + age
            }
        }
    }
    


  • Loader creates an extra context for the dynamically instantiated item. Consequently, if I remember correctly, a property defined in the Loader element itself is visible to the loaded item. The styling of Qt Quick Controls 1.x is based on this technique.

    Loader {
        property string modelName: model.name
        sourceComponent: exampleComponent
    }
    
    Component {
        id: exampleComponent
        Text {
            text: modelName
        }
    }
    


  • @jpnurmi Yes, you are right. That's even better!

    import QtQuick 2.7
    
    Item {
        width: 640
        height: 480
    
        ListModel {
            id: peopleModel
            ListElement { name: "Samantha"; age: "21" }
            ListElement { name: "Joe"; age: "33" }
            ListElement { name: "Alex"; age: "32" }
        }
    
        Column {
            anchors.fill: parent
            Repeater {
                anchors.fill: parent
    
                model: peopleModel
    
                Loader {
                    sourceComponent: aDelegate
                    property string modelName: name
                    property int modelAge: age
                }
            }
        }
    
        Component {
            id: aDelegate
            Text {
                x: 5
                height: 15
                text: modelName + "," + modelAge
            }
        }
    }
    


  • It works!

    Only remarks that the component delegated can't has model.<property>, it must be only <property> and the Loader must have a property for every model property, not a model property.

    Thank you very much!



  • With a little bit of trickery, using the same technique you should be able to expose 'model' as is to the loaded item:

    delegate: Item {
        property var itemModel: model // read 'model' from the delegate's context
        width: loader.width
        height: loader.height
    
        Loader {
            id: loader
            property var model: parent.itemModel // inject 'model' to the loaded item's context
            sourceComponent: exampleComponent
        }
    }
    
    Component {
        id: exampleComponent
        Text {
            text: model.name
        }
    }
    

Log in to reply