No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

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

    Dynamic v-model bindings in input fields do not update visually

    Help
    4
    26
    7737
    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.
    • T
      tonyskulk last edited by

      Hi, I am using this code to dynamically create a list of input fields with dynamic v-model bindings like v-model=“newSession[column.name]”.

      <q-item
          v-for="column in columns"
          :key="column.name"
          dense
      >
          <q-item-section>
              // display array-valued fields
              <q-select
                  v-if="Array.isArray(newSession[column.name])"
                  clearable
                  standout="bg-teal text-white"
                  :label="column.label"
                  v-model="newSession[column.name]"
                  use-input
                  use-chips
                  multiple
                  hide-dropdown-icon
                  input-debounce="0"
                  new-value-mode="add"
              />
              // display boolean-valued fields
              <q-field
                  v-else-if="typeof newSession[column.name] === 'boolean'"
                  clearable
                  standout="bg-teal text-white"
                  v-model="newSession[column.name]"
                  :label="column.label"
              >
                  <template v-slot:control>
                  <q-checkbox
                      :value="newSession[column.name]"
                      @change="event => { newSession[column.name] = event.target.value; $forceUpdate()}"
                  />
                  </template>
              </q-field>
              // display other fields
              <q-input
                  v-else
                  clearable
                  standout="bg-teal text-white"
                  v-model="newSession[column.name]"
                  :label="column.label"
                  :hint="typeof newSession[column.name]"
              />
          </q-item-section>
      </q-item>
      

      I have also initialised the underlying ‘newSession’ object and a ‘columns’ object array (used as another existing Q-Table´s column definition).
      Everything is displayed correctly first. But if I change any input field´s value and jump to the next field, the old field´s value will be restored. So it seems that I am not able to change any field´s value at all. But when I look at the underlying model (‘newSession’), I can see that it has been changed after switching to the next field. So there are two questions for me:

      1. Why has any input field´s value not updated visually according to the model change?
      2. Why is the model value not changing directly e.g. on typing in chars?

      I have tried to find some answers on my own, but I could only get rid off the first point, and also I am not happy with this solution. With using the following code, I pushed for a complete re-rendering after model change, so at least the q-input components get visually updated after model changes. Here is the code:

      <q-input
          v-else
          clearable
          standout="bg-teal text-white"
          :value="newSession[column.name]"
          @change="event => { newSession[column.name] = event.target.value; $forceUpdate()}"
          :label="column.label"
          :hint="typeof newSession[column.name]"
      />
      

      Also this only works with q-input and not with other ‘field-components’ I used above.
      It seems to me that my expected behavior according to my two questions mentioned above should work without more fine-tuning, because I think it should be a default scenario. But maybe I missed something essentially (especially concerning @input and @change events).
      Can someone please help me out of this?

      Thanks,
      Tony

      1 Reply Last reply Reply Quote 1
      • s.molinari
        s.molinari last edited by

        Can you share your code within the <script> section of your component please?

        Scott

        1 Reply Last reply Reply Quote 0
        • metalsadman
          metalsadman last edited by

          @tonyskulk much better if a reproduction pen is provided, otherwise it’s a hard game of guessing :/.

          1 Reply Last reply Reply Quote 0
          • T
            tonyskulk last edited by

            @s-molinari This is the <script> part. Besides this there is a separate column definition in a separated js file, because its very big. It´s a default table column definition. I will put it in the next post below.

            <script>
            import { Loading, extend } from 'quasar'
            import { columns } from '../constants'
            import _ from 'lodash'
            
            export default {
            name: 'PageIndex',
            data () {
                return {
                selected: [],
                newDialog: false,
                newSession: {},
                loading: true,
                columns,
                data: []
                }
            },
            mounted () {
                this.onRefresh()
            },
            methods: {
                openNewSessionDialog () {
                this.columns.map(column => {
                    let value = ''
                    if (typeof column.field === 'function') {
                    value = column.field(this.selected[0])
                    } else {
                    value = this.selected[0][column.field]
                    }
                    return ({
                    name: column.name,
                    value: value
                    })
                }).forEach(field => {
                    this.newSession[field.name] = field.value
                })
                console.log(this.newSession)
                this.newDialog = true
                }
            }
            }
            </script>
            

            @metalsadman I tried using codepen to get a reproducing example, but I don´t know how to use it for .vue components. Can you recommend a tool to provide that?

            1 Reply Last reply Reply Quote 0
            • T
              tonyskulk last edited by

              Column definition from above:

              import _ from 'lodash'
              
              export const columns = [
              {
                  name: 'session_id',
                  label: 'Session ID',
                  align: 'left',
                  reference: '_id.$oid',
                  field: row => _.get(row, '_id.$oid'),
                  // format: val => `${val}`,
                  sortable: true,
                  immutable: true
              },
              {
                  name: 'label',
                  // align: 'left',
                  label: 'Label',
                  field: 'label',
                  sortable: true
              },
              {
                  name: 'data_source_training',
                  label: 'Datasource Training',
                  reference: 'data_sources.data_sources.training.path',
                  field: row => _.get(row, 'data_sources.data_sources.training.path'),
                  sortable: true
              },
              {
                  name: 'data_source_test',
                  label: 'Datasource Test',
                  reference: 'data_sources.data_sources.test.path',
                  field: row => _.get(row, 'data_sources.data_sources.test.path'),
                  sortable: true
              },
              {
                  name: 'total_timesteps',
                  label: 'Total timesteps',
                  field: 'total_timesteps',
                  sortable: true
              },
              {
                  name: 'policy',
                  label: 'Policy',
                  reference: 'training.policy.target',
                  field: row => _.get(row, 'training.policy.target'),
                  format: val => val.substring(val.lastIndexOf('.') + 1),
                  sortable: true
              },
              {
                  name: 'epsilon',
                  label: 'Exploration',
                  reference: 'training.epsilon',
                  field: row => _.get(row, 'training.epsilon'),
                  sortable: true
              },
              {
                  name: 'duration_training',
                  label: 'Training duration',
                  reference: 'training_metrics.duration_training',
                  field: row => _.get(row, 'training_metrics.duration_training', ''),
                  sortable: true,
                  immutable: true
              }
              ]
              1 Reply Last reply Reply Quote 0
              • s.molinari
                s.molinari last edited by

                I’m not sure it makes a difference, but you start with newSesssion as an object in data, but it should be an array.

                Also, try this for getting your code up as a working example: https://codesandbox.quasar.dev.

                Scott

                1 Reply Last reply Reply Quote 0
                • T
                  tonyskulk last edited by

                  Actually it´s an object. I am referencing the fields via ‘[]’, only because I want to use dynamic field names. I will try to put my code online with your link, thanks!

                  1 Reply Last reply Reply Quote 0
                  • s.molinari
                    s.molinari last edited by s.molinari

                    From the QSelect API in the docs.

                    97c10b3f-416c-48d9-ad3e-778339dc51a1-image.png

                    Scott

                    T 1 Reply Last reply Reply Quote 0
                    • T
                      tonyskulk @s.molinari last edited by

                      @s-molinari Yes, but in the QSelect I am using a model (newSession[column.name]) that is an array (see my first post).

                      <q-select
                              v-if="Array.isArray(newSession[column.name])"
                              clearable
                              standout="bg-teal text-white"
                              :label="column.label"
                              v-model="newSession[column.name]"
                              use-input
                              use-chips
                              multiple
                              hide-dropdown-icon
                              input-debounce="0"
                              new-value-mode="add"
                      />
                      1 Reply Last reply Reply Quote 0
                      • T
                        tonyskulk last edited by

                        My problem is that I want to use different input components according to the different types that newSession[column.name] can have.
                        This can be array, number, boolean or string.
                        So newSession should still be in object and I want to access its properties dynamically using [] what is actually nothing else than newSession.dynamicpropertyname.

                        1 Reply Last reply Reply Quote 0
                        • s.molinari
                          s.molinari last edited by

                          Well. I can only tell you what Quasar is expecting.

                          Scott

                          T 1 Reply Last reply Reply Quote 0
                          • T
                            tonyskulk @s.molinari last edited by

                            @s-molinari I got my full code up as a working example here: https://codesandbox.io/s/codesandbox-app-5hxoc

                            When you select a row in the table and then click on the copy-Button, a dialog opens where I want to be able to change any field values. But only when I close the dialog, the changes are applied on the model (see the model output on top of the table). After changing a field and leaving it to switch to the next field, the old value is visible again.

                            Everything takes place in the file Index.vue and constants.js for simplicity.
                            The model underlying the dialog is ‘newSession’ and the table data is based on ‘data’. On dialog opening I copy the selected row data into a newSession model (see the function openNewSessionDialog()).
                            (I mocked the backend request with static as you can see.)

                            1 Reply Last reply Reply Quote 0
                            • s.molinari
                              s.molinari last edited by

                              Ok. I see the use cases and sort of what you want to do.

                              Questions:

                              With the select you are trying to build in the dialog entry mask, what data is it supposed to be selecting with/ for? Your code loses me on that.

                              I think I understand the copying of the selected session. The idea is to then change parts of it to make a new session and add it to the table data, correct?

                              If I can get the answers to those questions, I might be able to help. Maybe. 😁

                              Scott

                              1 Reply Last reply Reply Quote 0
                              • T
                                tonyskulk last edited by tonyskulk

                                To answer your questions:

                                With the select you are trying to build in the dialog entry mask, what data is it supposed to be selecting with/ for? Your code loses me on that.

                                I am not sure if I got your question. The dialog entry mask is build based on the selected table entry. So I make a transformation from the ‘complicated’ raw model ‘data’ to a simplified model ‘newSession’. In the dialog I want to make changes based on the underlying ‘newSession’ model. And after clicking the save-button, I am transforming the simplified ‘newSession’ model back to the ‘data’ model. (However the transformations are working fine I think. )

                                I think I understand the copying of the selected session. The idea is to then change parts of it to make a new session and add it to the table data, correct?

                                Yes, that´s 100% correct.

                                I hope I could answer your questions and I am glad for your support in this 🙂

                                Tony

                                1 Reply Last reply Reply Quote 0
                                • s.molinari
                                  s.molinari last edited by

                                  For my first question, you have a QSelect being used in your dialog, which is what you are asking about. What part of the data is that supposed to be showing a selectable and addable selection field in your dialog?

                                  Scott

                                  1 Reply Last reply Reply Quote 0
                                  • T
                                    tonyskulk last edited by tonyskulk

                                    Every field in the dialog has an underlying model like ‘newSession[column.name]’, eg. ‘newSession.label’. And depending on what type ‘newSession[column.name]’ has, it should display an editable component like this:

                                    • boolean -> checkbox
                                    • array -> QSelect
                                    • everything else -> plain QInput
                                    1 Reply Last reply Reply Quote 0
                                    • s.molinari
                                      s.molinari last edited by s.molinari

                                      So, which part of the data is supposed to be remapped to an array? Can you give me an example of a key in the data?

                                      Scott

                                      1 Reply Last reply Reply Quote 0
                                      • s.molinari
                                        s.molinari last edited by

                                        Needless to say, what you’ve attempted isn’t going to work (as we can see). You’re going to need to do more with the data, before it reaches QTable. I’m just trying to understand how the select is going to offer the object data as an array selection from your data.

                                        Scott

                                        1 Reply Last reply Reply Quote 0
                                        • T
                                          tonyskulk last edited by

                                          So, which part of the data is supposed to be remapped to an array? Can you give me an example of a key in the data?

                                          In the column definition in constants.js there is for example the field ‘net_arch_pi’ defined by

                                          {
                                          name: 'net_arch_pi',
                                          label: 'Policy Network',
                                          reference: 'training.policy_kwargs.net_arch.args.pi',
                                          field: row =>
                                            _.get(row, 'training.policy_kwargs.net_arch.args.pi', [64, 64]),
                                          format: val => '[' + val.reduce((a, b) => a + ' - ' + b) + ']',
                                          sortable: true
                                          },
                                          

                                          which is an array of integers like [64,64] or [512,512,512].
                                          So we map this field to a table column basically by

                                          field: row =>.get(row, 'training.policy_kwargs.net_arch.args.pi')
                                          

                                          which is just the lodash implementation of

                                          field: row => row.training.policy_kwargs.net_arch.args.pi
                                          

                                          So when opening the dialog we actually map

                                          data.training.policy_kwargs.net_arch.args.pi
                                          

                                          to

                                          newSession.net_arch_pi
                                          

                                          which should be editable on the dialog screen by a QSelect component.


                                          But I wonder if it is only concerned to QSelect components, because I have the same effect on any ‘input field’ on any newSession.XXXX attribute. I also think that the mapping is fine as we can see that in the dialog the data is correctly displayed at first.

                                          1 Reply Last reply Reply Quote 0
                                          • metalsadman
                                            metalsadman last edited by metalsadman

                                            Tldr; as far as i can see above, theres nothing wrong in the components in question, its how you are structuring your data, imo i think you need some more time restructuring it or see and understand more how the component works, the docs should help. A codesandbox should also help so you can show what is working so far or whatnot, and in the end we can support you further.

                                            Check The quasar codesandbox what @s-molinari linked above, imo would rather see a running code than code you posted in this thread, when at first look is rather complex or need restructuring*.

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