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

Passing array of QML elements to Javascript function



  • This is my first time using a declarative language and I have run into a few issues.

    This application is meant to help count currency by number of units input by the user and displays the total face value to the user.

    0_1535952294851_Untitled.png

    My first problem is I'm sending 9 elements to my FormCalculations.tillBalanceHandler individually

    Is there a way to send something like... parent.children? and if so how do I reference them individually inside the javascript function?

    //this is my main qml file
    Page1Form 
    {
    //Handle calculations of tillBalanceNum
    tillBalanceNum.text: FormCalculations.tillBalanceHandler(quarterRollCalc, dimeRollCalc, nickelRollCalc, pennyRollCalc, tillQuarterCalc, tillNickelsCalc, tillDimesCalc, tillPennyCalc, extraChangeCalc)
    }
    //this is a small clip of how my elements in ui.qml look
    Column {
            id: column
            x: 5
            width: 80
            height: 316
            spacing: 13
    
            Text {
                id: quarterRolls
                width: 80
                height: 20
                text: qsTr("quarter rolls")
                font.family: "Verdana"
                font.pixelSize: 12
    
            }
    
            Text {
                id: dimeRolls
                width: 80
                height: 20
                text: qsTr("dime rolls")
                font.family: "Verdana"
                font.pixelSize: 12
            }
    Column {
            id: column1
            x: 129
            y: 0
            width: 42
            height: 316
            spacing: 13
    
            TextInput {
                id: quarterRollCount
                width: 30
                height: 20
                text: qsTr("#")
                validator: IntValidator{bottom:1; top:1000}
                font.pixelSize: 12
                property double value: 10.00
    
    
            }
    
            TextInput {
                id: dimeRollCount
                width: 30
                height: 20
                text: qsTr("#")
                validator: IntValidator{bottom:1; top:1000}
                font.pixelSize: 12
                property double value: 5.00
    
            }
    Column {
            id: column2
            x: 217
            y: 0
            width: 42
            height: 316
            spacing: 13
    
            Text {
                id: quarterRollCalc
                width: 80
                height: 20
                font.pixelSize: 12
            }
    
            Text {
                id: dimeRollCalc
                width: 80
                height: 20
                font.pixelSize: 12
            }
    
    //this is my javascript file
    function tillBalanceHandler(QRC, DRC, NRC, PRC, TQC, TDC, TNC, TPC, ECC)
        {
        var calcArray = [QRC.text, DRC.text, NRC.text, PRC.text, TQC.text, TDC.text, TNC.text, TPC.text, ECC.text]
        var iterator
        var totalToSubtract = 225
            for (iterator in calcArray)
            {
            totalToSubtract = totalToSubtract - calcArray[iterator]
            }
    
        //result needs 2 digits after decimal
        var result = totalToSubtract.toFixed(2)
    
        return result
        }
    
    

    my 2nd problem if possible is if someone could tell me if it's possible to batch together SignalHandlers?

    //main.qml again
    Page1Form {
                //Handle Edits to Counts to Display Totals
                quarterRollCount.onEditingFinished: {quarterRollCalc.text = FormCalculations.countHandler(quarterRollCount)}
                dimeRollCount.onEditingFinished: {dimeRollCalc.text = FormCalculations.countHandler(dimeRollCount)}
                nickelRollCount.onEditingFinished: {nickelRollCalc.text = FormCalculations.countHandler(nickelRollCount)}
                pennyRollCount.onEditingFinished: {pennyRollCalc.text = FormCalculations.countHandler(pennyRollCount)}
                tillQuarterCount.onEditingFinished: {tillQuarterCalc.text = FormCalculations.countHandler(tillQuarterCount)}
                tillNickelCount.onEditingFinished: {tillNickelsCalc.text = FormCalculations.countHandler(tillNickelCount)}
                tillDimeCount.onEditingFinished: {tillDimesCalc.text = FormCalculations.countHandler(tillDimeCount)}
                tillPenniesCount.onEditingFinished: {tillPennyCalc.text = FormCalculations.countHandler(tillPenniesCount)}
                extraChangeCount.onEditingFinished: {extraChangeCalc.text = FormCalculations.countHandler(extraChangeCount)}
    }
    //javascript file
    function countHandler(countElement)
        {
        var countInt = parseInt(countElement.text)
        var value = countElement.value
    
        var total = (countInt * value).toFixed(2)
    
        return total
        }
    

    If anyone has suggestions for how to approach QML/Javascript in this context, please do so I can make my life easier
    thanks!



  • @Gizmo
    You should really have a look at:
    http://doc-snapshots.qt.io/qt5-5.11/qtquick-modelviewsdata-modelview.html
    It will solve both your problems...

    To get you going, try the following:

        ListModel {
            id: myModel
            ListElement {denomination: "quarter rolls"; unitValue: 10.0}
            ListElement {denomination: "dime rolls"; unitValue: 5.0}
            ListElement {denomination: "nickel rolls"; unitValue: 2.0}
            ListElement {denomination: "penny rolls"; unitValue: 0.50}
            ListElement {denomination: "till quarters"; unitValue: 0.25}
            ListElement {denomination: "till dimes"; unitValue: 0.10}
            ListElement {denomination: "till nickels"; unitValue: 0.05}
            ListElement {denomination: "till pennies"; unitValue: 0.01}
        }
    
        Column {
            height: 20*myModel.count
            width: 80
            padding: 10
    
            Repeater {
                id: test
                model: myModel
    
                delegate: Row {
                    height: 30
                    width: 100
                    Text {
                        id: denomLabel
                        width: 100
                        height: 30
                        font.pixelSize: 12
                        text: denomination
                    }
    
                    TextInput {
                       id: countVal
                        width: 100
                        height: 30
                        text: "1"
                        validator: IntValidator{bottom:1; top:1000}
                        font.pixelSize: 12
                        onAccepted: {
                            totVal.text = (unitValue * parseInt(countVal.text)).toFixed(2)
                        }
                    }
    
                    Text {
                        id: totVal
                        width: 80
                        height: 30
                        font.pixelSize: 12
                        text: unitValue.toFixed(2) //(unitValue * parseInt(countVal.text)).toFixed(2)
                    }
                }
            }
        }
    

    You can access model items via the get(index) method and items from the Repeater via the itemAt(index) method to access the values in the delegate that are not part of the model.

    Good luck!



  • I'm currently working with "totVal" and I need to access it within your solution.
    How do I access the index of TotVal with itemAt()?
    At this point I'm curious to reassign the index each time totVal is created within the repeater.

    I had totVal tell me the index of itself, but it seems the row is creating a problem?
    I tried to assume perhaps it could be an array, (RowNum, ElementNum) but that didn't work either.
    I tried test.itemAt(0).totVal and that didn't work either.
    I'm able to see that test.itemAt(up to myModel.count).width only gives me the width of what the row is.



  • @Gizmo
    You are right in that it has to do with the Row. You cannot directly access totVal since it is not the root of the delegate. In your case the root is the Row indeed. To access children of the delegate's root object, or their properties, you have to use an alias, for example like this:

            Repeater {
                id: test
                 ...
    
                delegate: Row {
                      ...
                     property alias sumVal: totVal.text
                      ...
                     Text {
                           id: totVal
                           text: ...
                     }
                 }
            } 
    

    Now, you can access sumVal as:

    test.itemAt(index).sumVal
    

    Note that aliases can also be to the object itself, so you could instead have done:

        property alias totVal: totVal
    

    and then use:

    test.itemAt(index).totVal.text
    

    to get the text value.



  • Hahaha that's fantastic, I tried the property alias within the totVal {block} and it didn't work with all of this code inside my ui.qml. I finally realized that placing all of this in my main qml file makes life much easier and I have more freedom. Thanks again Diracsbracket.

    0_1536199001859_Untitled.png


Log in to reply