| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- <template>
- <q-select
- v-model="selectedCity"
- v-bind="$attrs"
- use-input
- hide-selected
- fill-input
- clearable
- :options="cityOptions"
- :label="label"
- :loading="loading"
- :placeholder="$t('common.actions.search') + ' ' + $t('ui.navigation.city')"
- :rules="rules"
- :disable="disable"
- label-color="primary"
- @filter="filterFn"
- >
- <template #no-option>
- <q-item>
- <q-item-section class="text-grey">
- {{ $t("http.errors.no_records_found") }}
- </q-item-section>
- </q-item>
- </template>
- </q-select>
- </template>
- <script setup>
- import { getCities } from "src/api/city";
- import { ref, onMounted, watch } from "vue";
- import { useI18n } from "vue-i18n";
- const emit = defineEmits(["selectedStateId"]);
- const { state, label, rules, initialId, disable } = defineProps({
- // This country prop is here for future use, maybe
- country: {
- type: Object,
- required: false,
- default: () => {
- return {
- label: "Brasil",
- value: 1,
- };
- },
- },
- state: {
- type: Object,
- required: false,
- default: null,
- },
- label: {
- type: String,
- default: () => useI18n().t("ui.navigation.city"),
- },
- rules: {
- type: Array,
- default: () => [],
- },
- initialId: {
- type: Number,
- required: false,
- default: null,
- },
- disable: {
- type: Boolean,
- default: false,
- },
- });
- const selectedCity = defineModel();
- const loading = ref(false);
- const filteredCities = ref([]);
- const baseCities = ref([]);
- const cityOptions = ref([]);
- const filterFn = async (val, update) => {
- if (!val) {
- cityOptions.value = filteredCities.value.map((city) => ({
- label: city.name,
- value: city.id,
- state_id: city.state_id,
- }));
- } else {
- const needle = val.toLowerCase();
- const cities = filteredCities.value.filter(
- (v) => v.name.toLowerCase().indexOf(needle) > -1,
- );
- cityOptions.value = cities.map((city) => ({
- label: city.name,
- value: city.id,
- state_id: city.state_id,
- }));
- }
- update();
- };
- const selectCityByName = (name) => {
- if (selectedCity.value?.label === name) {
- return;
- }
- selectedCity.value = cityOptions.value.find((city) => city.label === name);
- };
- const selectCityById = (id) => {
- if (selectedCity.value?.value === id) {
- return;
- }
- selectedCity.value = cityOptions.value.find((city) => city.value === id);
- };
- watch(
- () => state,
- (value, oldValue) => {
- if (
- value?.value != oldValue?.value &&
- value?.value != selectedCity.value?.state_id
- ) {
- selectedCity.value = null;
- }
- if (value) {
- filteredCities.value = baseCities.value.filter(
- (city) => city.state_id === value.value,
- );
- cityOptions.value = filteredCities.value.map((city) => ({
- label: city.name,
- value: city.id,
- state_id: city.state_id,
- }));
- } else {
- filteredCities.value = baseCities.value;
- cityOptions.value = baseCities.value.map((city) => ({
- label: city.name,
- value: city.id,
- state_id: city.state_id,
- }));
- }
- },
- { immediate: true },
- );
- watch(selectedCity, () => {
- if (selectedCity.value?.state_id) {
- emit("selectedStateId", selectedCity.value.state_id);
- }
- });
- onMounted(async () => {
- try {
- loading.value = true;
- baseCities.value = await getCities();
- filteredCities.value = baseCities.value;
- cityOptions.value = baseCities.value.map((city) => ({
- label: city.name,
- value: city.id,
- state_id: city.state_id,
- }));
- if (initialId) {
- selectCityById(initialId);
- }
- } catch (e) {
- console.error(e);
- } finally {
- loading.value = false;
- }
- });
- defineExpose({
- selectCityByName,
- selectCityById,
- });
- </script>
|