Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to add item to a repeater dynamically?
QtWS25 Last Chance

How to add item to a repeater dynamically?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
11 Posts 5 Posters 1.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Kamichanw
    wrote on last edited by
    #1

    I'm trying to add item to a Repeater whose model is an object list.

    import QtQuick 2.0
    import QtQuick.Controls
    
    Window {
        width: 400
        height: 300
        visible: true
    
        Row {
            Repeater {
                id: repeater
                model: ["red", "green", "blue"]
    
                delegate: Rectangle {
                    width: 50
                    height: 50
                    color: modelData
                }
            }
        }
        Button {
            text: "add item"
            anchors.top: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                repeater.model.splice(1, 0, "yellow")
            }
        }
    }
    

    In the code snippet above, I tried to insert item at index 1 via js-like list operation, but it doesn't work. Besides, I found that repeater.model doesn't change at all after I called splice.

    sierdzioS B 2 Replies Last reply
    0
    • K Kamichanw

      I'm trying to add item to a Repeater whose model is an object list.

      import QtQuick 2.0
      import QtQuick.Controls
      
      Window {
          width: 400
          height: 300
          visible: true
      
          Row {
              Repeater {
                  id: repeater
                  model: ["red", "green", "blue"]
      
                  delegate: Rectangle {
                      width: 50
                      height: 50
                      color: modelData
                  }
              }
          }
          Button {
              text: "add item"
              anchors.top: parent.top
              anchors.horizontalCenter: parent.horizontalCenter
              onClicked: {
                  repeater.model.splice(1, 0, "yellow")
              }
          }
      }
      

      In the code snippet above, I tried to insert item at index 1 via js-like list operation, but it doesn't work. Besides, I found that repeater.model doesn't change at all after I called splice.

      sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      @Kamichanw You probably need to assign the new value explicitly:

      repeater.model = repeater.model.splice(1, 0, "yellow")
      

      (Z(:^

      1 Reply Last reply
      1
      • K Kamichanw

        I'm trying to add item to a Repeater whose model is an object list.

        import QtQuick 2.0
        import QtQuick.Controls
        
        Window {
            width: 400
            height: 300
            visible: true
        
            Row {
                Repeater {
                    id: repeater
                    model: ["red", "green", "blue"]
        
                    delegate: Rectangle {
                        width: 50
                        height: 50
                        color: modelData
                    }
                }
            }
            Button {
                text: "add item"
                anchors.top: parent.top
                anchors.horizontalCenter: parent.horizontalCenter
                onClicked: {
                    repeater.model.splice(1, 0, "yellow")
                }
            }
        }
        

        In the code snippet above, I tried to insert item at index 1 via js-like list operation, but it doesn't work. Besides, I found that repeater.model doesn't change at all after I called splice.

        B Offline
        B Offline
        Bob64
        wrote on last edited by
        #3

        @Kamichanw I think the issue is that while a simple list is sufficient for a "static" model, it does not provide the signals needed to notify that the model has changed. Hence the suggestion above to completely reassign the model as QML sees that as a property change and will therefore reinitialise the internal model that is driving the Repeater.

        If you want to trigger fine-grained dynamic updates, you might be better to use a ListModel. It is still relatively simple (not quite as simple as a JS list, but simpler than writing a C++ backend model), but it provides all the notifications needed.

        M 1 Reply Last reply
        3
        • B Bob64

          @Kamichanw I think the issue is that while a simple list is sufficient for a "static" model, it does not provide the signals needed to notify that the model has changed. Hence the suggestion above to completely reassign the model as QML sees that as a property change and will therefore reinitialise the internal model that is driving the Repeater.

          If you want to trigger fine-grained dynamic updates, you might be better to use a ListModel. It is still relatively simple (not quite as simple as a JS list, but simpler than writing a C++ backend model), but it provides all the notifications needed.

          M Offline
          M Offline
          Mairtin
          wrote on last edited by
          #4

          @Bob64 Add a log and you'll see that it's not that the model isn't sending an update, the model isn't getting updated to begin with. Neither splice nor push seem to actually add anything to repeater.model

          M B 2 Replies Last reply
          0
          • M Mairtin

            @Bob64 Add a log and you'll see that it's not that the model isn't sending an update, the model isn't getting updated to begin with. Neither splice nor push seem to actually add anything to repeater.model

            M Offline
            M Offline
            Mairtin
            wrote on last edited by
            #5

            As a side note, Object.freeze() doesn't seem to work in QML (or at least not in QDS)

            1 Reply Last reply
            0
            • M Mairtin

              @Bob64 Add a log and you'll see that it's not that the model isn't sending an update, the model isn't getting updated to begin with. Neither splice nor push seem to actually add anything to repeater.model

              B Offline
              B Offline
              Bob64
              wrote on last edited by Bob64
              #6

              @Mairtin OK, I see what you mean. You are right that if you look at repeater.model in the QML debugger console, it appears to be a list object with three items. It seems to be possible to update it using splice and push but if you examine the same object after doing that it still has its original form.

              I'd be interested to understand better what is happening under the hood here but, in any case, I would use a model that explicitly supports incremental updates.

              sierdzioS 1 Reply Last reply
              0
              • B Bob64

                @Mairtin OK, I see what you mean. You are right that if you look at repeater.model in the QML debugger console, it appears to be a list object with three items. It seems to be possible to update it using splice and push but if you examine the same object after doing that it still has its original form.

                I'd be interested to understand better what is happening under the hood here but, in any case, I would use a model that explicitly supports incremental updates.

                sierdzioS Offline
                sierdzioS Offline
                sierdzio
                Moderators
                wrote on last edited by
                #7

                @Bob64 said in How to add item to a repeater dynamically?:

                I'd be interested to understand better what is happening under the hood here

                You are passing a JS array to model property. Since it's not a QObject and does not have any notifiable Q_PROPERTIES, the QML engine just assumes it does not have to listen to any signals here (correctly: there are no signals emitted when you splice). It only knows that it needs to react when the entire object is changes (hence my recommendation to assign the model after splicing).

                (Z(:^

                B 1 Reply Last reply
                0
                • sierdzioS sierdzio

                  @Bob64 said in How to add item to a repeater dynamically?:

                  I'd be interested to understand better what is happening under the hood here

                  You are passing a JS array to model property. Since it's not a QObject and does not have any notifiable Q_PROPERTIES, the QML engine just assumes it does not have to listen to any signals here (correctly: there are no signals emitted when you splice). It only knows that it needs to react when the entire object is changes (hence my recommendation to assign the model after splicing).

                  B Offline
                  B Offline
                  Bob64
                  wrote on last edited by Bob64
                  #8

                  @sierdzio Yes, I was OK with that part and I thought I understood what was happening. But if you do something like this:

                          onClicked: {
                              repeater.model.splice(1, 0, "yellow")
                              console.log(repeater.model)
                          }
                  

                  You get output:

                  qml: [red,green,blue]
                  

                  What is repeater.model here given that splice does not cause an error? It suggests to me that it is still a Javascript array. But why does splice not update the array itself? Note that this is a separate question from why this update does not trigger the Repeater to update - I understand that aspect.

                  mzimmersM 1 Reply Last reply
                  0
                  • K Offline
                    K Offline
                    Kamichanw
                    wrote on last edited by
                    #9

                    I think ListModel can meet my requirement perfectly.

                    1 Reply Last reply
                    0
                    • K Kamichanw has marked this topic as solved on
                    • B Bob64

                      @sierdzio Yes, I was OK with that part and I thought I understood what was happening. But if you do something like this:

                              onClicked: {
                                  repeater.model.splice(1, 0, "yellow")
                                  console.log(repeater.model)
                              }
                      

                      You get output:

                      qml: [red,green,blue]
                      

                      What is repeater.model here given that splice does not cause an error? It suggests to me that it is still a Javascript array. But why does splice not update the array itself? Note that this is a separate question from why this update does not trigger the Repeater to update - I understand that aspect.

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #10

                      @Bob64 said in How to add item to a repeater dynamically?:

                      But why does splice not update the array itself?

                      Well, it is updating an array...just not the QML model containing a representation of that array. Hence the need to the explicit assignment that @sierdzio mentioned.

                      B 1 Reply Last reply
                      2
                      • mzimmersM mzimmers

                        @Bob64 said in How to add item to a repeater dynamically?:

                        But why does splice not update the array itself?

                        Well, it is updating an array...just not the QML model containing a representation of that array. Hence the need to the explicit assignment that @sierdzio mentioned.

                        B Offline
                        B Offline
                        Bob64
                        wrote on last edited by
                        #11

                        @mzimmers I do understand this in the broad sense, but I think there is a slightly more nuanced aspect to my confusion here.

                        When one assigns an array to a model property, what happens to that property's value? Does it continue to hold the original array, and QML initialises some internal model from it that is used to drive the delegates?

                        If the property does continue to hold the original array, then it would make sense that you could query the property to access that array, and it would make sense that you could call splice on it, repeater.model.splice(...). As we are all agreed, that won't actually update the view, because the change to the array is not visible to QML.

                        However, if we query repeater.model after doing the splice() it continues to show the original elements so what happened to that modification you made?

                        On the other hand, if the property value is being replaced by QML with something else that is not the original array, why is it possible to call methods like push and splice on it without any error?

                        At the end of the day, I guess it does not matter too much, but I am just curious about why this behaviour is seen.

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved