QML Loader, passing arguments to source
-
Hi all -
I have a page that will select a sub-page to display based on a property. I'm using a Loader for this.
This works:required property Equipment equipment Loader { id: loader Component.onCompleted: { var sourceFile switch (equipmentCopy.category) { case NgaUI.CATEGORY_VSP: sourceFile = "edits/VspEdit.qml" break; ... default: sourceFile = "" break; } setSource(sourceFile, { "equipment": equipmentEdit.equipment, }) } }
What I'd prefer to do is something like this (for brevity and clarity):
required property Equipment equipment Loader { id: loader source: { switch (equipmentCopy.category) { case NgaUI.CATEGORY_VSP: "edits/VspEdit.qml" ... default: return null } equipment: equipmentEdit.equipment } }
But I get a runtime error: "Unable to assign Equipment to QUrl." So, it appears that I can't pass arguments this way.
So...is it even possible to specify arguments within my Loader definition? Or, do I need to use the onCompleted() method?
Thanks...
-
required properties can't work in Loader's components unless you call
setSource
https://bugreports.qt.io/browse/QTBUG-125072
https://bugreports.qt.io/browse/QTBUG-93086A workaround is mentioned at the end of the description here : https://bugreports.qt.io/browse/QTBUG-125071
Using StackView could also be an alternative if it fits your use case.
Also is this for a delegate? A DelegateChooser could be a good solution.
-
If i'm understanding properly your need :
https://www.youtube.com/watch?v=nteJeojg07k at 8min50s
-
@mzimmers Connections and Bindings are your friend hier
//From Component to Outside Connections{ target: loader.item enabled: loader.status == Loader.Ready function mySignal(myArgument) { myOutsideProperty = myArgument } } //from file to Loader Component: Binding { target:loader.item property:"myComponentPropert" value: myOutsideProperty when: loader.status == Loader.Ready }
Also IIRC properties defined in the scope of the Loader are also passed to the Component loader. Not 100% on this though
-
@ankou29666 @J-Hilk thanks for the replies - the KDAB tutorial seems to agree with what @J-Hilk posted. Somehow, though, it's not working for me. Here's what I did:
Pane { id: equipmentEdit required property Equipment equipment Loader { id: loader source: { switch (equipmentCopy.category) { case NgaUI.CATEGORY_VSP: "edits/VspEdit.qml" default: return null } } } } Binding { target: loader.item property: "equipment" value: equipmentEdit.equipment when: loader.status === Loader.Ready } }
in "edits/VspEdit.qml," the equipment property is required. At run-time, I get an error:
Required property equipment was not initialized.
Did I miss a step? Or, is this possibly a race condition where the QML engine attempts to initialize the property before the Loader is ready?
Thanks...
-
hmmm I see nothing in the doc on how to deal with it when the source property belongs to the Binding's parent.
have you tried
value: equipment
in the Binding ?or
when: loader.source==="edits/VspEdit.qml" && loader.status===Loader.Ready"
if ever relevant depending on other cases for the switch ?
-
@ankou29666 said in QML Loader, passing arguments to source:
have you tried value: equipment in the Binding
Yes, and I even created properties inside the loader, and used those instead -- same result.
-
and what happens if you remove the requirement for that "equipment" property inside your "edits/VspEdit.qml" ?
or maybe just
when: loader.source==="edits/VspEdit.qml"
, without checking the status ?I'm actually thinking about a race condition as you suggested.
As far as I understand,- the component requires the property binding BEFORE it's instantiation, but
- the binding is made only AFTER the loader has done the job, due to the "when" condition
- and thus the binding is made AFTER the instantiation of the component, which is contradictory with the first statement
so my guess would be removing the loader.status case in the "when" clause.
-
@ankou29666 said in QML Loader, passing arguments to source:
so my guess would be removing the loader.status case in the "when" clause.
That was my guess too, but it doesn't work. Maybe a loader isn't what I should be using here. I'll look at alternatives.
-
@mzimmers I noticed some strange behaviour with bindings since I startet working with them in Qt6 and had undefined's when they clearly shouldn't be. A work around that I found for me would be:
Pane { id: equipmentEdit required property Equipment equipment property bool completed: false Component.onCompleted: equipmentEdit.completed = true Loader { id: loader source: { switch (equipmentCopy.category) { case NgaUI.CATEGORY_VSP: "edits/VspEdit.qml" default: return null } } } } Binding { target: loader.item property: "equipment" value: equipmentEdit.equipment when: loader.status === Loader.Ready && equipmentEdit.completed } }
Don't know why, I never had to rely on this tricks before
-
@J-Hilk it was worth a try, but still didn't work. As I said above, maybe I don't need a Loader here - I just need something to insert one of my Components into a screen, selecting the component based on a property of one of the properties in my main Component (in this case, equipmentEdit.category).
-
-
required properties can't work in Loader's components unless you call
setSource
https://bugreports.qt.io/browse/QTBUG-125072
https://bugreports.qt.io/browse/QTBUG-93086A workaround is mentioned at the end of the description here : https://bugreports.qt.io/browse/QTBUG-125071
Using StackView could also be an alternative if it fits your use case.
Also is this for a delegate? A DelegateChooser could be a good solution.
-
@GrecKo said in QML Loader, passing arguments to source:
required properties can't work in Loader's components unless you call setSource
Well, that's that. Looks like I'll be using setSource() after all; a Loader is better for my use case than a StackView.
Thanks to all who looked at this.
-
M mzimmers has marked this topic as solved on