I have a listview where I want to use either a defaultDelegate or a customDelegate depending on the value of a property.
So far I've tried using a component to load the different delegates:
Component{
id: delegate
Loader {
sourceComponent: type == 3 ? customDelegate : defaultDelegate
}
}
However, I can't access the properties I have in my model from the two delegates I have. I have the following error:
ReferenceError: name is not defined
Here is the model I use:
ListModel {
id: test
ListElement {
name: "Bill"
team: "554"
type: 2
}
ListElement {
name: "John"
team: "555"
type: 3
}
ListElement {
name: "Sam"
team: "556"
type: 1
}
}
Does anyone Have any idea, what I am doing wrong here?
It is, of course, a context problem. In your code, the name
, team
and type
context properties inserted by the ListView
into delegate
's context is inaccessible to the components inside your delegates, as the Loader
uses the creation context of customDelegate
and defaultDelegate
as the parent context when instantiating them, and name
, team
and type
do not refer to anything withing that context chain.
One solution is to explicitly set the required information as a property of the Loader
(this works because the Loader
sets itself as the context object for the component it is loading).
Following a working example:
ListModel {
id: testModel
ListElement {
name: "Bill"
team: "554"
type: 2
}
ListElement {
name: "John"
team: "555"
type: 3
}
ListElement {
name: "Sam"
team: "556"
type: 1
}
}
ListView {
anchors.fill: parent
model: testModel
delegate: myDelegate
}
Component {
id: myDelegate // yourDelegate
Loader {
property string modelName: model.name
property string modelTeam: model.team
property int modelType: model.type
sourceComponent: modelType === 3 ? colonDelegate : semicolonDelegate
}
}
Component {
id: colonDelegate
Text { text: modelName + ": " + modelTeam }
}
Component {
id: semicolonDelegate
Text { text: modelName + "; " + modelTeam }
}
For further reading and improvements I highly recommend you to read this.