DrillDown Pt.4

Continuation from [pt.3](https://qiita.com/tayama468/items/6a330b4c537e36ae633a)

## Implementation

### 3. components/DrillDown.vue

#### Create files

```shell
touch components/DrillDown.vue
mkdir -p __mock__/api/drillDown
touch __mock__/api/drillDown/dummy.json
touch __mock__/api/drillDown/GET.js
touch store/drillDown.js
```

#### Set form data to DrillDown.vue in DrillDownSearch.vue

```shell
vim pages/DrillDownSearch.vue
```

▼

```vuejs
// pages/DrillDownSearch.vue
<template>
  <v-app>
    <div>
      <v-btn @click="open" block>
        Components Button
      </v-btn>
      <ConfirmDialog ref="confirm">
        <DrillDown :firstItems="firstItems" :initial-item="initialItem"></DrillDown>
      </ConfirmDialog>
    </div>
  </v-app>
</template>

<script>
  // ...
  import DrillDown from '../components/DrillDown.vue'
  export default {
    components: { Button, ConfirmDialog, DrillDown },
    data() {
      return {
        firstItems: [1, 2, 3],
        initialItem: {
          option1: 1,
          option2: '',
          option3: ''
        },
        isDialogOpened: false
      }
    },
    // ...
  }
</script>
```

▼

```shell
vim components/DrillDown.vue
```

▼

```vuejs
// components/DrillDown.vue
<template>
  <div>
    <v-container fluid>
      <v-select v-for="(value, key) in initialItem"
        :key="key"
        :value="value"
        :items="getOption(key)"
        :label="key"
        outlined
      ></v-select>
    </v-container>
  </div>
</template>
<script>
  export default {
    props: {
      initialItem: {
        type: Object,
        default: {}
      },
      firstItems: {
        type: Array,
        default: []
      }
    },
    computed: {
      option1() {
        if (this.firstItems.length === 0) return []
        return [{ text: '選択してください', value: ''}, ...this.firstItems]
      },
      option2() {
        return [{ text: '選択してください', value: ''}]
      },
      option3() {
        return [{ text: '選択してください', value: ''}]
      }
    },
    methods: {
      getOption(key) {
        switch (key) {
          case 'option1':
            return this.option1
          case 'option2':
            return this.option2
          case 'option3':
            return this.option3
        }
      }
    }
  }
</script>
```

#### Prepare dummy data

```shell
vim __mock__/api/drillDown/dummy.json
```

▼

```json
// __mock__/api/drillDown/dummy.json
{
  "1": [
    {"text": "1-1"},
    {"text": "1-2"},
    {"text": "1-3"}
  ],
  "1-1": [
    {"text": "1-1-1"},
    {"text": "1-1-2"},
    {"text": "1-1-3"}
  ],
  "1-2": [
    {"text": "1-2-1"},
    {"text": "1-2-2"},
    {"text": "1-2-3"}
  ],
  "1-3": [
    {"text": "1-3-1"},
    {"text": "1-3-2"},
    {"text": "1-3-3"}
  ],
  "2": [
    {"text": "2-1"},
    {"text": "2-2"},
    {"text": "2-3"}
  ],
  "2-1": [
    {"text": "2-1-1"},
    {"text": "2-1-2"},
    {"text": "2-1-3"}
  ],
  "2-2": [
    {"text": "2-2-1"},
    {"text": "2-2-2"},
    {"text": "2-2-3"}
  ],
  "2-3": [
    {"text": "2-3-1"},
    {"text": "2-3-2"},
    {"text": "2-3-3"}
  ],
  "3": [
    {"text": "3-1"},
    {"text": "3-2"},
    {"text": "3-3"}
  ],
  "3-1": [
    {"text": "3-1-1"},
    {"text": "3-1-2"},
    {"text": "3-1-3"}
  ],
  "3-2": [
    {"text": "3-2-1"},
    {"text": "3-2-2"},
    {"text": "3-2-3"}
  ],
  "3-3": [
    {"text": "3-3-1"},
    {"text": "3-3-2"},
    {"text": "3-3-3"}
  ]
}
```

#### Prepare get function (just return dummy data)

```shell
vim __mock__/api/drillDown/GET.js
```

▼

```js
// __mock__/api/drillDown/GET.js
const dummyData = require('./dummy.json')
function get(request, response) {
  return response.json({
    http_status: 200,
    success: true,
    dummyData
  })
}
module.exports = get
```

#### Prepare action function (just fetch dummy data)

```shell
vim store/drillDown.js
```

▼

```js
// store/drillDown.js
export const actions = {
  async fetch() {
    const path = `/drillDown`
    return this.$axios.$get(path)
      .then(res => {
        const { drillDown } = res
      })
  }
}
```

#### Use action in DrillDown.vue

```shell
vim pages/DrillDownSearch.vue
```

▼

```vuejs
// pages/DrillDownSearch.vue
<template>
  <v-app>
    <div>
      <v-btn @click="open" block>
        Components Button
      </v-btn>
      <ConfirmDialog ref="confirm">
        <DrillDown :firstItems="firstItems" :initial-item="initialItem" :path="path"></DrillDown>
      </ConfirmDialog>
    </div>
  </v-app>
</template>

<script>
  const PATH = 'drillDown/fetch'
  // ...
  export default {
  // ...
    data() {
      return {
        // ...
        isDialogOpened: false,
        path: PATH
      }
    },
    // ...
  }
</script>
```

▼

```shell
vim components/DrillDown.vue
```

▼

```vuejs
// components/DrillDown.vue
// ...
<script>
  export default {
    props: {
      // ...
      firstItems: {
        type: Array,
        default: []
      },
      path: {
        type: String,
        default: ''
      }
    },
    computed: {
      // ...
    },
    mounted() {
      this.prepareOption()
    },
    methods: {
      async prepareOption() {
        await this.$store.dispatch(this.path, {
          option1: this.initialItem.option1
        })
      },
      // ...
    }
  }
</script>
```

#### Return options according to post data

```shell
vim components/DrillDown.vue
```

▼

```vuejs
// components/DrillDown.vue
// ...
<script>
  export default {
    // ...
    methods: {
      async prepareOption() {
      	// ...
        await this.$store.dispatch(this.path, {
          option1: this.initialItem.option1,
          option2: this.initialItem.option2
        })
      },
      // ...
    }
  }
</script>
```

▼

```shell
vim store/drillDown.js
```

▼

```js
// store/drillDown.js
export const actions = {
  async fetch({ commit }, params) {
    const path = `/drillDown`
    return this.$axios.$get(path, {params: params})
      .then(res => {
        const { drillDown } = res
      })
  }
}
```

▼

```shell
vim __mock__/api/drillDown/GET.js
```

▼

```js
// __mock__/api/drillDown/GET.js
// ...
function get(request, response) {
  const drillDown = makeResDataBy(request.query)
  return response.json({
    // ...
    drillDown
  })
}
function makeResDataBy(params) {
  const res = {
    option2: null,
    option3: null
  }
  const reqKeys = Object.keys(params)
  const resKeys = Object.keys(res)
  const reqLength = Object.keys(params).length
  const reqKey = reqKeys[reqLength - 1]
  const resKey = resKeys[reqLength - 1]
  const reqValue = params[reqKey]
  res[resKey] = dummyData[reqValue]

  return res
}
module.exports = get
```

#### Store fetch data

```shell
vim store/drillDown.js
```

▼

```js
// store/drillDown.js
export const state = () => ({
  option2: null,
  option3: null
})

export const mutations = {
  SET(state, obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      if (obj[keys[i]]) {
        state[keys[i]] = obj[keys[i]]
        break
      }
    }
  }
}

export const actions = {
   async fetch({ commit }, params) {
    // ...
    return this.$axios.$get(path, {params: params})
      .then(res => {
        // ...
        commit('SET', drillDown)
      })
  }
}
```

#### Set initial option and value

```shell
vim components/DrillDown.vue
```

▼

```vuejs
// components/DrillDown.vue
<template>
  <div>
    <v-container fluid>
      <v-select v-for="(value, key) in initialItem"
        :key="key"
        :value="value"
        :items="getOption(key)"
        :label="key"
        :disabled="isDisabled(key)"
        outlined
      ></v-select>
    </v-container>
  </div>
</template>
<script>
  export default {
    // ...
    data: () => ({
      item1: '',
      item2: '',
      item3: '',
      canSelect: {
        option1: true,
        option2: false,
        option3: false,
      },
      isSetInitialOption: false
    }),
    computed: {
      // ...
      option2() {
        if (!this.$store.state.drillDown) return []
        const option = this.$store.state.drillDown.option2
        return option
          ? [{ text: '選択してください', value: ''}, ...option]
          : [{ text: '選択してください', value: ''}]
      },
      option3() {
        if (!this.$store.state.drillDown) return []
        const option = this.$store.state.drillDown.option3
        return option
          ? [{ text: '選択してください', value: ''}, ...option]
          : [{ text: '選択してください', value: ''}]
      }
    },
    methods: {
      async prepareOption() {
        // ...
        this.$nextTick(() => {
          this.setInitialValue()
        })
      },
      setInitialValue() {
        this.item1 = this.initialItem.option1 ? this.initialItem.option1 : ''
        this.item2 = this.initialItem.option2 ? this.initialItem.option2 : ''
        this.item3 = this.initialItem.option3 ? this.initialItem.option3 : ''
        this.$nextTick(() => {
          this.isSetInitialOption = true
        })
      },
      // ...
      isDisabled(key) {
        return !this.canSelect[key]
      }
    }
  }
</script>
```

#### Watch items and Update item according to new value

```shell
vim components/DrillDown.vue
```

▼

```vuejs
// components/DrillDown.vue
<template>
  <div>
    <v-container fluid>
      <v-select v-for="(value, key) in initialItem"
        :key="key"
        :value="value"
        :items="getOption(key)"
        :label="key"
        :disabled="isDisabled(key)"
        @input="newv => updateItem(newv, value, key)"
        outlined
      ></v-select>
    </v-container>
  </div>
</template>
<script>
  export default {
    // ...
    methods: {
      // ...
      updateItem(newv, value, key) {
        switch (key) {
          case 'option1':
            this.item1 = newv
            break
          case 'option2':
            this.item2 = newv
            break
          case 'option3':
            this.item3 = newv
            break
        }
      },
      // ...
    },
    watch: {
      item1(newv) {
        if (!this.isSetInitialOption) return
        this.canSelect['option3'] = false
        this.item2 = ''
        this.item3 = ''
        if (newv === '') {
          this.canSelect['option2'] = false
          return
        } 
        this.$store.dispatch(this.path, {
          option1: newv
        })
          .then(() => {
            if (this.$store.state.drillDown.option2) {
              this.canSelect['option2'] = true
            } else {
              this.canSelect['option2'] = false
            }
          })
          .catch(err => {
            console.log('/drillDown: ', err)
            this.isError = true
          })
      },
      item2(newv) {
        if (!this.isSetInitialOption) return
        this.item3 = ''
        if (newv === '') {
          this.canSelect['option3'] = false
          return
        }
        this.$store.dispatch(this.path, {
          option1: this.item1,
          option2: newv
        })
          .then(() => {
            if (this.$store.state.drillDown.option3) {
              this.canSelect['option3'] = true
            } else {
              this.canSelect['option3'] = false
            }
          })
          .catch(err => {
            console.log('/drillDown: ', err)
            this.isError = true
          })
      }
    }
</script>
```

▼

```shell
vim pages/DrillDownSearch.vue
```

▼

```vuejs
// pages/DrillDownSearch.vue
// ...
<script>
// ...
  export default {
    // ...
    data() {
      return {
      	// ...
        isResoleved: false,
        // ...
      }
    },
    computed: {
      item1() {
        return this.isResoleved ? this.$refs.drillDown.item1 : this.initialItem.option1
      },
      item2() {
        return this.isResoleved ? this.$refs.drillDown.item2 : this.initialItem.option2
      },
      item3() {
        return this.isResoleved ? this.$refs.drillDown.item3 : this.initialItem.option3
      }
    },
    methods: {
      async open() {
        // ...
        if (await this.$refs.confirm.open()) {
          // ...
          this.isResoleved = true
        } else {
          // ...
        }
      }
    }
  }
</script>
```

## Next [DrillDown Pt.5](https://qiita.com/tayama468/items/62fa0742d657467ef117)