issue with mapHandler within a function

675
7
09-21-2023 02:08 PM
PedroSalazar01
New Contributor II

Can some one see why I can not go past this line of code

  handler = (jmv: JimuMapView) => {
for some reason when running the program or debugging it does not go past there
please see whole program below
-----------------------------------------------------------------------------
import { React, type AllWidgetProps } from 'jimu-core'
import { MapViewManager, JimuMapViewComponent, type JimuMapView } from 'jimu-arcgis'
import reactiveUtils from 'esri/core/reactiveUtils'

const { useEffect, useState } = React

let handler

const Widget = (props: AllWidgetProps<any>) => {
  const viewManager = MapViewManager.getInstance()
  const mapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0])
  const [jimuMapView, setJimuMapView] = useState<JimuMapView>(mapView)
  const [mapReady, setMapReady] = useState(false)
  useEffect(() => {
    if (jimuMapView) {
      reactiveUtils
        .whenOnce(() => jimuMapView.view.ready)
        .then(() => {
          setMapReady(true)
          alert('map ready')
          if (props.state === 'OPENED') {
            alert('open')
            handler = (jmv: JimuMapView) => {
              alert('test')
              if (jmv) { alert('Event Handler ready') } else { alert('Not Ready') }
            }
          } else if (props.state === 'CLOSED') {
            alert('closed')
          }
        }
        )
    }
  }, [jimuMapView, props.state])

  return (

    <div className="widget-starter jimu-widget">
      {
        props.useMapWidgetIds &&
        props.useMapWidgetIds.length === 1 && (
          <JimuMapViewComponent
            useMapWidgetId={props.useMapWidgetIds?.[0]}
            onActiveViewChange={handler}

          />
        )
      }
      {/* <p>Lat/Lon: {latitude} {longitude} </p> */}
      <p><h9>Click on Map to get the coordinates </h9></p>

     </div>

  )
}

export default Widget
0 Kudos
7 Replies
KenBuja
MVP Esteemed Contributor

When posting code in your questions, please use the "Insert/edit code sample" button

https://community.esri.com/t5/python-blog/code-formatting-the-community-version/ba-p/1007633#U100763...

0 Kudos
PedroSalazar01
New Contributor II
import { React, type AllWidgetProps } from 'jimu-core'
import { MapViewManager, JimuMapViewComponent, type JimuMapView } from 'jimu-arcgis'
import reactiveUtils from 'esri/core/reactiveUtils'

const { useEffect, useState } = React

let handler

const Widget = (props: AllWidgetProps<any>) => {
  const viewManager = MapViewManager.getInstance()
  const mapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0])
  const [jimuMapView, setJimuMapView] = useState<JimuMapView>(mapView)
  const [mapReady, setMapReady] = useState(false)
  useEffect(() => {
    if (jimuMapView) {
      reactiveUtils
        .whenOnce(() => jimuMapView.view.ready)
        .then(() => {
          setMapReady(true)
          alert('map ready')
          if (props.state === 'OPENED') {
            alert('open')
            handler = (jmv: JimuMapView) => {
              alert('test')
              if (jmv) { alert('Event Handler ready') } else { alert('Not Ready') }
            }
          } else if (props.state === 'CLOSED') {
            alert('closed')
          }
        }
        )
    }
  }, [jimuMapView, props.state])

  return (

    <div className="widget-starter jimu-widget">
      {
        props.useMapWidgetIds &&
        props.useMapWidgetIds.length === 1 && (
          <JimuMapViewComponent
            useMapWidgetId={props.useMapWidgetIds?.[0]}
            onActiveViewChange={handler}

          />
        )
      }
      {/* <p>Lat/Lon: {latitude} {longitude} </p> */}
      <p><h9>Click on Map to get the coordinates </h9></p>

     </div>

  )
}

export default Widget
0 Kudos
PedroSalazar01
New Contributor II

Ken:

Thanks for the tip

what do you think the issue is with this code?

0 Kudos
JeffreyThompson2
MVP Regular Contributor

You have defined the handler function, but you never actually call handler(). So you will not see the alerts, within the function. onActiveViewChange is called automatically when the map is changed (Not elements within the map, the entire map object.). 

GIS Developer
City of Arlington, Texas
0 Kudos
PedroSalazar01
New Contributor II
/* eslint-disable no-prototype-builtins */
/** @jsx jsx */
import { type AllWidgetProps, jsx } from 'jimu-core'
import { useEffect, useState } from 'react'
import { type IMConfig } from '../config'
import { MapViewManager, type JimuMapView, JimuMapViewComponent } from 'jimu-arcgis'
import reactiveUtils from 'esri/core/reactiveUtils'

import type Point from 'esri/geometry/Point'

import defaultMessages from './translations/default'
//const { useEffect, useState } = React

let activeViewChangeHandler

export default function (props: AllWidgetProps<IMConfig>) {
  const [latitude, setLatitude] = useState<string>('')
  const [longitude, setLongitude] = useState<string>('')
  const [zoom, setZoom] = useState<number>(0)
  const [scale, setScale] = useState<number>(0)
  const [mapViewReady, setMapViewReady] = useState<boolean>(false)
  const viewManager = MapViewManager.getInstance()
  const mapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0])
  const [jimuMapView, setJimuMapView] = useState<JimuMapView>(mapView)
  const [mapReady, setMapReady] = useState(false)

  useEffect(() => {
    if (jimuMapView) {
      reactiveUtils
        .whenOnce(() => jimuMapView.view.ready)
        .then(() => {
          setMapReady(true)
          alert('map ready')
          if (props.state === 'OPENED') {
            alert('open')
            activeViewChangeHandler = (jmv: JimuMapView) => {
              alert('open2')
              if (jmv) {
                // When the extent moves, update the state with all the updated values.
                jmv.view.watch('extent', evt => {
                  setLatitude(jmv.view.center.latitude.toFixed(3))
                  setLongitude(jmv.view.center.longitude.toFixed(3))
                  setScale(Math.round(jmv.view.scale * 1) / 1)
                  setZoom(jmv.view.zoom)

                  // this is set to false initially, then once we have the first set of data (and all subsequent) it's set
                  // to true, so that we can hide the text until everything is ready:
                  setMapViewReady(true)
                })

                // When the pointer moves, take the pointer location and create a Point
                // Geometry out of it (`view.toMap(...)`), then update the state.
                jmv.view.on('pointer-move', evt => {
                  const point: Point = jmv.view.toMap({
                    x: evt.x,
                    y: evt.y
                  })
                  setLatitude(point.latitude.toFixed(3))
                  setLongitude(point.longitude.toFixed(3))
                  setScale(Math.round(jmv.view.scale * 1) / 1)
                  setZoom(jmv.view.zoom)
                  setMapViewReady(true)
                })
              }
            }
          } else if (props.state === 'CLOSED') {
            alert('closed')
          }
        }
        )
    }
  }, [jimuMapView, props.state])

  // activeViewChangeHandler = (jmv: JimuMapView) => {
  //   if (jmv) {
  //     // When the extent moves, update the state with all the updated values.
  //     jmv.view.watch('extent', evt => {
  //       setLatitude(jmv.view.center.latitude.toFixed(3))
  //       setLongitude(jmv.view.center.longitude.toFixed(3))
  //       setScale(Math.round(jmv.view.scale * 1) / 1)
  //       setZoom(jmv.view.zoom)

  //       // this is set to false initially, then once we have the first set of data (and all subsequent) it's set
  //       // to true, so that we can hide the text until everything is ready:
  //       setMapViewReady(true)
  //     })

  //     // When the pointer moves, take the pointer location and create a Point
  //     // Geometry out of it (`view.toMap(...)`), then update the state.
  //     jmv.view.on('pointer-move', evt => {
  //       const point: Point = jmv.view.toMap({
  //         x: evt.x,
  //         y: evt.y
  //       })
  //       setLatitude(point.latitude.toFixed(3))
  //       setLongitude(point.longitude.toFixed(3))
  //       setScale(Math.round(jmv.view.scale * 1) / 1)
  //       setZoom(jmv.view.zoom)
  //       setMapViewReady(true)
  //     })
  //   }
  // }

  const sections = []

  sections.push(
    <span>
      {defaultMessages.latLon} {latitude} {longitude}
    </span>
  )

  if (props.config.showZoom) {
    sections.push(<span>Zoom {zoom.toFixed(0)}</span>)
  }

  if (props.config.showScale) {
    sections.push(<span>Scale 1:{scale}</span>)
  }

  // We have 1, 2, or 3 JSX Elements in our array, we want to join them
  // with " | " between them. You cannot use `sections.join(" | ")`, sadly.
  // So we use array.reduce(...) to return an array of JSX elements.
  const allSections = sections.reduce((previousValue, currentValue) => {
    return previousValue === null
      ? [currentValue]
      : [...previousValue, ' | ', currentValue]
  }, null)

  return (
    <div className="widget-get-map-coordinates jimu-widget m-2">
      {props.hasOwnProperty('useMapWidgetIds') &&
        props.useMapWidgetIds &&
        props.useMapWidgetIds.length === 1 && (
          <JimuMapViewComponent
            useMapWidgetId={props.useMapWidgetIds?.[0]}
            onActiveViewChange={activeViewChangeHandler}
          />
      )}

      {/* Only show the data once the MapView is ready */}
      <p>{mapViewReady ? allSections : defaultMessages.latLonWillBeHere}</p>
    </div>
  )
}
0 Kudos
PedroSalazar01
New Contributor II

Jeffry:

modified the get-map-coordinates-function program, but still getting the same issue here

activeViewChangeHandler = (jmv: JimuMapView) => {

 

when uncomment the original code and debug, any time i hover over the map, it goes to this code, but not when i use the useEffect function, any help will be greatly appreciated

Pedro

0 Kudos
JeffreyThompson2
MVP Regular Contributor

activeViewChangeHandler should not be defined within the useEffect function and should only be used for necessary effects when the map changes, usually just redefining the mapView. If your widget does not work with multiple maps, activeViewChangeHandler will never be called. You should delete the definition of activeViewChangeHadler from within the useEffect function, but keep its contents to set up your eventListeners. As written, your widget operates something like this:

  1. Widget loads, useEffect fires, jimuMapView is probably undefined so useEffect and the widget does nothing. activeViewChangeHandler is undefined.
  2. jimuMapView becomes defined and useEffect fires again. Wait for jimuMapView.view to become ready.
  3. jimuMapView is now ready. If widget.state is OPENED,  activeViewChangeHandler now becomes defined. 
  4. Nothing else happens because all of your eventListeners are defined within activeViewChangeHandler and activeViewChangeHandler will only be called if the mapView changes.
GIS Developer
City of Arlington, Texas
0 Kudos