Новые значения VueJS для реквизита отправляются вместо сброса

У меня проблема с моим проектом VueJS. Я сделал компонент GoogleMaps в DetailView.vue. Компонент карт использует три реквизита, такие как driver, waypoints и stopOver.

Структура проекта такова: App.vue содержит файл Login.vue с маршрутом к основному представлению панели мониторинга. Внутри этого MainView у меня есть некоторые элементы меню, такие как «Туры» с DataTable внутри.

Нажав на строку с данными, VueJS представляет DetailView.vue внутри v-dialog (с использованием Vuetify).

Внутри этого DetailView есть еще одна таблица данных, переключатель и вверху мой компонент карты.

<LiefermaxMap style = "width: 100%; height: 50%;" :waypoints = "waypoints" :driver = "driverLocation" :stopOver = "showCalculatedTour"></LiefermaxMap>

waypoints и driverLocation — это свойства вычисленный, showCalculatedTour — это обычное имущество, в зависимости от состояния переключателя.

Закрытие этого диалогового окна DetailVue и открытие другого тура приводит к добавлению в свойство другого набора путевых точек (и driverLocation тоже) вместо замены старых.

waypoints() {
  var points = [];
  if (!this.showCalculatedTour) {
    this.loadnoSpecific.items.items.forEach(element => {
      var p = { lat: element.latitude, lng: element.longitude, done: element.done };
      points.push(p);
    });
  } else {
    this.data.contracts.forEach(element => {
      var c = element.customer.position;
      var p = { lat: c.lat, lng: c.lng, done: element.done }
      points.push(p);
    });
  }
  console.info('points: ' + points)
  return points;
},
driverLocation() {
  const drv = this.data.location;
  const marker = { lat: drv.latitude, lng: drv.longitude };
  return marker;
},

Вот скриншот проекта.

Что я делаю неправильно?

ОБНОВИТЬ:

Ожидаемое поведение: удалить все остальные путевые точки из предыдущих выбранных туров. Фактическое поведение: путевые точки добавляются к старым.

Пример Tours.vue (вид позади диалогового окна на скриншоте):

    <template>
  <div>
    <v-toolbar flat color = "white">
      <v-toolbar-title>Touren</v-toolbar-title>
      <v-spacer></v-spacer>
    </v-toolbar>
    <v-data-table style = "width: 70vw;"
                  :headers = "headers"
                  :items = "tours.items.items"
                  :rows-per-page-items = "[5,10,20,50,100]"
                  :loading = "isLoading"
                  :total-items = "totalItems"
                  :must-sort = "true"
                  :pagination.sync = "pagination"
                  class = "elevation-1"
    >
      <template slot = "items" slot-scope = "props">
        <tr @click = "rowClicked(props.item)">
        <td class = "text-xs-left">{{ props.item.loadno }}</td>
        <td class = "text-xs-left">{{ props.item.tourname }}</td>
        <td class = "text-xs-left">{{ props.item.kfz }}</td>
        <td class = "text-xs-left">{{ props.item.driverID }}</td>
        <td class = "text-xs-left">{{ props.item.device }}</td>
        <td class = "text-xs-left">{{ props.item.created_at | formatDate }}</td>
        </tr>
      </template>
    </v-data-table>
    <v-dialog v-model = "showDetail" transition = "dialog-bottom-transition" max-width = "70vw">
      <TourDetail v-model = "showDetail" :data = "selectedTour" style = "height: 90vh;"></TourDetail>
    </v-dialog>
  </div>
</template>

<script>
import { settings } from '../settings';
import { authHeader } from '../_helpers';
import TourDetail from './TourDetail.vue';
export default {
  name: 'tours',
  components: {
    TourDetail
  },
  data() {
    return {
      totalItems: 0,
      selectedTour: {},
      showDetail: false,
      pagination: {
        descending: true,
        page: 1,
        rowsPerPage: 10,
        sortBy: 'loadno'
      },
      headers: [ // .. ]
    };
  },
  watch: {
    pagination(newValue, oldValue) {
      this.getDataFromApi();
    },
    tours(newValue, oldValue) {
      this.totalItems = newValue.items.total;
    }
  },
  mounted() {
    this.getDataFromApi();
  },
  computed: {
    tours() {
      return this.$store.state.tours.all;
    },
    isLoading() {
      return this.$store.state.tours.loading;
    }
  },
  methods: {
    rowClicked(tour) {
      const requestOptions = {
        method: 'GET',
        headers: authHeader()
      };
      const loadno = tour.loadno;
      console.info('LoadNo: ' + loadno);
      this.$store.dispatch('locations/getLoadnoSpecific', { loadno });
      fetch(
        `${settings.apiUrl}/tours/loadno/complete/` + loadno,
        requestOptions
      ).then(response =>
        response.json().then(json => {
          this.selectedTour = json.tour;
          this.showDetail = true;
        })
      );
    },
    getDataFromApi() {
      const perpage = this.pagination.rowsPerPage;
      const page = this.pagination.page;
      const sortby = this.pagination.sortBy;
      const descending = this.pagination.descending;

      this.$store.dispatch('tours/getAll', {
        perpage,
        page,
        sortby,
        descending
      });
    }
  }
};
</script>

TourDetail.vue

<template>
    <v-flex style = "height: 100%;">
      <v-toolbar
          color = "primary"
          dark
          flat
          style = "z-index: 2; position: absolute;"
        >
          <v-toolbar-title class = "justify-center">Fahrer: {{ data.driver.firstname + ' ' + data.driver.lastname  }} &nbsp; | &nbsp;  iPad: {{ data.device }} &nbsp; | &nbsp; Fahrzeug: {{ data.kfz }}</v-toolbar-title>
        </v-toolbar>
      <v-card style = "height: 100%; position: relative;">
        <LiefermaxMap style = "width: 100%; height: 50%;" :waypoints = "waypoints" :driver = "driverLocation" :stopOver = "showCalculatedTour"></LiefermaxMap>
        <v-layout row wrap style = "height: 50%;">
        <v-flex xs12>
          <v-card style = "height: 100%;">
          <v-switch v-model = "showCalculatedTour" :label = "switchLabel" style = "position: absolute; right: 10%;"></v-switch>
        <v-data-table
          :headers = "headers"
          :items = "data.contracts"
          :expand = "expand"
          :rows-per-page-text = "perPageText"
          style = "padding: 5%;"
        >
          <template slot = "items" slot-scope = "props">
            ...
          </template>
          <template slot = "expand" slot-scope = "props">
            <v-card>
              <div>
                ...
              </div>
            </v-card>
          </template>
        </v-data-table>
          </v-card>
        </v-flex>
        </v-layout>
      </v-card>
    </v-flex>
</template>

<script>
import LiefermaxMap from '../components/LiefermaxMap.vue';
export default {
  components: {
    LiefermaxMap
  },
  computed: {
    loadnoSpecific() {
      return this.$store.state.locations.loadnoSpecific;
    },
    waypoints() {
      var points = [];
      if (!this.showCalculatedTour) {
        this.loadnoSpecific.items.items.forEach(element => {
          var p = { lat: element.latitude, lng: element.longitude, done: element.done };
          points.push(p);
        });
      } else {
        this.data.contracts.forEach(element => {
          var c = element.customer.position;
          var p = { lat: c.lat, lng: c.lng, done: element.done }
          points.push(p);
        });
      }
      console.info('points: ' + points)
      return points;
    },
    driverLocation() {
      const drv = this.data.location;
      const marker = { lat: drv.latitude, lng: drv.longitude };
      return marker;
    },
    switchLabel() {
      return this.showCalculatedTour ? 'errechnete Route' : 'gefahrene Route';
    }
  },
  props: ['data'],
  data() {
    return {
      showCalculatedTour: false,
      googleWaypoints: [],
      drivenWaypoints: [],
      expand: false,
      perPageText: 'pro Seite',
      completeTourLoading: true,
      completeTour: [{}],
      selectedContract: {},
      headers: [... ]
    };
  },
  methods: { ... }
  }
};
</script>
<style scoped>
// ...
</style>

И компонент LiefermaxMap:

<template>
  <div v-show = "mapInitialized" class = "liefermaxmap" id = "liefermaxmap" ref = "liefermaxmap"></div>
</template>
<script>
export default {
  name: 'LiefermaxMap',
  props: ['waypoints', 'driver', 'stopOver'],
  data: function() {
    return {
      mapName: 'liefermaxmap',
      markerCoordinates: [{}],
      mapInitialized: false,
      directionsService: null,
      directionsDisplay: null,
      vueGMap: null,
      bounds: null,
      markers: []
    };
  },
  watch: {
    waypoints(newValue, oldValue) {
      console.info('Waypoints changed, count: ' + newValue.length);
      console.info(newValue)
      this.setWaypoints();
    }
  },
  methods: {
    createGoogleMaps: function() {
      return new Promise((resolve, reject) => {
        let gmap = document.createElement('script');
        gmap.src =
          'https://maps.googleapis.com/maps/api/js?key=XXXX';
        gmap.type = 'text/javascript';
        gmap.onload = resolve;
        gmap.onerror = reject;
        document.querySelector('head').appendChild(gmap);
      });
    },
    initGoogleMaps: function() {
      const localOptions = {
        zoom: 4,
        center: this.driver,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        panControl: true,
        mapTypeControl: true,
        mapTypeControlOptions: {
          position: google.maps.ControlPosition.RIGHT_BOTTOM
        },
        panControlOptions: {
          position: google.maps.ControlPosition.RIGHT_CENTER
        },
        zoomControl: true,
        zoomControlOptions: {
          style: google.maps.ZoomControlStyle.LARGE,
          position: google.maps.ControlPosition.RIGHT_CENTER
        },
        scaleControl: false,
        streetViewControl: false,
        streetViewControlOptions: {
          position: google.maps.ControlPosition.RIGHT_CENTER
        }
      };

      this.vueGMap = new google.maps.Map(
        this.$refs['liefermaxmap'],
        localOptions
      );
      // eslint-disable-next-line
      var drivermarker = new google.maps.Marker({
        position: new google.maps.LatLng(this.driver),
        map: this.vueGMap,
        icon: 'http://maps.google.com/mapfiles/ms/micons/truck.png'
      });
      this.directionsService = new google.maps.DirectionsService();
      this.directionsDisplay = new google.maps.DirectionsRenderer();
      this.directionsDisplay.setMap(this.vueGMap);
      this.mapInitialized = true;
    },
    addMarker(latLng, color) {
      let url = 'http://maps.google.com/mapfiles/ms/icons/';
      url += color + '-dot.png';

      let marker = new google.maps.Marker({
        map: this.vueGMap,
        position: latLng,
        icon: {
          url: url
        }
      });
    },
    setWaypoints() {
      this.directionsService = new google.maps.DirectionsService();
      this.directionsDisplay = new google.maps.DirectionsRenderer();
      this.directionsDisplay.setMap(this.vueGMap);
      var googleWaypoints = [];
      this.waypoints.forEach(element => {
        var pos = new google.maps.LatLng(element.lat, element.lng);
        var wp = { location: pos, stopover: false };
        googleWaypoints.push(wp);
        console.info(element)
        if (element.done == true) {
          this.addMarker(pos, 'green')
        } else {
          this.addMarker(pos, 'red')
        }
      });

      var i = 0;
      var j = 0;
      var temparray = [];
      var chunk = 15;

      for (i = 0, j = googleWaypoints.length; i < j; i += chunk) {
        temparray = googleWaypoints.slice(i, i + chunk);
        var request = {
          origin: 'XXX',
          destination: 'XXX',
          travelMode: 'DRIVING',
          optimizeWaypoints: true,
          waypoints: temparray
        };
        this.directionsService.route(request, (result, status) => {
          if (status === 'OK') {
            this.directionsDisplay.setDirections(result);
            console.info(result);
          }
        });
      }
    },
    googleMapsFailedToLoad() {
      this.vueGMap = 'Error while loading map';
    }
  },
  mounted() {
    this.initGoogleMaps();
  }
};
</script>
<style scoped>
.liefermaxmap {
  width: 100%;
  height: 100%;
}
</style>

Мое предложение состоит в том, чтобы использовать часы вместо вычислений. И в смонтированном присвойте значение вашим полям данных. Вам нужно будет смонтировать для первой инициализации и следить за каждым изменением данных. Удачи.

mare96 13.06.2019 17:38

Можете ли вы указать, каково ваше ожидаемое поведение и ваше фактическое поведение? не понятно в чем проблема. Когда вы переключаетесь с одного тура на другой, видите ли вы старые точки данных на карте?

Daniel Ormeño 13.06.2019 17:58

Кроме того, можете ли вы обновить вопрос с помощью шаблона, чтобы увидеть, как вы показываете/скрываете диалоговое окно?

Daniel Ormeño 13.06.2019 18:01

Я обновил свой вопрос с кодом компонентов

Pascal Friedrich 13.06.2019 18:20

может я просто не вижу - а где вы удаляете модификации карты? - ой в смонтированном - вот оно

Estradiaz 13.06.2019 21:48
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
5
307
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

vue повторно использует компоненты — используйте key для принудительного монтирования


Изменять

<LiefermaxMap style = "width: 100%; height: 50%;" :waypoints = "waypoints" :driver = "driverLocation" :stopOver = "showCalculatedTour"></LiefermaxMap>

к

<LiefermaxMap style = "width: 100%; height: 50%;" :key = "waypoints" :waypoints = "waypoints" :driver = "driverLocation" :stopOver = "showCalculatedTour"></LiefermaxMap>

используйте key, чтобы указать vue не использовать компонент повторно, чтобы можно было запустить монтирование,

или переместите свой метод initMap.

Другие вопросы по теме