-1

I need to insert elements in a ListView inside another ListView (via JS code inside my QML file) but when I try to access the inner ListView I get the error :

TypeError: Cannot call method 'insert' of undefined

Here is an example code to show my problem :

Item{
        id:list
        width: parent.width-210
        height: parent.height
        x:105

        Component{
            id:listDelegate

            Item {
                id:elem
                height: 100
                width: parent.width

                Item{
                    id:titre_liste
                    height: 50
                    width: parent.width
                    Text{
                        anchors.left: parent.left
                        color:"white"
                        text:titre_txt
                        font.pixelSize: 25
                        font.bold: false
                    }
                }
                Item{
                    id:listInList
                    width: parent.width-100
                    height: parent.height

                    Component{
                        id:listInListDelegate

                        Item{
                            id:element_liste
                            height: parent.height
                            width: parent.width/5
                            Text{
                                anchors.left: parent.left
                                color:"white"
                                text:element_txt
                                font.pixelSize: 25
                                font.bold: true
                            }
                        }
                    }
                    ListView {
                        id: viewin
                        anchors.fill: parent
                        model: ListModel{
                            id:listModel_in
                        }
                        delegate: listInListDelegate
                    }
                }
            }
        }
        ListView {
            id: viewglobal
            anchors.fill: parent
            model: ListModel{
                id:listModel
            }
            delegate: listDelegate
        }
    }

And here is my JS code, at the end of the QML file :

function addItem(){
    var i;
    var numListe = -1;
    var liste = "titre"
    var item = "item"

    for(i = 0;i<listModel.count;i++)
    {
        if(listModel.get(i).titre_txt === liste)
        {
            numListe = i;
        }
    }
    if(numListe === -1)//if the list doesn't exist
    {
        listModel.append({titre_txt:liste});
        numListe = listModel.count-1;
    }
    listModel.get(numListe).listModel_in.insert(0,{element_txt:item});
}

The error come from the last line of the JS code, when I try to insert a new element in the inner list. I verified that the value of "numListe" is 0 so it is not just a problem of wrong index.

How can I add elements to the inner list ?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Dosman
  • 1
  • where do you use `addItem()`? – eyllanesc Jan 26 '18 at 14:04
  • I use it in a button, the function is called everytime the button is pressed. (I didn't include the button in the code to keep it simple) – Dosman Jan 26 '18 at 14:07
  • you must place everything you need to reproduce your error, for you it may be simple, but that simple if you use it inappropriately can generate this type of errors, you must provide a [mcve] – eyllanesc Jan 26 '18 at 14:12

1 Answers1

0

There is a lot of stuff wrong with that code.

For starters - it is a mess, which is a very bad idea for someone who is obviously new at this stuff. Keep it clean - that's always a good idea regardless of your level of expertise.

listModel_in is an id and as such cannot be accessed outside of the delegate component.

That object however happens to be bound to the view's model property, so as long as the model doesn't change, you can access listModel_in via the model property. However, the view itself doesn't look like it is the delegate root object, so you have to interface it, for example by using an alias.

However, the inner model doesn't exist in the outer model, it only exists in the outer model's delegate item.

So you cannot possibly get it from listModel. You can get it from the viewglobal view, however ListView doesn't provide access by index. So you will have to set currentIndex for every index and use currentItem.

So it will look like this:

viewglobal.currentItem.modelAlias.insert(0,{element_txt:item});

But it should go without saying, you are putting data in the GUI layer, which is conceptually wrong. But it gets worse than conceptually wrong - you might not be aware of this, but ListView only creates items that it needs to show, meaning that it creates and destroys delegates as necessary. Meaning if your item falls out of view, it will be destroyed, and when it comes back into view, a new one will be created, and all the data you had in the model of the old delegate item will be lost. The view should never store data, just show it.

The inner model should be inside the outer model. However, last time I checked, QMLs ListModel didn't support model nesting, neither using declarative nor imperative syntax. If you want to nest models, I have provided a generic object model QML type you can use.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • I didn't know that out of view items were destroyed. If I put all data in the C++ layer, and send it to the GUI everytime a new item must be added, how can I be sure that the user can view the entire list without stuff being deleted as it scroll to the bottom of the list ? – Dosman Jan 26 '18 at 15:02
  • It doesn't have to be C++, it just has to be a separate data layer. It can still be QML, just not nested inside inside a view. This way the data will persist regardless of the gui. – dtech Jan 26 '18 at 15:05
  • You can set some crazy high value for `cacheBuffer` to force keeping all elements at all times, but that would be inefficient and would be a stupid idea to rely on that, simply don't keep data in the view. The view should only connect to and display the data layer. This way you can have no view or you can have different views simultaneously. Data and gui should be two completely separate layers. – dtech Jan 26 '18 at 15:26
  • Here is what I want to acheive : I have events in the C++ side and I have to display them using QML so that they are grouped by date. First, I made a QList of events in the C++ side, but I was unable to access the content of the QList on the QML side. To bypass this problem, I decided to pass the events one by one to the QML side as they arrived and store them in the ListModel. It works with a simple list, but I can't make it work with nested lists. Do you have any idea what can be the best solution for my problem ? – Dosman Jan 26 '18 at 15:40
  • You should implement your own `QAbstractListModel` subclasses for the outer and inner model. – dtech Jan 26 '18 at 17:03
  • Thanks a lot for your help, I am new to QML and now I understand better how it works. – Dosman Jan 29 '18 at 07:01