Pass in data into modal v-dialog

57 Views Asked by At

I'm new to Vuetify and trying to build a UI that shows a table of found Wifi networks along each Wifi's properties. For each known network the user should have the option to modify the stored password, or delete the Wifi from the list of known networks.

Screenshot

Here's my best attempt to achieve this so far:

<template>
  <div class="pa-4 text-center">
    <v-dialog v-model="showEditDialog" max-width="600">
      <v-card prepend-icon="mdi-account" title="Edit Wifi settings">
        <v-card-text>
          <v-row dense>
            <v-col cols="12" md="4" sm="6">
              <v-text-field
                hint="Enter the Wifi password of your router."
                label="Wifi Password *"
                type="password"
                required="true"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6">
              <v-checkbox :model-value="true" label="Auto-Connect">
              </v-checkbox>
            </v-col>
          </v-row>

          <small class="text-caption text-medium-emphasis"
            >* indicates a required field</small
          >
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>

          <v-btn
            text="Close"
            variant="plain"
            @click="showEditDialog = false"
          ></v-btn>

          <v-btn
            color="primary"
            text="Save"
            variant="tonal"
            @click="showEditDialog = false"
          ></v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <v-dialog v-model="showDeleteDialog" max-width="500">
      <template v-slot:item.name="{ item }">
        <v-card title="Delete Wifi">
          <v-card-text>
            Are you sure you want to remove {{ item.name }} from the list of
            known Wifis?
          </v-card-text>

          <v-card-actions>
            <v-spacer></v-spacer>

            <v-btn
              text="Cancel"
              variant="plain"
              @click="hideDeleteWifiDialog()"
            ></v-btn>

            <v-btn
              color="red"
              text="Delete Wifi"
              variant="tonal"
              prepend-icon="$vuetify"
              @click="deleteWifi(item)"
            ></v-btn>
          </v-card-actions>
        </v-card>
      </template>
    </v-dialog>
  </div>

  <v-data-table
    :headers="headers"
    :items="wifiNetworks"
    :items-per-page="20"
    :items-per-page-options="[ { value: 20, title: '20' }, { value: -1, title: 'All' } ]"
  >
    <template v-slot:item.autoConnect="{ item }">
      <v-chip
        :color="item.autoConnect ? 'green' : 'black'"
        :text="item.autoConnect ? 'Yes' : 'No'"
        :variant="item.autoConnect ? 'tonal' : 'text'"
        size="small"
        label
      >
      </v-chip>
    </template>

    <template v-slot:item.isConnected="{ item }">
      <div class="text-end">
        <v-chip
          :color="item.isConnected ? 'green' : 'black'"
          :text="item.isConnected ? 'Connected' : 'Connect'"
          :variant="item.isConnected ? 'tonal' : 'outlined'"
          @click="item.isConnected ? {} : { click: connect(item) }"
          size="small"
          label
        >
        </v-chip>
      </div>
    </template>

    <template v-slot:item.action="{ item }">
      <v-icon class="me-2" size="small" @click="editItem(item)">
        mdi-pencil
      </v-icon>
      <v-icon
        size="small"
        @click="showDeleteWifiDialog(item)"
        :disabled="false"
      >
        mdi-delete
      </v-icon>
    </template>
  </v-data-table>
</template>

<script>
  export default {
    data: () => ({
      showEditDialog: false,
      showDeleteDialog: false,
      headers: [
        { title: 'Network Name (SSID)', key: 'SSID' },
        { title: 'Security Type', key: 'security' },
        { title: 'Auto Connect', key: 'autoConnect' },
        { title: 'Action', key: 'action' },
        { title: 'Connection', key: 'isConnected' },
      ],
      wifiNetworks: [
        {
          SSID: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
          security: 'WEP',
          isConnected: false,
          autoConnect: true,
          action: 'connect',
        },
        {
          SSID: 'XYZ',
          security: 'WPA2',
          isConnected: true,
          autoConnect: true,
          action: 'connect',
        },
        {
          SSID: '0x1234',
          security: 'None',
          isConnected: false,
          autoConnect: false,
          action: 'connect',
        },
        {
          SSID: 'BGT',
          security: 'WPA',
          isConnected: false,
          autoConnect: false,
          action: 'connect',
        },
      ],
    }),

    methods: {
      editItem(item) {
        this.showEditDialog = true
      },
      showDeleteWifiDialog(item) {
        this.showDeleteDialog = true
      },
      hideDeleteWifiDialog() {
        this.showDeleteDialog = false
      },
      deleteWifi(item) {
        this.showDeleteDialog = false
        // Handle deletion, send back data
      },
    },
  }
</script>

Now the problem is that I couldn't find a working way to pass in the row's data into the modal dialogs ('edit' and 'delete'). I need to print the Wifi's name in the modal dialog, and also to get back the information which Wifi was meant when it's deleted or modified when the user clicks on 'Save'.

What can I try next?

2

There are 2 best solutions below

2
Oluwafemi Sule On BEST ANSWER

Editing and saving a network connection

Copy a reference of the row item model so that it doesn't update the row item model until the Save button is clicked.

Set this reference to the copied row item model on the component instance. Then set the v-model attribute for input fields to field values in the reference.

Implement the saveNetwork method for clicks to the Save button and copy field values from the reference to the row item model.

Deleting a network connection

Assuming that the SSID is unique for the connections in wifiNetworks, update wifiNetworks to the list of networks with the network with the SSID in the copied reference excluded.

<template>
  <div class="pa-4 text-center">
    <v-dialog v-model="showEditDialog" max-width="600">
      <v-card prepend-icon="mdi-account" title="Edit Wifi settings">
        <v-card-text>
          <v-row dense>
            <v-col cols="12" md="4" sm="6">
              <v-text-field
                hint="Enter the Wifi password of your router."
                label="Wifi Password *"
                type="text"
                required="true"
                v-model="itemRef.value.SSID"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6">
              <v-checkbox
                v-model="itemRef.value.autoConnect"
                label="Auto-Connect"
              >
              </v-checkbox>
            </v-col>
          </v-row>

          <small class="text-caption text-medium-emphasis"
            >* indicates a required field</small
          >
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>

          <v-btn
            text="Close"
            variant="plain"
            @click="showEditDialog = false"
          ></v-btn>

          <v-btn
            color="primary"
            text="Save"
            variant="tonal"
            @click="saveNetwork()"
          ></v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <v-dialog v-model="showDeleteDialog" max-width="500">
      <v-card title="Delete Wifi">
        <v-card-text>
          Are you sure you want to remove {{ itemRef.value.SSID }} from the list
          of known Wifis?
        </v-card-text>

        <v-card-actions>
          <v-spacer></v-spacer>

          <v-btn
            text="Cancel"
            variant="plain"
            @click="hideDeleteWifiDialog()"
          ></v-btn>

          <v-btn
            color="red"
            text="Delete Wifi"
            variant="tonal"
            prepend-icon="$vuetify"
            @click="deleteWifi()"
          ></v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>

  <v-data-table
    :headers="headers"
    :items="wifiNetworks"
    :items-per-page="20"
    :items-per-page-options="[
      { value: 20, title: '20' },
      { value: -1, title: 'All' },
    ]"
  >
    <template v-slot:item.autoConnect="{ item }">
      <v-chip
        :color="item.autoConnect ? 'green' : 'black'"
        :text="item.autoConnect ? 'Yes' : 'No'"
        :variant="item.autoConnect ? 'tonal' : 'text'"
        size="small"
        label
      >
      </v-chip>
    </template>

    <template v-slot:item.isConnected="{ item }">
      <div class="text-end">
        <v-chip
          :color="item.isConnected ? 'green' : 'black'"
          :text="item.isConnected ? 'Connected' : 'Connect'"
          :variant="item.isConnected ? 'tonal' : 'outlined'"
          @click="item.isConnected ? {} : { click: connect(item) }"
          size="small"
          label
        >
        </v-chip>
      </div>
    </template>

    <template v-slot:item.action="{ item }">
      <v-icon class="me-2" size="small" @click="editItem(item)">
        mdi-pencil
      </v-icon>
      <v-icon
        size="small"
        @click="showDeleteWifiDialog(item)"
        :disabled="false"
      >
        mdi-delete
      </v-icon>
    </template>
  </v-data-table>
</template>

<script>
import { ref } from 'vue';

export default {
  data: () => ({
    showEditDialog: false,
    showDeleteDialog: false,
    headers: [
      { title: 'Network Name (SSID)', key: 'SSID' },
      { title: 'Security Type', key: 'security' },
      { title: 'Auto Connect', key: 'autoConnect' },
      { title: 'Action', key: 'action' },
      { title: 'Connection', key: 'isConnected' },
    ],
    wifiNetworks: [
      {
        SSID: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
        security: 'WEP',
        isConnected: false,
        autoConnect: true,
        action: 'connect',
      },
      {
        SSID: 'XYZ',
        security: 'WPA2',
        isConnected: true,
        autoConnect: true,
        action: 'connect',
      },
      {
        SSID: '0x1234',
        security: 'None',
        isConnected: false,
        autoConnect: false,
        action: 'connect',
      },
      {
        SSID: 'BGT',
        security: 'WPA',
        isConnected: false,
        autoConnect: false,
        action: 'connect',
      },
    ],
  }),

  methods: {
    editItem(item) {
      this.item = item;
      this.itemRef = ref({ ...item });
      this.showEditDialog = true;
    },
    showDeleteWifiDialog(item) {
      this.item = item;
      this.itemRef = ref({ ...item });
      this.showDeleteDialog = true;
    },
    saveNetwork() {
      this.showEditDialog = false;
      this.item.SSID = this.itemRef.value.SSID;
      this.item.autoConnect = this.itemRef.value.autoConnect;
    },
    hideDeleteWifiDialog() {
      this.showDeleteDialog = false;
    },
    deleteWifi(item) {
      this.showDeleteDialog = false;
      this.wifiNetworks = this.wifiNetworks.filter(
        (w) => w.SSID !== this.itemRef.value.SSID
      );
    },
  },
};
</script>

Stackblitz

0
Igor Moraru On

You can achieve this by saving the edited item in component data. Then manipulate this object in the dialog and save it back to items array on save (or delete it from array on delete).

data: () => ({
    editedItem: {},
    // ... 
}),
methods: {
    editItem(item) {
      this.editedItem = Object.assign({}, item);
      this.showEditDialog = true;
    },
    saveItem() {
      this.showEditDialog = false;
      let index = this.wifiNetworks.findIndex(
        (wifi) => wifi.SSID === this.editedItem.SSID
      );
      this.wifiNetworks[index] = Object.assign({}, this.editedItem);
    },
    showDeleteWifiDialog(item) {
      this.editedItem = Object.assign({}, item);
      this.showDeleteDialog = true;
    },
    hideDeleteWifiDialog() {
      this.editedItem = {};
      this.showDeleteDialog = false;
    },
    deleteWifi() {
      this.wifiNetworks.splice(this.wifiNetworks.indexOf(this.editedItem), 1);
      this.showDeleteDialog = false;
    },
}

Note: In the second dialog, you have a template tag that does not belong there.