Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Unsolved Accessing child properties in a Component type

    QML and Qt Quick
    3
    11
    1439
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      BikashRDas last edited by

      Hi All,
      Please have a look into the following code snippet.
      I have a conditional statement to load one of the component defined below. I can switch between the components by using the Switch button. On switching I want to read the text data from the text field in the already visible component, print the text to console and then switch to the other component.

      The issue I am facing is to read the text from the text field from the active component.

      import QtQuick 2.5
      import QtQuick.Layouts 1.3
      import QtQuick.Controls 2.2
      
      Item {
          ColumnLayout {
              id: cl
              Switch {
                  id: switchButton
                  checked: true
                  onCheckedChanged: {
                      ***console.log the text from loaded component***
                      ldr.sourceComponent = checked === true ? c1 : c2
                  }
              }
              Text {
                  id: label
                  text: "Text field"
              }
              Loader {
                  id: ldr
                  sourceComponent: switchButton.checked === true ? c1 : c2
              }
          }
      
          Component {
              id: c1
              TextField {
                  id: tf1
                  placeholderText: "Text Input 1"
                  width: 400
                  height: 50
                  background: Rectangle {
                      anchors.fill: parent
                      border{
                          color: "#252525"
                          width: 1
                      }
                      radius: 2
                  }
              }
          }
      
          Component {
              id: c2
              TextField {
                  id: tf2
                  placeholderText: "Text Input 2"
                  width: 400
                  height: 50
                  background: Rectangle {
                      anchors.fill: parent
                      border{
                          color: "#252525"
                          width: 1
                      }
                      radius: 2
                  }
              }
          }
      }
      

      One solution could be to have a string property as part of the root Item element and update the same on change text in any of the text field

      Item {
          property string textData: ""
          :
          :
          :
          Component {
              TextField {
                   .
                   .
                   .
                   onTextChanged: {
                         textData  = text
                   }
              }
          }
      }
      

      Just wanted to know, if there is any proper solution for this situation.

      KroMignon 1 Reply Last reply Reply Quote 0
      • KroMignon
        KroMignon @BikashRDas last edited by KroMignon

        @BikashRDas said in Accessing child properties in a Component type:

        Just wanted to know, if there is any proper solution for this situation.

        I would do it like this:

        • add a property alias on each Component declaration
        • setup text value in onLoaded event

        Like this:

        import QtQuick 2.5
        import QtQuick.Layouts 1.3
        import QtQuick.Controls 2.2
        
        Item {
            ColumnLayout {
                id: cl
                Switch {
                    id: switchButton
                    checked: true
                    onCheckedChanged: {
                        ldr.sourceComponent = checked === true ? c1 : c2
                    }
                }
                Text {
                    id: label
                    text: "Text field"
                }
                Loader {
                    id: ldr
                    sourceComponent: switchButton.checked === true ? c1 : c2
                    onLoaded: {
                        // read current value
                        item.text = label.text
                        // uddate value on text changes
                        item.text = Qt.bindings(Qt.binding(function () { return label.text; })
                    }
                }
            }
        
            Component {
                id: c1
                
                property alias text: tf1.text
                TextField {
                    id: tf1
                    placeholderText: "Text Input 1"
                    width: 400
                    height: 50
                    background: Rectangle {
                        anchors.fill: parent
                        border{
                            color: "#252525"
                            width: 1
                        }
                        radius: 2
                    }
                }
            }
        
            Component {
                id: c2
                property alias text: tf2.text
                TextField {
                    id: tf2
                    placeholderText: "Text Input 2"
                    width: 400
                    height: 50
                    background: Rectangle {
                        anchors.fill: parent
                        border{
                            color: "#252525"
                            width: 1
                        }
                        radius: 2
                    }
                }
            }
        }
        

        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

        1 Reply Last reply Reply Quote 0
        • B
          BikashRDas last edited by BikashRDas

          @KroMignon said in Accessing child properties in a Component type:

          property alias text: tf2.text

          give error, Component objects cannot declare new properties.

          KroMignon 1 Reply Last reply Reply Quote 0
          • fcarney
            fcarney last edited by fcarney

            You can access properties in your top level item inside the component through item:

                        onCheckedChanged: {
                            console.log(ldr.item.placeholderText)
                            ldr.sourceComponent = checked === true ? c1 : c2
                        }
            

            C++ is a perfectly valid school of magic.

            B 1 Reply Last reply Reply Quote 3
            • KroMignon
              KroMignon @BikashRDas last edited by

              @BikashRDas said in Accessing child properties in a Component type:

              give error, Component objects cannot declare new properties.

              Oh my bad, sorry.
              In fact it is much easier as @fcarney already explained.

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              1 Reply Last reply Reply Quote 0
              • B
                BikashRDas @fcarney last edited by BikashRDas

                @fcarney said in Accessing child properties in a Component type:

                console.log(ldr.item.placeholderText)

                I replaced the "placeholdertext" with "text". It's working. Thanks.
                Is there anyway to make the text data in the active component, available to other QML?
                E.g. Suppose the above code is part of MyTextField.qml.
                In my main. qml, I am creating an instance of MyTextField component like,

                in Main.qml

                Window {
                    .
                    .
                    .
                    MyTextField {
                        id: mtf
                        .
                        .
                        .
                    }
                
                    onSomthing : {
                        // mtf.textData refers to the text property of the textfield of active component in MyTextField.qml
                        console.log(mtf.textData)
                    }
                }
                
                KroMignon 1 Reply Last reply Reply Quote 0
                • KroMignon
                  KroMignon @BikashRDas last edited by

                  @BikashRDas said in Accessing child properties in a Component type:

                  Is there anyway to make the text data in the active component, available to other QML?
                  E.g. Suppose the above code is part of MyTextField.qml.

                  Yes, I think here using property alias should do the job:

                  import QtQuick 2.5
                  import QtQuick.Layouts 1.3
                  import QtQuick.Controls 2.2
                  
                  Item {
                      property alias textData: ldr.item.text
                      ...
                  }
                  

                  It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                  B 1 Reply Last reply Reply Quote 1
                  • B
                    BikashRDas @KroMignon last edited by

                    @KroMignon said in Accessing child properties in a Component type:

                    @BikashRDas said in Accessing child properties in a Component type:

                    Is there anyway to make the text data in the active component, available to other QML?
                    E.g. Suppose the above code is part of MyTextField.qml.

                    Yes, I think here using property alias should do the job:

                    import QtQuick 2.5
                    import QtQuick.Layouts 1.3
                    import QtQuick.Controls 2.2
                    
                    Item {
                        property alias textData: ldr.item.text
                        ...
                    }
                    

                    I had tried this earlier. getting this error. qrc:/MyTextBox.qml:7 Invalid alias target location: text

                    KroMignon 1 Reply Last reply Reply Quote 0
                    • KroMignon
                      KroMignon @BikashRDas last edited by

                      @BikashRDas said in Accessing child properties in a Component type:

                      I had tried this earlier. getting this error. qrc:/MyTextBox.qml:7 Invalid alias target location: text

                      One other solution would be to use another trick:

                      import QtQuick 2.5
                      import QtQuick.Layouts 1.3
                      import QtQuick.Controls 2.2
                      
                      Item {
                          property alias textData: ldr.textData
                          ColumnLayout {
                              id: cl
                              Switch {
                                  id: switchButton
                                  checked: true
                                  onCheckedChanged: {
                                      console.log(ldr.item.placeholderText)
                                      ldr.sourceComponent = checked === true ? c1 : c2
                                  }
                              }
                              Text {
                                  id: label
                                  text: "Text field"
                              }
                              Loader {
                                  id: ldr
                                  property var textData
                                  sourceComponent: switchButton.checked === true ? c1 : c2
                                  onLoaded: {
                                      // read current value
                                      textData = item.text
                                      // uddate value on text changes
                                      textData = Qt.bindings(Qt.binding(function () { return item.text; })
                                  }
                              }
                          }
                      ...
                      }
                      

                      But you can only read it from outside, not write on it.

                      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                      B 1 Reply Last reply Reply Quote 0
                      • B
                        BikashRDas @KroMignon last edited by BikashRDas

                        @KroMignon Okay got it. Thanks for the reply. This trick will solve my requirement. But it would be good to know if there is any appropriate way to be able to do both read and write.

                        Another question is, hope you have noticed, initially I had posted an approach to use a property as part of root Item and update the same on on text change in the texfield of active components. In the approaches (mentioned by you and one by me) we can have a read access to the text data of the text field. Just wanted to know if there is any advantage/disadvantage of these 2 approaches.

                        KroMignon 1 Reply Last reply Reply Quote 0
                        • KroMignon
                          KroMignon @BikashRDas last edited by KroMignon

                          @BikashRDas If you need to have a read/write access you could do it like this:

                          import QtQuick 2.5
                          import QtQuick.Layouts 1.3
                          import QtQuick.Controls 2.2
                          
                          Item {
                              id: _root
                              property string textData
                              onTextDataChanged: {
                                  if(ldr.status === Loader.Ready)
                                      ldr.item.text = textData
                              }
                              ColumnLayout {
                                  id: cl
                                  Switch {
                                      id: switchButton
                                      checked: true
                                      onCheckedChanged: {
                                          console.log(ldr.item.placeholderText)
                                      }
                                  }
                                  Text {
                                      id: label
                                      text: "Text field"
                                  }
                                  Loader {
                                      id: ldr
                                      property string textData
                                      onTextDataChanged: _root.textData = textData
                                      sourceComponent: switchButton.checked === true ? c1 : c2
                                      onLoaded: {
                                          // read current value
                                          textData = item.text
                                          // update value on text changes
                                          textData = Qt.bindings(Qt.binding(function () { return item.text; })
                                      }
                                  }
                              }
                          ...
                          }
                          

                          I think there is no risk about "binding loop", but I don't guarantee anything... Try it out.

                          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post