@nurzhannogerbek

Как передать данные из дочернего компонента в родительский?

Здравствуйте, товарищи! Помогите пожалуйста разобраться cо структурой во Vue.js приложении.

Есть два компонента. Первый называется YandexMap (родительский), второй Navbar (дочерний).

В компоненте YandexMap я инициализирую карту, делаю запрос к API через пакет axios по определенному url адресу и полученные результаты наношу на карту.

Сейчас возник вопрос. При нажатии кнопки в дочернем компоненте Navbar, мне нужно отправить данные (в моем случаи начальную и конечную дату) в родительский компонент YandexMap. Эти данные я хотел бы использовать в url адресе к API, чтобы построить новые гео-объекты. Как это сделать и насколько текущая организация кода правильная?

Второй вопрос при нажатии вышеупомянутой кнопку, мне нужно почистить яндекс карту, которая инициализирована в родительском компоненте. Как это сделать? Подскажите пожалуйста.

YandexMap.vue:
<template>
    <div>
        <Navbar/>
        <div id="yandex-map"></div>
        <Preloader v-if="loading"/>
    </div>
</template>

<script>
    import axios from 'axios';

    import Preloader from './Preloader.vue'
    import Navbar from './Navbar.vue'

    export default {
        name: "YandexMap",
        components: {
            Preloader,
            Navbar
        },
        data() {
            return {
                loading: false
                start_date: "2018-10-01"
                end_date:"2018-10-31"
            }
        },
        mounted() {
            // Установить скрипты для использования яндекс карты
            let scriptYandexMap = document.createElement('script');
            scriptYandexMap.setAttribute('src', 'https://api-maps.yandex.ru/2.1/?apikey=key&lang=ru_RU');
            document.head.appendChild(scriptYandexMap);

            // Инициализировать яндекс карту и установка гео-объектов на карте
            scriptYandexMap.addEventListener("load", this.geoObjects);
        },
        methods: {
            geoObjects() {
                    // Создаем карту
                    self.map = new ymaps.Map("yandex-map", {
                        center: [48.583213, 66.017493],
                        zoom: 5,
                        controls: ['zoomControl', 'searchControl', 'fullscreenControl' ],
                        searchControlProvider: 'yandex#search'
                    });

                    // Показать Preloader
                    self.loading = true;

                    // Выполняем запросы
                    axios.all([
                        axios.get('http://localhost:3000/api/markers?start_date=' + self.start_date + '&end_date=' + self.end_date),
                        axios.get('http://localhost:3000/api/polygons?start_date=' + self.start_date + '&end_date=' + self.end_date)
                    ]).then(axios.spread(function (markers, polygons){
                        
                        // Здесь опустил код, который наносит гео-объекты на карту

                        // Убираю Preloader, после того как все гео-объекты нанеслись на карту
                        self.loading = false;
                    }));
            }
        }
    }
</script>


Navbar.vue:
<template>
    <b-navbar toggleable type="warning" variant="warning">
        <v-date-picker class='v-date-picker'
                       mode='range'
                       v-model='range'
                       :show-day-popover=false
                       is-double-paned
                       show-caps>
        </v-date-picker>

        <b-button class="search-btn" v-on:click="search">
            <font-awesome-icon :icon="faSearch"/>
        </b-button>
    </b-navbar>
</template>

<script>
    import Vue from 'vue';

    import VCalendar from 'v-calendar'
    import 'v-calendar/lib/v-calendar.min.css';

    import FontAwesomeIcon from '@fortawesome/vue-fontawesome'
    import  faSearch from '@fortawesome/free-solid-svg-icons'

    Vue.use(VCalendar);

    export default {
        name: "Navbar",
        data() {
            return {
                range: {
                    start: null,
                    end: null
                },
                faSearch: faSearch
            }
        },
        components: {
            FontAwesomeIcon
        },
        methods: {
            search: function () {
                console.log(this.range.start); // Выбранное пользователем начальная дата
                console.log(this.range.end); // Выбранное пользователем конечная дата
            }
        }
    }
</script>
  • Вопрос задан
  • 512 просмотров
Решения вопроса 1
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
NogerbekNurzhan, у вас метод geoObject слишком "умный". Нужна декомпозиция. Отдельный метод создает карту, отдельный метод манипулирует отображаемыми объектами, еще один может очищать объекты. пример: createMap(), setObjects(dateStart, dateEnd), deleteObjects()
На ивент пишете отдельный обработчик @clicked=onChangeDate в котором вызываете пересоздание объектов на существующей карте
onChangeDate(dateStart, dateEnd) {
  this.deleteObjects();
  this.setObjects(dateStart, dateEnd);
}


---------------------------------
В идеале вообще вынести непосредственно карту в отдельный компонент, в который упрятать все манипуляции с картой, а то что у вас сейчас называется YandexMap - это все-таки композитный компонент, содержащий и карту и панель управления.
Тогда управление картой можно будет свести к передаче пропсов, как-то так
<MyComp>
  <Navbar @clicked="onChangeDate"/>
  <YandexMap
    :date-start="dateStart"
    :date-end="dateEnd"
  />
<MyComp>
<script>
data: function(){
  return {
    dateStart: null,
    dateEnd: null,
  }
}
methods: {
  onchangeDate(d1, d2){
    this.dateStart = d1;
    this.dateEnd = d2;
  }
}
</script>


ну а в компоненте YandexMap соответственно добавить пропсы для дат, повесить слушателя на их изменение и в его обработчике очищать объекты и загружать новые.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@99percent
Frontend-разработчик
В дочернем компоненте на клик this.$emit('event-name', data). В родительском в темплейте на дочернем компоненте: @event-name="handler". Прям как Alex привел пример.
Ответ написан
Комментировать
@Safe_Mode
Вообще, это антипаттерн, так даже в доках вью сказано, данные нужно хранить в состоянии приложения, хотя бы использую просто отдельный экземпляр вью
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы