How to add item to a repeater dynamically?
-
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 thatrepeater.model
doesn't change at all after I calledsplice
. -
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 thatrepeater.model
doesn't change at all after I calledsplice
.@Kamichanw You probably need to assign the new value explicitly:
repeater.model = repeater.model.splice(1, 0, "yellow")
-
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 thatrepeater.model
doesn't change at all after I calledsplice
.@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. -
@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. -
@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
norpush
seem to actually add anything torepeater.model
-
@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
norpush
seem to actually add anything torepeater.model
@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 usingsplice
andpush
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.
-
@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 usingsplice
andpush
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.
@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 yousplice
). It only knows that it needs to react when the entire object is changes (hence my recommendation to assign the model after splicing). -
@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 yousplice
). It only knows that it needs to react when the entire object is changes (hence my recommendation to assign the model after splicing).@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 thatsplice
does not cause an error? It suggests to me that it is still a Javascript array. But why doessplice
not update the array itself? Note that this is a separate question from why this update does not trigger theRepeater
to update - I understand that aspect. -
-
@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 thatsplice
does not cause an error? It suggests to me that it is still a Javascript array. But why doessplice
not update the array itself? Note that this is a separate question from why this update does not trigger theRepeater
to update - I understand that aspect.@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.
-
@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.
@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 thesplice()
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
andsplice
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.