Select to view content in your preferred language

Using react, trying to make feature layer from array of graphics from clientside

649
0
06-05-2023 06:03 AM
Maher_Elgammal
New Contributor

I am using React, and I am trying to create feature layer from an array of objects from client side, when the user click on a place, a graphic appears, and a list opens, so he insert his data, and click ok to push to my array (array of suggestions and complains, like this), but some times It appears and be rendered and sometimes it don't and tell me some errors like 
Logger.js:5 [esri.layers.graphics.sources.MemorySource] Encountered 1 validation errors while loading features and gives me the object that didn't appear.

and another error like this: 

[esri.core.accessorSupport.write] web-document-write:property-required Missing value for required property 'x' on 'esri.geometry.Point' 

I will attach my code, thanks so much!

 

import React, { useEffect, useRef, useState } from 'react'
import Draw from "@arcgis/core/views/draw/Draw.js";
import Graphic from "@arcgis/core/Graphic.js";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";
import Field from "@arcgis/core/layers/support/Field.js";

export default function Form({ view }) {
    let pointRef = useRef(null)
    let xCor, yCor;
    const [hint, setHint] = useState({
        nameRef: "",
        phoneRef: "",
        emailRef: "",
        typeRef: "",
        messageRef: "",
    })
    const [clicked, setClicked] = useState(false)
    let graphs = []  //some global variables so I can deal with them in more than 1 function
    var layer;
    var hints = [];
    const draw = new Draw({
        view: view
    });

    //drawPoint is used to put a point on the map, It gives back some attributes like vertices which I can use to show a graph in this place 
    function drawPoint() {
        view.surface.style.cursor = "crosshair";
        let pointAction = draw.create("point");
        pointAction.on("draw-complete", (e) => {
            console.log(e);
            [xCor, yCor] = e.vertices[0];
            view.graphics.removeAll();
            let point = {
                type: "point",
                x: xCor,
                y: yCor,
                spatialReference: view.spatialReference,
            };

            //adding a graphic (Point), depending on the cordinates of drawn point.
            let graphic = new Graphic({
                geometry: point,
                symbol: {
                    type: "simple-marker",
                    color: [244, 67, 54],
                    path:
                        "M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z",
                    size: 32,
                    yoffset: 16,
                    outline: {
                        width: 0,
                    },
                },
            });

            //adding the created graphic to the map and Opening the form to start writing the hint.
            view.graphics.add(graphic);
            openForm();
        })
    }

    //open form function turns the d-none form to an appearing form and change mouse shape.
    function openForm() {
        if (pointRef.current) {
            pointRef.current.classList.remove('d-none');
            view.surface.style.cursor = "context-menu";
        }
    }

    function closeForm() {
        if (pointRef.current) {
            pointRef.current.classList.add('d-none');
        }
    }

    //this is the function that send the data from user to be saved in the local storage, and back a toasty message.
    function sendHint() {
        view.map.remove(layer);
        setClicked(!clicked)
        closeForm()
        view.graphics.removeAll();
        const date = new Date();
        let hintMessage = {
            name: hint.nameRef,
            phone: hint.phoneRef,
            email: hint.emailRef,
            type: hint.typeRef,
            message: hint.messageRef,
            x: xCor,
            y: yCor,
            date: date.toDateString(),
        }
        hints = JSON.parse(localStorage.getItem("messages"));

        localStorage.setItem("messages", JSON.stringify(hints ? [...hints, hintMessage] : [hintMessage]));
        toast("Your Hint was sent Successfully!", {
            position: "top-center",
            type: "success",
            style: { background: "black", color: "white" }
        });
    }

    //Now Local Storage has data saved in it, this function responsible to get this data and create graphic from each record in it, then create a feature layer based on graphic array.
    function GetAllMessage() {
        view.graphics.removeAll();
        graphs = [];
        const hints = JSON.parse(localStorage.getItem("messages"));
        if (!hints) return;
        const popupTemplate = {
            title: "{name} - {type}",
            content: [{
                type: "fields",
                fieldInfos: [
                    {
                        fieldName: "name",
                        label: "Name"
                    },
                    {
                        fieldName: "phone",
                        label: "Phone Number"
                    },
                    {
                        fieldName: "email",
                        label: "Email"
                    },
                    {
                        fieldName: "type",
                        label: "Type of Hint"
                    },
                    {
                        fieldName: "message",
                        label: "Message"
                    },
                    {
                        fieldName: "date",
                        label: "Sent at"
                    },
                ]
            }]
        }
        console.log(hints);
        hints.map((hint) => {
            const graph = new Graphic({
                geometry: {
                    type: "point",
                    x: hint.x,
                    y: hint.y,
                    spatialReference: view.spatialReference,
                },
                symbol: {
                    type: "simple-marker",
                    color: "red",
                },
                attributes: hint,
                popupTemplate: popupTemplate,
            })
            graphs.push(graph)
        });
        const fields = [
            new Field({
                name: "ObjectID",
                type: "oid",
            }),
            new Field({
                name: "name",
                type: "string",
            }),
            new Field({
                name: "phone",
                type: "string",
            }),

            new Field({
                name: "email",
                type: "string",
            }),
            new Field({
                name: "type",
                type: "string",
            }),
            new Field({
                name: "message",
                type: "string",
            }),
        ];

        var renderer = {
            type: "unique-value",
            legendOptions: {
                title: "Complains and Suggestions",
            },
            defaultSymbol: {
                type: "simple-marker",
                color: "gray",
                outline: null,
            },
            defaultLabel: "Feedback",
            field: "type",
            uniqueValueInfos: [
                {
                    value: "Complain",
                    symbol: {
                        type: "simple-marker",
                        color: "red",
                        outline: null,
                    },
                    label: "Complain",
                },
                {
                    value: "Request Information",
                    symbol: {
                        type: "simple-marker",
                        color: "blue",
                        outline: null,
                    },
                    label: "Request Information",
                },
                {
                    value: "Missed Services",
                    symbol: {
                        type: "simple-marker",
                        color: "gold",
                        outline: null,
                    },
                    label: "Missed Services",
                },
                {
                    value: "Add Information",
                    symbol: {
                        type: "simple-marker",
                        color: "green",
                        outline: null,
                    },
                    label: "Add Information",
                },
                {
                    value: "Other",
                    symbol: {
                        type: "simple-marker",
                        color: "dark",
                        outline: null,
                    },
                    label: "Other",
                },
            ],
        };

        let layer = new FeatureLayer({
            source: graphs,
            objectIdField: "ObjectID",
            fields:fields,
            renderer:renderer,
            popupTemplate:popupTemplate,
        });

        view.map.add(layer);
    }

    //after graphics are ready as a feature layer, Its time to display it to the user when he click on list-button 
    function displayMessages() {
        view.map.removeAll();
        GetAllMessage();
        console.log(graphs);
        if (graphs.length)
            view.popup.open({
                features: graphs,
                featureMenuOpen: true,
            });
        else
            toast("No Messages", {
                position: "top-center",
                type: "info",
                style: { background: "black", color: "white" },
            });
    }

    //more than a function to be excuted when the user try to send a hint, so a function contains all the desired actions and be fired when the user send a hint.
    function excute() {
        sendHint();
        view.map.removeAll();
        displayMessages();
    }

    //A button that helps the user to remove all the hints saved in local storage and display the map without these hints
    function removeAll() {
        localStorage.removeItem("messages");
        toast("All Your Hints were Removed!", {
            position: "top-center",
            type: "error",
            style: { background: "black", color: "white" }
        });
        displayMessages()
        view.popup.close();
    }



    return (
        <>
            <div id='hint-form' className="p-3 d-none bg-dark rounded-3 text-white esri-widget" ref={pointRef}>
                <div className="title d-flex justify-content-between align-items-center pt-3">
                    <i onClick={closeForm} className="fa-solid fa-xmark fa-2x"></i>
                    <h4>Give a hint!</h4>
                    <hr />
                </div>
                <div className="form-inputs">

                    <input value={hint.nameRef} onChange={(e) => setHint({ ...hint, nameRef: e.target.value })} type="text" placeholder='Your Name' className='my-3 form-control esri-input' />
                    <input value={hint.phoneRef} onChange={(e) => setHint({ ...hint, phoneRef: e.target.value })} type="text" placeholder='Your Phone' className='my-3 form-control esri-input' />
                    <input value={hint.emailRef} onChange={(e) => setHint({ ...hint, emailRef: e.target.value })} type="email" placeholder='Your Email' className='my-3 form-control esri-input' />
                    <select value={hint.typeRef} onChange={(e) => setHint({ ...hint, typeRef: e.target.value })} className="form-control esri-input">
                        <option value="Complain">Complain</option>
                        <option value="Request Information">Request Information</option>
                        <option value="Missed Services">Missed Services</option>
                        <option value="Add Information">Add Information</option>
                        <option value="Other">Other</option>
                    </select>
                    <textarea value={hint.messageRef} onChange={(e) => setHint({ ...hint, messageRef: e.target.value })} name="message" id="message" rows="5" placeholder='Enter Your Message Here Please...' className='form-control esri-input my-3'></textarea>
                    <button onClick={excute} className='btn btn-warning w-100'>Send Hint!</button>
                </div>
            </div>
            <div onClick={drawPoint} id="pin-button" className="esri-widget esri-widget--button esri-interactive" title="Add a Hint">
                <span className="esri-icon-plus-circled"></span>
            </div>
            <div onClick={displayMessages} id="list-button" className="esri-widget esri-widget--button esri-interactive" title="Hints List">
                <span className="esri-icon-comment"></span>
            </div>
            <div onClick={removeAll} id="remove-button" className="esri-widget esri-widget--button esri-interactive" title="Remove All Hints">
                <span className="esri-icon-erase"></span>
            </div>
            <ToastContainer />
        </>
    )
}

 

0 Kudos
0 Replies