VueJS Child component GMAP not rerender when parent data updates - google-maps

Hi I'm new with Vue and I bump to this problem where when I update the location it doesn't reflect on the child component. I've used computed and watch but still not updating. forgive me as I don't have a strong knowledge about VueJS.
so in my code I have location(computed) which listen to localLocation(data) that is bind to the project.location. I update the location using the method setPlace()
hope anyone can help. here's my code below:
<template lang="pug">
.google-maps-wrapper
template(v-if="!location")
f7-list.no-margin-top
f7-list-button(title='Add Location' #click="isAutocompleteOpen = true")
template(v-if="location")
f7-list.no-margin(inline-labels no-hairlines-md)
f7-list-item.short-text Address: {{ location.formattedAddress }}
div
gmap-map.main-map(ref="googleMap" :options="mapOptions" :center="location.position" :zoom="16" :map-type-id="mapTypeId")
gmap-marker(:position="location.position" :clickable="false")
f7-actions(ref='mapsAction')
f7-actions-group
f7-actions-group
f7-actions-button(#click="copyToClipboard()") Copy to Clipboard
f7-actions-button(#click="isAutocompleteOpen = true") Change Address
f7-actions-button(v-if="$root.$device.ios || $root.$device.macos" #click="$refs.navigateActions.f7Actions.open()") Navigate
f7-actions-button(v-else #click="googleMapsNavigate()") Navigate
f7-actions-group
f7-actions-button
b Cancel
f7-actions(ref='navigateActions')
f7-actions-group
f7-actions-group
f7-actions-button(#click="googleMapsNavigate()") Google Maps
f7-actions-button(#click="appleMapsNavigation()") Apple Maps
f7-actions-group
f7-actions-button
b Cancel
f7-popup.locate-project(:opened='isAutocompleteOpen' #popup:closed='closeAutocomplete()')
f7-page
f7-navbar
f7-nav-title Search Location
f7-nav-right
f7-link(#click="closeAutocomplete()") Close
f7-searchbar.searchbar(search-container=".search-list" search-in=".item-title" #input="searchLocation($event)" placeholder="Enter Location" clear-button)
f7-list.not-found(v-if="!pendingSearch && !suggestedLocations.length && searchedLocation")
f7-list-item(title="Nothing found")
f7-block-title.gmap-preloader(v-if="pendingSearch")
f7-preloader(size="16")
f7-list.search-list.searchbar-found.gmap-search-list(v-if="!pendingSearch && suggestedLocations.length" media-list)
f7-list-item.item-button(v-for='(location, index) in suggestedLocations' :title="location.structured_formatting.main_text" :subtitle="location.structured_formatting.secondary_text" #click="updateLocation(location)")
</template>
<script>
import { debounce } from 'lodash-es'
import { Plugins } from '#capacitor/core'
const { Clipboard } = Plugins
const { Browser } = Plugins
const debounceSearch = debounce(run => {
run()
}, 500)
import defaultMixin from '#/mixins/default'
import {
f7Actions,
f7ActionsLabel,
f7ActionsGroup,
f7ActionsButton,
f7Popup,
f7Page,
f7NavRight,
f7NavTitle,
f7Navbar,
f7Block,
f7BlockTitle,
f7Label,
f7Link,
f7Preloader,
f7List,
f7ListButton,
f7ListItem,
f7ListInput,
f7Icon,
f7Searchbar
} from 'framework7-vue'
import { gmapApi } from 'vue2-google-maps'
export default {
name: "google-maps",
mixins: [defaultMixin],
props: ['project'],
components: {
f7Actions,
f7ActionsLabel,
f7ActionsGroup,
f7ActionsButton,
f7Popup,
f7Page,
f7NavRight,
f7NavTitle,
f7Navbar,
f7Block,
f7BlockTitle,
f7Label,
f7Link,
f7Preloader,
f7List,
f7ListButton,
f7ListItem,
f7ListInput,
f7Icon,
f7Searchbar
},
data() {
return {
mapTypeId: "terrain",
directionsService: undefined,
directionsDisplay: undefined,
autocompleteService: undefined,
autocompleteRequest: undefined,
navigate: false,
localLocation: this.project.location,
mapOptions: {
disableDefaultUI: true,
backgroundColor: '#d3d3d3',
draggable: false,
zoomControl: false,
fullscreenControl: false,
streetViewControl: false,
clickableIcons: false
},
isAutocompleteOpen: false,
suggestedLocations: [],
pendingSearch: false,
origin: '',
searchedLocation: ''
}
},
computed: {
location() {
return this.localLocation
},
google: gmapApi
},
methods: {
appleMapsNavigation(){
window.open(`http://maps.apple.com/?daddr=${encodeURI(this.project.location.formattedAddress)}`)
},
googleMapsNavigate(){
if(this.$root.$device.ios){
window.open(`comgooglemaps://?daddr=${encodeURI(this.project.location.formattedAddress)}`)
}else{
window.open(`https://www.google.com/maps/dir//${encodeURI(this.project.location.formattedAddress)}`)
}
},
closeAutocomplete() {
this.isAutocompleteOpen = false
this.searchedLocation = ''
this.suggestedLocations = []
this.$f7.searchbar.clear('.searchbar')
},
updateLocation( location ){
this.getGeocode(location.place_id, output => {
this.suggestedLocations = []
this.setPlace(output[0])
})
},
getGeocode( placeId, callback ){
const geocoder = new google.maps.Geocoder()
this.$f7.dialog.preloader()
geocoder.geocode({placeId}, output => {
callback(output)
this.closeAutocomplete()
this.$f7.dialog.close()
})
},
searchLocation( event ) {
this.pendingSearch = true
this.searchedLocation = event.target.value
debounceSearch(() => {
if(!this.searchedLocation) {
this.pendingSearch = false
this.suggestedLocations = []
return
}
const autocompleteService = new google.maps.places.AutocompleteService()
autocompleteService.getPlacePredictions({input: this.searchedLocation}, output => {
if(this.pendingSearch){
this.suggestedLocations = output || []
this.pendingSearch = false
}
})
})
},
setPlace( selectedLocation ) {
if(!selectedLocation.formatted_address) return;
const data = {
location: {
formattedAddress: selectedLocation.formatted_address,
position: {
lat: selectedLocation.geometry.location.lat(),
lng: selectedLocation.geometry.location.lng()
}
}
};
this.$f7.popup.close('.add-location')
if(this.$refs.autocomplete) this.$refs.autocomplete.$el.disabled = true
this.localLocation = data.location
db.collection("projects")
.doc(this.project.id)
.set(data, {
merge: true
})
.then()
},
copyToClipboard() {
Clipboard.write({
string: this.project.location.formattedAddress
});
}
}
}
</script>
Code Summary (just the summary of the whole code above)
Template that displays the address and map
.google-maps-wrapper
template(v-if="!location")
f7-list.no-margin-top
f7-list-button(title='Add Location' #click="isAutocompleteOpen = true")
template(v-if="location")
f7-list.no-margin(inline-labels no-hairlines-md)
f7-list-item.short-text Address: {{ location.formattedAddress }}
div
gmap-map.main-map(ref="googleMap" :options="mapOptions" :center="location.position" :zoom="16" :map-type-id="mapTypeId")
gmap-marker(:position="location.position" :clickable="false")
Last line of the template where it updates the location
f7-list-item.item-button(v-for='(location, index) in suggestedLocations' :title="location.structured_formatting.main_text" :subtitle="location.structured_formatting.secondary_text" #click="updateLocation(location)")
Script that updates the location
updateLocation( location ){
this.getGeocode(location.place_id, output => {
this.suggestedLocations = []
this.setPlace(output[0])
})
},
setPlace( selectedLocation ) {
if(!selectedLocation.formatted_address) return;
const data = {
location: {
formattedAddress: selectedLocation.formatted_address,
position: {
lat: selectedLocation.geometry.location.lat(),
lng: selectedLocation.geometry.location.lng()
}
}
};
this.$f7.popup.close('.add-location')
if(this.$refs.autocomplete) this.$refs.autocomplete.$el.disabled = true
this.localLocation = data.location
db.collection("projects")
.doc(this.project.id)
.set(data, {
merge: true
})
.then()
},
Initial Page No Address yet
Actual Output after adding location
Expected Output

Related

Forge Autodesk_Error_Customtooltip

Does anyone know how to fix the error. My goal is to put some graphs in a customtooltip.
I have taken the variables from the example on the web. I don't know what is causing me to not be able to see the customtooltip.
Thank you
const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
const DataVizCore = Autodesk.DataVisualization.Core;
const DataVizUI = Autodesk.DataVisualization.UI;
function onSpriteHovering(event) {
const targetDbId = event.dbId;
var id = targetDbId;
var xcoord = 262.76056690205695;
var ycoord = 357.1343908626808;
var hoveredDeviceInfo = {
id,
xcoord,
ycoord
}
var currentDeviceData = {
"Device-01": {
"CO₂": "495.71 ppm",
"Humidity": "34.33 %RH",
"Temperature": "21.18 Celsius"
}
};
var chartData = {
"Device-01": {
name: "",
properties: {
"CO₂": {
dataUnit: "ppm",
seriesData: [{
value: [1612396800000, 492.55117490452676],
label: {}
},
{
value: [1612400400000, 494.27072441289187],
label: {}
}
],
yAxis: {
dataMin: 450,
dataMax: 680
}
},
"Humidity": {
dataUnit: "%RH",
seriesData: [{
value: [1612396800000, 34.58961659380417],
label: {}
}],
yAxis: {
dataMin: 25,
dataMax: 50
}
},
}
}
};
const bocadilloemergente = new DataVizUI.CustomToolTip(hoveredDeviceInfo, chartData, currentDeviceData);
}
Error in the console:
The variable was defined in a different context, and not available during the mouse event. The customtooltip is shipped using react component not data visualization extension so you need refer to the react component package to use the tooltip.
Look here
Install the package

How to get xyz cordinates of forge-viewer onClick event?

I am following this (https://stackblitz.com/edit/angular-forge-viewer-pjyarf?file=app%2Fapp.component.ts) link to get the xyz cordinates of viewer onclick event in Angular.I cant get the viewer properly. Please help to get the solution.
ngOnInit() {
this.mainFunction();
}
mainFunction(){
this.viewerOptions = {
initializerOptions: {
env: 'AutodeskProduction',
getAccessToken: (
onGetAccessToken: (token: string, expire: number) => void
) => {
const expireTimeSeconds = 60 * 30;
onGetAccessToken(ACCESS_TOKEN, expireTimeSeconds);
},
api: 'derivativeV2',
enableMemoryManagement: true,
},
onViewerInitialized: (args: ViewerInitializedEvent) => {
args.viewerComponent.DocumentId = DOCUMENT_URN;
this.viewer=args.viewer;
},
};
}
selectionChanged(e){
const state = this.viewer.viewerState.getState({ viewport: true });
const globalOffset = this.viewer.model.myData.globalOffset
const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
const originPosition = currentPosition.clone().add( globalOffset );
console.log("hiiihhaaaaaa:",originPosition);
}

How to restrict Google Maps search results to only one country properly?

I am developing an application, in Ionic, where you can plan a trip with a start address and and end address. However I want to limit this feature to only one country. Before writing I have been searching for solutions on the internet, but none of them worked for me.
Have tried these suggestions:
https://stackoverflow.com/a/8282093/8130808
https://stackoverflow.com/a/10170421/8130808
Here is how I have tried to approach it:
//Places markers and displays a route, so the user can accept the current placing
newRoutePlaceMarks(place: any): void {
var googleDiplay = new google.maps.DirectionsRenderer({ draggable: true });
var route = this.directionsDisplay;
//A bit of a hack, sadly Typescript and google maps arent the best of buddies
this.directionsService.route({
origin: this.routeStart,
destination: this.routeEnd,
travelMode: 'DRIVING',
}, function (response, status) {
if (status === 'OK') {
console.log("status is OK trying to put directions up");
//The reason why I've set the addListener before the actual route is so it gets triggered
//on the creation of the route. Had some problem with figuring out how to actually handle
//the data when on the route creation, as this response function is in strict mode, and outside
google.maps.event.addListener(route, "directions_changed", function () {
console.log("Route changed");
this.global = ShareService.getInstance();
this.directions = route.getDirections();
this.metersToDist = this.directions.routes[0].legs[0].distance.value;
this.timeToDist = this.directions.routes[0].legs[0].duration.value;
this.startAddress = this.directions.routes[0].legs[0].start_address;
this.startCord = this.directions.routes[0].legs[0].start_location;
this.endAddress = this.directions.routes[0].legs[0].end_address;
this.endCord = this.directions.routes[0].legs[0].end_location;
this.global.setMetersToDist(this.metersToDist);
this.global.setTimeToDist(this.timeToDist);
this.global.setStartAddress(this.startAddress);
this.global.setStartCord(this.startCord);
this.global.setEndAddress(this.endAddress);
this.global.setEndCord(this.endCord);
var options = {
types: ['geocode'],
componentRestrictions: { country: "dk" }
};
google.maps.places.Autocomplete(this.startAddress, options);
});
//The actual initialiser for the route
route.setDirections(response);
} else {
alert('Could not display route ' + status);
}
});
}
My problem is that the input is HTTPELEMENT, I get the input from an alert dialog
newRouteInput() {
let alert = this.alertCtrl.create({
title: 'New route',
inputs: [
{
name: 'routeStart',
placeholder: 'Start of route'
},
{
name: 'routeEnd',
placeholder: 'End of route'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'Debug start and end',
handler: data => {
if (data.username !== "undefined") {
console.log(data.routeStart + " " + data.routeEnd);
this.routeStart = "Brøndby Strand";
this.routeEnd = "Hvidovre";
this.newRoutePlaceMarks(this.map);
this.routeButton = false;
} else {
return false;
}
}
},
{
text: 'Place route markers',
handler: data => {
if (data.username !== "undefined") {
this.routeStart = data.routeStart;
this.routeEnd = data.routeEnd;
this.newRoutePlaceMarks(this.map);
this.routeButton = false;
} else {
console.log(data.routeStart + " " + data.routeEnd);
return false;
}
}
}
]
});
alert.present();
}
When I run this I get an error because of this.startAddress. It's not null, it contains the start address:
InvalidValueError: not an instance of HTMLInputElement

Kendo Upload in Kendo grid rows add row

I am using Kendo() grid in my application which has binding with an model.
I want to provide Upload control in Grid against each row. Please see razor view design as follows:
<div id="processDetailGrid"></div>
var processDetailGrid
, processDetailDataSource
, processDetailToolbar
, projectComboBox;
$(function () {
ProcessDetailToolbar = $("#processDetailToolbar").kendoToolBar({items: [{ id: "processDetailAdd", type: "button", spriteCssClass: "fa fa-plus-square", text: "Add", overflow: "never", click: processDetailAdd }]}).data("kendoToolBar");
function processDetailAdd() {
processDetailGrid.addRow();}
processDetailGrid = $("#processDetailGrid").kendoGrid({
dataSource: processDetailDataSource,
height: '98%',
selectable: "cell",
resizable: true,
reorderable: true,
columnMenu: true,
editable: false,
columns: [
{
field: "SoftwareUpLoad",
title: "#Resource.Field_SoftwareUpLoad",
template: kendo.template($("#template").html()),
// template: '#= SoftwareUpLoad==""?"<input type=\'file\' show=\'0\' name=\'files\' />":"<a class=\'k-button\' href=\'GetFiles?key=SoftwareUpLoad\'>Download</a>"#',
width: 300
},
{
field: "CutterCode",
title: "CutterCode",
width: 200
}
],
dataBound: function (e) {
var grid = this;
var firstItem = this.dataSource.view()[0];
this.tbody.find("input[name=files][show=0]").kendoUpload({
multiple: false,
async: {
saveUrl: 'save',
removeUrl: "remove",
autoUpload: true
},
validation: {
allowedExtensions: [".pdf"]
},
upload: function (e) {
var item = grid.dataItem(this.element.closest("tr"));
var id = BillId;
this.element.closest(".k-button").addClass("k-state-disabled");
this.element.closest(".k-button").find("input[name=files]").attr("show", "1");
e.data = { id: id, Operation: item.OperationNO };
},
remove: function (e) {
var item = grid.dataItem(this.element.closest("tr"));
var id = BillId;
this.element.closest(".k-button").removeClass("k-state-disabled");
e.data = { id: id, Operation: item.OperationNO };
},
success: function (e) {
var FileName = e.response.FileName;
var item = grid.dataItem(this.element.closest("tr"));
item.FileName = FileName;
item.dirty = false;
}
});
}
}).data("kendoGrid");
})
In the grid data line I upload data, click on the new line button, upload the data will be automatically emptied,but I want't that, I would like to ask how to do?

ReactJS props updating at different speeds in same component

I have a Google maps component in a React/Redux app. When you click an item from a list, it passes down an array of coordinates to render as directions from the user's current location. The props are being passed fine through react-redux mapStateToProps. I'm calling a function to generate the the polyline, this is where my problem is. The marker is generated fine inside of render, but the directions do not render until another entry is clicked. Basically it's always one step behind the current markers. So, for 2 stops, I'll have directions from current location to stop 1, but not stop 2. For 3 stops, current location to stop 1 to stop 2 will be generated, but not stop 3.
When I log out the length of the array of stops inside of render I get the expected amount, a length of 1 for 1 stop. I have tried putting the method inside of componentWillWillReceiveProps and componentWillUpdate, and both methods will log a 0 for 1 stop.
Here's the component, if relevant:
const GoogleMapComponent = React.createClass({
mixin: [PureRenderMixin],
getInitialState: function() {
return {
map: null,
maps: null,
color: 0
}
},
componentWillUpdate: function() {
console.log('LOGS ZERO HERE', this.props.tourList.length)
if (this.state.maps) {
this.calculateAndDisplayRoute(this.state.directionsService, this.state.directionsDisplay, this.props.tourList);
}
},
saveMapReferences: function(map, maps) {
let directionsDisplay = new maps.DirectionsRenderer({map, polylineOptions: {strokeColor: '#76FF03'}, suppressMarkers: true});
let directionsService = new maps.DirectionsService();
this.setState({ map, maps, directionsService, directionsDisplay });
},
generateWaypoints: function(coords) {
return coords.map((coord) => {
return { location: new this.state.maps.LatLng(coord.lat, coord.lng) };
});
},
calculateAndDisplayRoute: function(directionsService, directionsDisplay, tourStops) {
let origin = this.props.userLocation || { lat: 37.77, lng: -122.447 };
let destination = tourStops[tourStops.length - 1];
let directions = { origin, destination, travelMode: this.state.maps.TravelMode.DRIVING };
if (this.props.tourList.length > 1) {
directions.waypoints = this.generateWaypoints(tourStops);
}
if (tourStops.length > 0) {
directionsService.route(directions, (response, status) => {
if (status === this.state.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
} else {
console.log('Directions request failed due to ' + status);
}
});
} else {
directionsDisplay.set('directions', null);
}
},
render: function() {
console.log('LOGS 1 HERE', this.props.tourList.length)
let markers = this.props.tourList.map((marker, idx) => {
let loc = marker.prevLoc ? marker.prevLoc : 'your current location.';
return <Marker className='point' key={idx} image={marker.poster} lat={marker.lat} lng={marker.lng} location={marker.location} price={marker.price} loc={loc} />
});
let defaultCenter = {lat: 37.762, lng: -122.4394};
let defaultZoom = 12
if (this.props.userLocation !== null) {
return (
<div className='map'>
<GoogleMap defaultCenter={defaultCenter} defaultZoom={defaultZoom} yesIWantToUseGoogleMapApiInternals={true}
onGoogleApiLoaded={({map, maps}) => {
map.setOptions({styles: mapStyles});
this.saveMapReferences(map, maps);
}} >
{markers}
<UserMarker lat={this.props.userLocation.lat} lng= {this.props.userLocation.lng} />
</GoogleMap>
</div>
);
}
return (
<div className='map'>
<GoogleMap defaultCenter={defaultCenter} defaultZoom={defaultZoom} yesIWantToUseGoogleMapApiInternals={true}
onGoogleApiLoaded={({map, maps}) => {
map.setOptions({styles: mapStyles});
this.saveMapReferences(map, maps);
}} >
{markers}
</GoogleMap>
</div>
);
}
});
function mapStateToProps(state) {
return {
tourList: state.sidebar.tourList,
userLocation: state.home.userLocation
}
}
export default connect(mapStateToProps)(GoogleMapComponent);
Figured it out, I was not passing nextProps to componentWillUpdate, so the function was always being called with the old props.
componentWillUpdate is called prior to this.props being updated. Change componentWillUpdate as follows:
componentWillUpdate: function(nextProps) {
console.log('SHOULD LOG ONE HERE', nextProps.tourList.length)
if (this.state.maps) {
this.calculateAndDisplayRoute(this.state.directionsService, this.state.directionsDisplay, nextProps.tourList);
}
}