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

    [SOLVED] QPopupEdit in QTable with Vuex data source - Do not emitted save event.

    Framework
    7
    31
    3677
    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.
    • S
      sontis @metalsadman last edited by

      @metalsadman thank you for the codepen and the explanation. The code (with using @input event) now works, BUT:
      I have the following data processing GUI -> Vuex -> REST Api -> DB Store.
      And I have now the messy code, because,

      • In @input event handler in QInput need update ONLY Vuex store. I do not want to invoke REST api after each key press. For this I have mutation and in during editing in the QPopupEdit the Vuex Store is unsynchronized with the DB Store. At this time, all GUI elements using this data will show an incorrect value.
      • In @save event handler in the QPopupEdit need send data by REST and if response OK then update Vuex Store.
      • In@cancel event handler in the QPopupEdit need recover Vuex Store back.
        The worst is Vuex Store is unsynchronized with the DB Store at some point. All GUI elements (which used this data) will not be displayed correctly.
      1 Reply Last reply Reply Quote 0
      • metalsadman
        metalsadman last edited by metalsadman

        @sontis it’s there in my example, @save event you have access to the initialValue and the newValue, you only commit the newValue when all goes well and can still revert to initialValue if something fails. like i said this has nothing to do with vuex or whatever data source you are using, the idea is the same. It’s a pretty solid component tbh and I don’t think in this case there’s a need for something to change, since clearly the functionalities are working as they should be.

        S 1 Reply Last reply Reply Quote 0
        • S
          sontis @metalsadman last edited by sontis

          @metalsadman
          Your codepen consists code:

          <q-input :value="props.row.name" dense autofocus counter @input="v => {props.row.name = v}"></q-input>
          

          If you will be use Vuex Store as the data source for your QTable, then each key press in the QPopupEdit will be modificate Vuex Store data without vuex mutation. This will cause an error

          vue.runtime.esm.js:1888 Error: [vuex] do not mutate vuex store state outside mutation handlers.
          

          See posts above.
          Therefore, in the case of QPopupEdit + Vuex + Rest Api + DB I have the messy code.

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

            @sontis hard to figure what you are actually doing in your vuex mutation, like i said in earlier post copy it first locally then that local data is what you should feed to your QTable’s data props then on your QPopupedit’s save event is where you call your actual vuex mutation/action. Per your thread’s title, there’s no issue there.

            About the vuex issue, would take some time for me to exactly emulate what’s wrong unless you provide a minimal pen of how you were doing it. I will try tho…

            S 1 Reply Last reply Reply Quote 0
            • S
              sontis @metalsadman last edited by

              @metalsadman
              But then I have to have a local copy data source and synchronize it with the vuex data source.
              Why then need vuex? 🙂
              Sorry, I am not a native English speaker. Maybe I got a mistake with the thread’s title

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

                @sontis you should mark as solved concerning the thread title since there’s nothing wrong with the event. your real issue was mutating your store, anyway here’s what i got https://codesandbox.io/s/q306jwnjx6 click “home” -> 'vuex table`, check the consoles, dunno if this is what you did, i would still suggest making a local copy and run your action/mutation @save event since that shows in vue devtools and is the vuex way of doing it.

                S 1 Reply Last reply Reply Quote 0
                • S
                  sontis @metalsadman last edited by sontis

                  @metalsadman thanks for good example.
                  If you set Vuex strict mode in the “…/store/index.js”:

                    const Store = new Vuex.Store({
                      strict: true,
                      modules: {
                        vuexDataTable
                      }
                    });
                  

                  then you see vuex errors after editing fields (check codesandbox console)
                  ![screenshot]
                  vuex-err.png

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

                    @sontis yep that’s why do my suggestion to copy it in local and do the mutation in the events. then in the watcher re assigned it to the local data. you should try to figure it out imo. the example is there to get you started.

                    S 1 Reply Last reply Reply Quote 0
                    • S
                      sontis @metalsadman last edited by

                      @metalsadman
                      “…suggestion to copy it in local…”
                      In this case, I don’t need Vuex 🙂 (data duplication/synchronization)
                      In Vuex Guide Form Handling recommends:
                      “…The “Vuex way” to deal with it is binding the <input>'s value and call an action on the input or change event…”
                      But the problem is that the quasar does not allow to mutate the properties of vuex storage objects.

                      1 Reply Last reply Reply Quote 0
                      • B
                        bfreed @sontis last edited by

                        @sontis You can avoid the vuex error by calling a mutation instead of modifying the props inline.
                        Mine looks like this:
                        @input="v => { setPendingRowState( {myVar: v, handle: props.row.handle} ); }

                        Where “setPendingRowState” commits a mutation:
                        setPendingRowState: function(payload) {
                        this.$store.commit(“progressReview/updatePendingProgress”, payload);
                        }

                        Obviously it doesn’t fix your concerns about being out of sync with the db, but hopefully it helps with the error anyway

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

                          @sontis well that’s the way to do it, beside this is normal behavior for vuex in strict mode coz you cannot simply mutate an array it’s entirety. what you can do is normalize your data in your vuex state, and then make a local copy map it to be an array (coz QTable data prop only accept an array), and in your mutation function you will have to filter it like an id to target that specific element in your state. keep on reading and you’ll get same answers :). you keep repeating it’s a quasar issue when it’s not :(.

                          anyway updated the sandbox using lodash https://codesandbox.io/s/q306jwnjx6.

                          S 1 Reply Last reply Reply Quote 1
                          • S
                            sontis @metalsadman last edited by sontis

                            @metalsadman thank you.
                            I found another solution.
                            I create the local buffer for v-model of the QPopupEdit. In @show event I fill this buffer from Vuex data and in @save event I invoke REST Api “update” method and change Vuex data. It seems so much easier. I have code like this:

                            <q-table ...  :data="ds">
                            ...
                              <template v-slot:body="props">
                                    <q-tr :props="props">
                                      <q-td key="desc" :props="props">
                                        {{ props.row.email }}
                                        <q-popup-edit v-model="popupEditData"
                                            @show="() => showPopup(props.row, 'name')"
                                            @save="(val, initval) => onUpdateDocument(val, props.row, 'name')"
                                            buttons>
                                          <q-input v-model="popupEditData" counter/>
                                        </q-popup-edit>
                                      </q-td>
                                      ...
                                    </q-tr>
                              </template>
                            ...
                            </q-table>
                            ...
                            export default {
                              data() {
                                return {
                                  popupEditData: '',
                                };
                            
                              computed: {
                                ...mapState({
                                  ds: state => state.ds.dsCustomers
                                }),
                            
                              methods: {
                                ...mapActions({
                                  getDocuments: 'ds/getCustomers',
                                  updateDocument: 'ds/updateCustomer',
                                }),
                            
                                showPopup(row, col) {
                                  this.popupEditData = row[col];
                                },
                            
                                onUpdateDocument(val, row, col) {
                                  this.setLoading(true);
                                  const updatedRow = extend({}, row);
                                  updatedRow[col] = val;
                                  const res = this.updateDocument(updatedRow);
                                  res.then((response) => {
                                    ...
                                    this.getDocuments();
                                  })
                                    .catch((err) => {
                                      ...
                                    })
                                    .finally(() => {
                                      this.setLoading(false);
                                    });
                                },
                            
                            1 Reply Last reply Reply Quote 1
                            • PeterQF
                              PeterQF last edited by PeterQF

                              Just so i understand. I also had the problem with “do not mutate vuex store state outside mutation handlers” and i now have a local baseFilter in data:

                               data() {
                                  return {
                                     baseFilter: {},
                              ...
                              

                              and then i update vuex in watch like this:

                              methods: {
                                  ...mapActions('filter', ['setPostsFilter']),
                                 ...
                              
                               watch: {
                                  baseFilter: {
                                    handler() {
                                      this.setPostsFilter({
                                        open: this.baseFilter.open,
                                        deleted: this.baseFilter.deleted,
                                        post_type: this.baseFilter.post_type,
                                        search: this.baseFilter.search
                                      })
                                    },
                                    deep: true
                                  }
                                },
                              

                              and then i get the state from vuex on mount like this:

                              computed: {
                                  ...mapState('filter', ['postsFilter'])
                              ......
                              
                              mounted() {
                                  this.baseFilter = this.postsFilter
                              ...
                              

                              is this an okay solution @metalsadman ?

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

                                @PeterQF yeah if somehow it shows error or the state gets modified by your local changes, you deep copy the state before you assign it to local.

                                1 Reply Last reply Reply Quote 1
                                • donsherman
                                  donsherman last edited by

                                  I got the same issue now like @sontis (of course while I have the same apporach). Is there meanwhile a solution now?
                                  There is no save event emitted by PopupEdit, if there is no :value and no :input handler in q-input avauilable.
                                  But that’s the problem, because q-input cannot mutate only the store (and even not directly)

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