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

Repeater and itemAt issue



  • Hello, I am experimenting with QML and trying to access an item created by repeator, but am getting the error:

    TypeError: Result of expression 'repeater.itemAt(0)' [null] is not an object.

    I can access the repeater.count but not any items.

    How can I do this?

    @import QtQuick 1.1

    Item {
    width: parent.width
    height: parent.height

    Row {
        id: rows
        Repeater {
            id: repeater
            model: 10
            Rectangle {
                  width: 10; height: 20;
          }
        }
    }
    Rectangle {
        x: repeater.itemAt(0).x  // this fails with TypeError: Result of expression 'repeater.itemAt(0)' [null] is not an object.
        y: 100 * repeater.count  // this works
        width: 10; height: 10
    }
    

    }
    @



  • Hi babazaroni! Repeater is not an actual parent of the items but the repeater's parent is. Repeater just adds children to the positioner item so you should use your Row with rows id to work with children.



  • Hi,

    There are a couple issues at play here:

    1. The order in which the bindings are initially evaluated. In this case, repeater.itemAt(0).x is evaluated before the Repeater has actually created its children.
    2. The fact that methods can't NOTIFY (like properties do) when their return value would change. In this case, even when the items are finally created, repeater.itemAt(0).x is not reevaluated.

    You could work around this by assigning the value (or binding) at component completion instead, e.g.

    @
    Component.onCompleted: myRect.x = repeater.itemAt(0).x //once-off assignment
    @

    or

    @
    Component.onCompleted: myRect.x = (function(){ return repeater.itemAt(0).x; }) //binding
    @

    Regards,
    Michael



  • @mbrasser :
    Thanks, your advice makes sense and I tried it but I'm still getting a null from itemAt.

    My code:

    import QtQuick 2.7
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        
        Column {
            Row {
                Repeater {
                    id: rectRepeater
                    model: 3
                    Rectangle {
                        width: 30
                        height: 30
                        color: "red"
                        radius: 10
                    }
                }
            }
            Row {
                Repeater {
                    model: 3
                    Text {
                        Component.onCompleted: {
                            text: rectRepeater.itemAt(0).width;
                        }
                    }
                }
            }
        }
    }
    

    I'd appreciate any ideas on that one.


  • Moderators

    @Stefan-Monov76 Probably because the Item is not instantiated by the time this Repeater starts creating the items. You can easily solve this by delaying the creation of items in the other Repeater.

    Column {
            anchors.fill: parent
            Row {
                Repeater {
                    id: rectRepeater
                    model: 3
                    Rectangle {
                        width: 30
                        height: 30
                        color: "red"
                        radius: 10
                    }
    
                    Component.onCompleted: {
                        textRepeater.model = 3
                    }
                }
    
            }
            Row {
                Repeater {
                    id: textRepeater
                    Text {
                        text : rectRepeater.itemAt(0).width
                    }
                }
            }
        }
    


  • @p3c0 :
    Thanks a lot, this works. But shouldn't @mbrasser's solution (which is used in my previous post) also have worked?


  • Moderators

    @Stefan-Monov76 That is because there is no guarantee that those component have been instantiated even by then.



  • @p3c0 :
    Your own code relies on rectRepeater having instantiated its items by the time onCompleted fires. My code relies on exactly the same. So there shouldn't be any difference, should there?


  • Moderators

    @Stefan-Monov76 My code atleast guarantees that the 2nd Repeater doesnot start instantiating items before 1st repeater have finished instantiating them because 2nd Repeater's Items depends on 1st Repeater's Item.



  • @p3c0 :
    If I'm not mistaken, Component.onCompleted fires only when the entire top-level component (in this case the Window) has finished loading. Even when I've put the Component.onCompleted handler inside my Text item. So my code only accesses the first Repeater's items when the Window has loaded. And if the Window has loaded, then the first Repeater has already instantiated its items. No?


  • Moderators

    @Stefan-Monov76 No. Each component has this attached property.



  • @p3c0 :
    Thanks again for the continued replies. I don't intend to argue or prove myself right, just to clear up the situation for myself, mind you! :)
    The docs say a component is one of two things:

    • a type defined by the top-level element of a QML file (one type per file) - in my case, I have defined exactly one such component, and it "derives" from Window
    • an object defined inline by instantiating the Component type, that you can later instantiate via a Loader object. This scenario is irrelevant here.

    So my Text objects are not components, they are merely objects, and since they are not components, they don't have a Component.onCompleted signal, they use the Window's Component.onCompleted signal.

    It's important to me to be strict when using the term "Component", it has a very specific meaning in QML.


  • Moderators

    @Stefan-Monov76 That's fine :)
    component in this case I was referring to QML types that are inherits Item. I generally prefer to say QML components when referring to these types. Sorry for not being clear.
    So basically any QML type that inherits Item has the Component.onCompleted signal. For eg. Text, Rectangle, Row ...
    Here is the complete list:
    http://doc.qt.io/qt-5/qml-qtquick-item.html
    Look for the row named by "Inherited By".



  • @p3c0 :
    Hmm, the docs for the Item type that you link to don't mention having the onCompleted signal.


  • Moderators

    @Stefan-Monov76 It is an attached signal. It is mentioned here.

    An attached signal handler is referred to in the same way. For example, the Component.onCompleted attached signal handler is commonly used to execute some JavaScript code when a component's creation process has been completed.



  • @p3c0 :
    Ok, thanks.


Log in to reply