@NogerbekNurzhan

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

Здравствуйте, товарищи! Помогите пожалуйста разобраться 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>
  • Вопрос задан
  • 257 просмотров
Решения вопроса 1
dpr
@dpr
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
Вообще, это антипаттерн, так даже в доках вью сказано, данные нужно хранить в состоянии приложения, хотя бы использую просто отдельный экземпляр вью
Ответ написан
Ваш ответ на вопрос

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

Войти через TM ID
Похожие вопросы
Ingram Micro Cloud Москва
от 170 000 руб.
//stablecode Вена
от 110 000 до 140 000 руб.
IT Company Санкт-Петербург
от 120 000 до 200 000 руб.
22 янв. 2019, в 17:47
300 руб./за проект
22 янв. 2019, в 17:36
600 руб./за проект
22 янв. 2019, в 17:30
100 руб./за 1000 зн.