2
votes

I'm wondering how can I pass an array in ListModel?

ok, In QML I have a ListView and I set it's ListModel like so:

model: ListModel
{
    id: myList   
    ListElement 
    {
        name: ""
        card: 0
        books: []
    }

}

I can append to it by using:

myList.append({name:"terry", card:00100, books:["024589","865976","879582","215645"]}); 

but when I try to output it on screen I get this.

{
    "card": 00100
    "books": {
        "objectName": "",
        "count": 4,
        "dynamicRoles": false
     },
    "name": "terry",
    "name": "terry"
}

I'm not sure why I'm getting 2 names though! and how can I get the value of books?

I look up the QML documentation of ListModel and ListElement couldn't find anything related to passing an array, all the examples are integer or string.

Any idea how I can get the date?
I did work around it by calling the array in Delegate with Component.onCompleted:{} but I believe that's not a good/correct way since Delegate is not responsible for holding the data and should be done in Model, please do correct me if I'm wrong.

Thanks for your time.

Edit01: Thanks for the reply, here is the reason I need array: I have a ComboBox in Delegate like so:

delegate: Rectangle
    {
     id: rowID
     width: 50
     height: 40
     color: "#323232"
     Row
     {
         anchors.fill: parent
         anchors.leftMargin: 10
         anchors.rightMargin: 10
         Label{
             id: nameID
             text: name
             font.pixelSize: 12
             width: 200
             wrapMode: Text.WrapAnywhere
             anchors.verticalCenter: parent.verticalCenter
             color: "#999"
         }

         Label{
             anchors.verticalCenter: parent.verticalCenter
             text: "out:"
             font.pixelSize: 12
             color: "#999"
         }

         ComboBox{
             id: booksID
             height: 20
             width: 50
             model: books
             anchors.verticalCenter: parent.verticalCenter
         }
     }
}

as you can see I'm feeding the name to Label (id: nameID) and I want to feed the books to ComboBox (id: booksID) that has model, if I make books key as ListElement how can I feed all the values?

in QML ListModel or ListElement documentation didn't mention anything about getting all the key's value right? it only supports get(int index) which is based on an index number.

3
Just a guess from a quick look at the docs, try books: [ ListElement "" ] in the model. - T4rk1n
@T4rk1n I get this UiError: widget creation failed but then when I make ListElement is equal to JSON right? which means I need to give it keys and values, but having Array sounds simpler and straight forward. - Bear

3 Answers

7
votes

You did that wrong. Array members must be ListElement:

ListModel {
    id: mod
    ListElement {
        name: "ali"
        dic: [ ListElement{text:"asad-o-llah"; code: 14}, ListElement{text:"aboo torab"; code: 72}, ListElement{text:"amir al-momenin"; code: 110}]
    }
}

ListView {
    model: mod
    anchors.fill: parent
    delegate: Component {
        Rectangle {
            width: parent.width; height: 50
            Row {
                Text {
                    text: name
                }
                ComboBox {
                    width: 100; height: 30
                    model: dic        //<-- set dic as model for combo box
                    textRole: "text"  //<-- important!
                    onCurrentIndexChanged: {
                        console.log("current code is "+model.get(currentIndex).code);   //<-- get code value
                    }
                }
            }
        }
    }
}
Component.onCompleted: {
    var v = mod.get(0).dic.get(0).value;    //<-- sample usage
    console.log(v);
}
4
votes

Do you want some thing similar to this:

Rectangle {

id: root
visible: true
width: 360
height: 360

ListModel
{
    id: myList
    ListElement {
           name: "Story"
           card: 3
           books: [
               ListElement { bookName: "Story 1" },
               ListElement { bookName: "Story 2" },
               ListElement { bookName: "Story 3" }
           ]
       }
       ListElement {
           name: "Novel"
           card: 3
           books: [
               ListElement { bookName: "Novel 1" },
               ListElement { bookName: "Novel 2" },
               ListElement { bookName: "Novel 3" }
           ]
       }
}


Component {
    id: displayDelegate
    Rectangle
        {
         id: rowID
         width: 300 //50
         height: 40
         color: "#323232"
         border.color: "white"
         Row
         {
             anchors.fill: parent
             anchors.leftMargin: 10
             anchors.rightMargin: 10
             Text{
                 id: nameID
                 text: name
                 font.pixelSize: 12
                 width: 50 //200
                 wrapMode: Text.WrapAnywhere
                 /*anchors.verticalCenter: parent.verticalCenter*/
                 color: "white"//"#999"
             }

             Text{
                 /*anchors.verticalCenter: parent.verticalCenter*/
                 text: "out:"
                 font.pixelSize: 12
                 color: "white"//"#999"
             }

             /*ComboBox{
                 id: booksID
                 height: 20
                 width: 50
                 model: books
                 anchors.verticalCenter: parent.verticalCenter
             }*/
             Repeater {
                 model: books
                 Text { text: bookName + "\t"; color: "white" }
             }
         }
    }
}

ListView {
    id: disp
    anchors.fill: parent
    model: myList
    delegate: displayDelegate
}

}

I have modified few line of the code which you have shared. I am not sure about your ComboBox implementation. Therefore, I have used my own implementation of Repeater. You can try to execute and check the result.

1
votes

As an alternative to working with ListModel and ListElement, you can also have a look at the QSyncable JsonListModel QML type. (It is an open-source component by Ben Lau, you can find it on GitHub here: https://github.com/benlau/qsyncable)

The JsonListModel is a specialized ListModel type, that can handle JSON Arrays that you e.g. create in your QML or fetch from a REST service. It automatically synchronizes the JSON to a QML ListModel, so its very convenient to use:

ListView {
        id: listView
        anchors.fill: parent

        // property for json data, used as source for JsonListModel
        property var jsonData: []

        // use JsonListModel as model
        model: JsonListModel {
          source: listView.jsonData
          keyField: "id"
        }

        // delegate
        delegate: DelegateItem { /* ... */ }
}

You can also find a comprehensive guide how it works here: JsonListModel guide