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

QML Binding loop detected for property, what is the cause?



  • I'm working on a project and trying to improve the error handling, this is driving me crazy. No matter what I try I'm still getting 3 QML messages on start-up that I just don't understand the cause of:

        qrc://qml/Modes/ModePreview.qml:185:17: QML ModeSelection: Binding loop detected for property "selectedItemIndex"
    

    In the original code I thought the cause of this was a reference to an object that was not ready so I added a JavaScript function to test the object exhaustively before trying to access the property. This is the part of the QML that is causing the issues:

        StackLayout {
            id: stackLayout
            anchors.top: tabBar.bottom
            anchors.left: tabBar.left
            anchors.right: tabBar.right
            anchors.bottom: cameraSelector.top
            currentIndex: tabBar.currentIndex
    
            readonly property int tabIndexLocal: 0
            readonly property int tabIndexMachine: 1
            readonly property int tabIndexTemplates: 2
            property var currentItem: children[currentIndex]
            property var lastSelected: ["","",""]
    
            function handleSelectedPathChanged(path) {
                if ( typeof path == "object"
                && typeof path.length == "number"
                && path.length > 0) {
                    workingModeSelected = false
                }
            }
            function getItem(member) {
                if ( typeof stackLayout.currentItem == "object"
                && typeof stackLayout.currentItem[member] != "undefined" ) {
                    return stackLayout.currentItem[member];
                }
                return -1;
            }
            function pathChanged(index, selectedPath) {
                var rc = false;
                if ( index >= stackLayout.tabIndexLocal 
                && index <= stackLayout.tabIndexTemplates ) {
                    if ( typeof selectedPath == "object"
                    && typeof selectedPath.length == "number"
                    && selectedPath.length > 0 ) {
                        if ( typeof stackLayout.lastSelected[index] === "string"
                        && stackLayout.lastSelected[index] !== selectedPath[0] ) {
                            stackLayout.lastSelected[index] = selectedPath[0];
                            rc = true;
                        }
                    }
                }
                return rc;
            }
            ModeSelection {
                id: localModesList
                modeType: ModePreviewManager.LocalModeType
                modePreviewModel: modePreviewManager.localModes
                onModePreviewModelChanged: selectedPath = []
    
                onSelectedPathChanged: {
                    stackLayout.handleSelectedPathChanged(selectedPath);
    
                    if ( stackLayout.pathChanged(stackLayout.tabIndexLocal, selectedPath) === true ) {
                        modeSelectionArea.refreshHighlight();
                    }
                }
            }
            ModeSelection {
                id: machineModesList
                modeType: ModePreviewManager.MachineModeType
                modePreviewModel: modePreviewManager.machineModes
                onModePreviewModelChanged: selectedPath = []
    
                onSelectedPathChanged: {
                    stackLayout.handleSelectedPathChanged(selectedPath)
    
                    if ( stackLayout.pathChanged(stackLayout.tabIndexMachine, selectedPath) === true ) {
                        modeSelectionArea.refreshHighlight();
                    }
                }
                onItemCountChanged: {
                    if ( machineModesList.itemCount > 0 ) {
                        tabBar.currentIndex = stackLayout.tabIndexMachine
                        machineModesList.setSelected(machineModesList.itemCount - 1);
                        ModeDetails.stopBusyAnim();
                    }
                }
            }
            ModeSelection {
                id: templateModeList
                modeType: ModePreviewManager.TemplateModeType
                modePreviewModel: modePreviewManager.templateModes
                onModePreviewModelChanged: selectedPath = []
    
                onSelectedPathChanged: {
                    stackLayout.handleSelectedPathChanged(selectedPath)
    
                    if ( stackLayout.pathChanged(stackLayout.tabIndexTemplates, selectedPath) === true ) {
                        modeSelectionArea.refreshHighlight();
                    }
                }
            }
        }
    

    What is causing the loop?


  • Lifetime Qt Champion

    @SPlatten Which is the line 185?



  • It doesn't really make much sense, line 185 is the line starting "ModeSelection {", this is the first "ModeSelection {" with "id: localModesList" which is also the tab I am currently viewing.



  • @SPlatten I think the problem is inside ModelSelection.qml, take a closer look at property selectedItemIndex from this QML element. I think it is a custom component.



  • I'm quite new to QML, is there any error handling I can introduce that would help me trace this?

    In the file ModeSelection.qml, near the top along with some other properties:

        property int selectedItemIndex: {
            //Some logic to get the index, if it fails return -1
        }


  • @SPlatten said in QML Binding loop detected for property, what is the cause?:

    I'm working on a project and trying to improve the error handling, this is driving me crazy. No matter what I try I'm still getting 3 QML messages on start-up that I just don't understand the cause of:

        qrc://qml/Modes/ModePreview.qml:185:17: QML ModeSelection: Binding loop detected for property "selectedItemIndex"
    

    What is causing the loop?

    My comment is just a sidenote. Please forgive the intrusion. It comes from empathy and I will be brief.

    I've struggled with these, too. The thought that crosses my mind is that something in the codebase (in "qtdeclarative/src" or similar) must be traversing the bits that are circularly linked, so why not print out the cycle along with the "binding loop detected"? I've seen several build tools and compilers do exactly that (print the whole cycle) when they detect cyclic dependencies. One of these days I hope to have time to propose such an enhancement and draft a patch.



  • I think the issue was caused by the fact that the property is no assigned a constant but a JavaScript which for some reason was erring and I think because of the error the value assigned to the property was undefined.


Log in to reply