Can someone guide me on how to release the onClick event? we have this setup in webapp builder but have not found the way to do it in Experience builder, see code
see snippet code web app builder
onClose: function(){
var mapFrame = this;
var map = this.map;
var my_content = document.getElementById("MyGoogleWidget");
var container = document.getElementById("btn_holder");
map.graphics.clear();
mapClick.remove();
mapFrame.LatTextBox.value = "";
mapFrame.LongTextBox.value = "";
container.innerHTML = "";
my_content.classList.add("hidden");
}
Experience Builder
The view's on method returns a handler that has a remove method. In this example, the click handler is removed after the fifth click.
let counter = 1;
const event = view.on("click", evt => {
console.log("click " + counter);
if (counter > 4) event.remove();
counter++;
});
Ken:
How do you reinitialize the event once its been removed without refreshing the map?
right now i have to refresh the map, I would want it reinitialized when the widget its open again.
Thanks in advance
Pedro
If I understand your question, you have a widget in a Widget Controller and you want to turn a click event on and off when the widget is activated. I have done this before in a class based component, but not a functional one, so my code may be slightly off, but I would handle this through a useEffect function triggered by the WidgetState. (I believe this can be found in props.state.)
const eventListener = useRef(null)
useEffect(()=> {
if (props.state === 'OPENED') {
eventListener.current = view.on('click', evt => {
yourFunction()
}
} else if (props.state === 'CLOSED') {
eventListener.current.remove()
}
},[props.state])
This is my base code for a widget that will need to interact with a map. It assumes that there is only one map in the Experience. It looks like you are missing a call to JimuMapViewComponent. I can also see some syntax problems in your return statement.
import { React } from 'jimu-core'
import { MapViewManager, JimuMapView, JimuMapViewComponent } from 'jimu-arcgis'
import reactiveUtils from 'esri/core/reactiveUtils'
const { useEffect, useState } = React
const Widget = (props) => {
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)
}
)
}
}, [jimuMapView])
const activeViewChangeHandler = (jmv: JimuMapView) => {
if (jmv) {
setJimuMapView(jmv)
}
}
return (
<div className='jimu-widget'
{
...
props.useMapWidgetIds &&
props.useMapWidgetIds.length === 1 && (
<JimuMapViewComponent
useMapWidgetId={props.useMapWidgetIds?.[0]}
onActiveViewChange={activeViewChangeHandler}
/>
)
}
>
{mapReady ? 'map ready' : 'map not ready'}
</div>
)
}
export default Widget
useEffect(() => {
if (jimuMapView) {
reactiveUtils
.whenOnce(() => jimuMapView.view.ready)
.then(() => {
setMapReady(true)
alert('map ready')
if (props.state === 'OPENED') {
if (!eventListener) {
alert('done')
eventListener = eventListener2.current
eventListener.current = jmv2.view.on('click', evt => {})
}
const test: string = eventListener.current.Status
alert(test)
alert('open')
} else if (props.state === 'CLOSED') {
alert('closed')
eventListener.current.remove()
alert(eventListener)
jmv2.view.graphics.removeAll()
}
}
)
}
}, [jimuMapView, props.state])
const activeViewChangeHandler = (jmv: JimuMapView) => {
jmv2 = jmv
if (jmv) {
// When the pointer moves, take the pointer location and create a Point
// Geometry out of it (`view.toMap(...)`), then update the state.
const simpleMarkerSymbol = {
type: 'simple-marker',
color: [226, 119, 40], // Orange
outline: {
color: [255, 255, 255], // White
width: 1
}
}
//jmv.view.on('pointer-move', evt => {
eventListener.current = jmv.view.on('click', evt => {
alert('Point')
eventListener2 = eventListener
const point: Point = jmv.view.toMap({
x: evt.x,
y: evt.y
})
setLatitude(point.latitude.toFixed(8))
setLongitude(point.longitude.toFixed(8))
setVisible(true)
const graphic = new Graphic({
geometry: point,
symbol: simpleMarkerSymbol
})
// setGraphic(graphic);
jmv.view.graphics.removeAll()
jmv.view.graphics.add(graphic)
//alert("Hello")
//jmv.view.add(graphic);
//const graphicsLayer = new GraphicsLayer();
// jmv.view.Graphics.add(graphicsLayer)
// graphicsLayer.add(graphic)
})
// Set up a click event handler and retrieve the screen point
}
jeffery:
Tried all kind of ways to re-add the listner
EvnetListner
But once i remove it when closing the widget
eventListener.current.remove()
i cannot re add it
any help will be greatly appreciated
Thanks
I suggest stepping back from Experience Builder and studying up on React before proceeding further. https://react.dev/learn React operates very differently from plain JavaScript and has a very steep learning curve. And Experience Builder adds another layer of complexity on top of that. I can tell you that there are issues with how you are using the useRef hook that are causing at least some of your problems. https://react.dev/reference/react/useRef Here is some pseudo-code for how to make this widget.
//import statements
//widget declaration
//useState declarations
//const eventListener = useRef(null)
//Declare a createEventListener function that returns the eventListener.
//useEffect function that has props.state in its depenency array.
//Inside useEffect, an if/else if statement based on props.state.
//If OPENED and if !eventListener.current, eventListener.current = createEventListener()
//Else if CLOSED, eventListener.current.remove() and eventListener.current = null
//return function
//export statement