amCharts vs Chart.js vs anything else

I’m using amCharts for a few years now and I’m pretty satisfied.

I need to update my website and was thinking to try another “chart maker” (free if possible) which would have more options (even though this one is pretty complete), which would be more interactive…

For example, I have a bar graph that display one value per day. But I would like to be able to display an average between 2 dates (that I would select by clicking on the graph, or by another way…) rather than the daily values. The graph would be automatically updated in the window. I might be able to do something like this with amCharts but I wanted to try with another one.

This is an open question. I start reading about Chart.js. Seems good too. Which one would you recommend?

Thanks

Laurent

Why are a functional component’s child component’s props using outdated state?

I am actually using Next JS but its the same. i have simplified the code and removed the irrelevant part.

What i am building is a form where i can add new fields (child component) dynamically but the default will be 1 and there must always be minimum 1 field.

Parent.js

import {useState, useEffect} from 'react'
import Rooms from './Rooms'

export default function TourOverview(props) {
   const [roomList, setRoomList] = useState([])

   useEffect(()=>{  // add one room as default that cant be removed
        setRoomList([<Rooms addRoomCount={addRoomCount} id={1} key={1} />])
    }, [])

    const addRoomCount=()=> {
        let tempArr = roomList //shallow copy
        tempArr.push(<Rooms removeRoomCount={removeRoomCount} id={roomList.length+1} key={roomList.length+1} />)
        setRoomList([...tempArr])
    }

    const removeRoomCount=(id)=>{
       // will leave empty as not relevant
    }

    return (
        <>
          {roomList}
        </>
    )

Child.js

import {useState, useEffect} from 'react'
export default function Rooms(props, ref) {

   return (
         <>
           Room {props.id}
           {props.addRoomCount != undefined ? <button type="button" className="btn btn-link"  onClick={props.addRoomCount}>
                + Add Room
            </button> : 
                <button type="button" className="btn btn-link" onClick={()=>props.removeRoomCount(props.id)}>
                    - Remove
                </button>
            }
    </>
)

From the code you can see that as the parent component loads for the first time it will automatically add a child component that has the “add room” button, the others added later will have only “remove” button.

This doesnt work, it looks ok initially, but the moment you click on “add room” button, the roomList state gets reset to the state when the one time useEffect was initially loaded, which is…empty.

In another words, the addRoomCount() assigned as a prop to the first , is using the state roomList during the initial load when its still empty, its like a time machine.

I tried the class component version of this and it works. So its only functional component wont work.

Anyone can explain why?

Unable to run javascipt in android

I am attempting to pass a URL as input to a JavaScript script from an Android application and expect to receive a true or false value as a string in return from the script. The JavaScript code works fine when run independently, but when integrated with the Android app, I’m not receiving any data from the script. It’s uncertain whether the JavaScript code is even executing properly within the Android environment.

private void linkValidation(String url) {
        textStatus.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.white));
        textStatus.setText(getString(R.string.validating_link));
        Toast.makeText(MainActivity.this, url, Toast.LENGTH_SHORT).show();

        // Regex pattern for profile link
        // ... (your existing pattern and matcher code) ...

        if (url.startsWith("https://www.threads.net") || url.startsWith("https://threads.net")) {
            // ... (your existing code) ...
            if (url.contains("/post/") || url.contains("threads.net/t/")) {
                textStatus.setText(null);
                validatePostJS(url, new JavaScriptCallback() {
                    @Override
                    public void onResult(String result) {
                        // Here, 'result' will contain the value of 'foundNot' from JavaScript
                        textStatus.setText(result);
                Toast.makeText(getApplicationContext(),"Hello"+result,Toast.LENGTH_SHORT).show();
                    }
                });
            } else {
                // ... (your existing code) ...
            }
        } else if (((!url.startsWith("https://")) && (url.contains("www.threads.net"))) || ((!url.startsWith("https://") && (url.contains("https://threads.net"))))) {
            // ... (your existing code) ...
        } else {
            // ... (your existing code) ...
        }
    }
 private void validatePostJS(String url, final JavaScriptCallback callback) {
        // Initialize WebView (headless - not attached to the layout)
        WebView webView = new WebView(getApplicationContext());
        webView.getSettings().setJavaScriptEnabled(true);

        // WebView JavaScript interface to receive the result
        class JavaScriptInterface {
            @JavascriptInterface
            public void processResult(String result) {
                // Call the callback with the result
                callback.onResult(result);
            }
        }

        // Set the JavaScript interface
        webView.addJavascriptInterface(new JavaScriptInterface(), "androidJSInterface");

        // Load a blank HTML page with JavaScript code in the WebView
        String htmlContent = "<html><head><script>" +
                "function evaluatePuppeteer() {" +
                "   const url = '" + url + "';" +
                "   let foundNot = null;" +
                "   (async () => {" +
                "       try {" +
                "           const browser = await puppeteer.launch({ headless: 'new' });" +
                "           const page = await browser.newPage();" +
                "           await page.setDefaultNavigationTimeout(60000);" +
                "           await page.goto(url, { waitUntil: 'networkidle0' });" +
                "           const svgElements = await page.$('[aria-hidden="true"][fill="none"]');" +
                "           if (svgElements) {" +
                "               foundNot = 'true';" +
                "           } else {" +
                "               foundNot = 'false';" +
                "           }" +
                "           await browser.close();" +
                "           androidJSInterface.processResult(foundNot);" + // Pass the result to the JavaScript interface
                "       } catch (error) {" +
                "           console.error('Error:', error);" +
                "       }" +
                "   })();" +
                "}" +
                "evaluatePuppeteer();" + // Call the function immediately when the page loads
                "</script></head><body></body></html>"; // No need for onload

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                // The page is loaded, and evaluatePuppeteer() has been called
                // At this point, JavaScript execution is already done, and the result is available in CommentFound
                // You can handle the result here or in the JavaScriptInterface's processResult method
            }
        });

        // Load the HTML content (start JavaScript execution)
        webView.loadData(htmlContent, "text/html", "UTF-8");
    }


    private interface JavaScriptCallback {
        void onResult(String result);
    }

Add attachments to my azure dev-Ops work item using React.js

i made an application that allows me to create a work item , so by using my app , you can enter the title , the priority … , but i want to include a new fild where the users can enter their attachments ,for example screenshoots and then send all these inforamtiosn to azure dev-ops .( i did everything exept attachments).

here for examples some fields : const ticketData = [
{
op: ‘add’,
path: ‘/fields/Microsoft.VSTS.Build.IntegrationBuild’,
value: ”
},
{
op: ‘add’,
path: ‘/fields/System.Title’,
value: title
},
{
op: ‘add’,
path: ‘/fields/Custom.00a17f02-70c7-4683-a6d4-c607f4b0a243’,
value: priorite
},
{
op: ‘add’,
path: ‘/fields/Microsoft.VSTS.TCM.ReproSteps’,
value: reproSteps
}, {
op: ‘add’,
path: ‘/fields/Criticité’,
value: criticite
},
{
op: ‘add’,
path: ‘/fields/Custom.Etatattendu’,
value: etatAttendu
},
{
op: ‘add’,
path: ‘/fields/Custom.Etatobservable’,
value: etatObservable
},
{
op: ‘add’,
path: ‘/fields/Custom.Affectedversion’,
value: affectedVersion
},
{
op: ‘add’,
path: ‘/fields/Custom.Environnement’,
value: environnement
},
{
op: ‘add’,
path: ‘/fields/Custom.Titredulot’, //versionCible
value: titredulot
} ,
{
op: ‘add’,
path: ‘/fields/Custom.PutonCreation’,
value: {
displayName: accounts[0].name
}
}

i made an application that allows me to create a work item , so by using my app , you can enter the title , the priority … , but i want to include a new fild where the users can enter their attachments ,for example screenshoots and then send all these inforamtiosn to azure dev-ops .( i did everything exept attachments).

here for examples some fields : const ticketData = [
{
op: ‘add’,
path: ‘/fields/Microsoft.VSTS.Build.IntegrationBuild’,
value: ”
},
{
op: ‘add’,
path: ‘/fields/System.Title’,
value: title
},
{
op: ‘add’,
path: ‘/fields/Custom.00a17f02-70c7-4683-a6d4-c607f4b0a243’,
value: priorite
},
{
op: ‘add’,
path: ‘/fields/Microsoft.VSTS.TCM.ReproSteps’,
value: reproSteps
}, {
op: ‘add’,
path: ‘/fields/Criticité’,
value: criticite
},
{
op: ‘add’,
path: ‘/fields/Custom.Etatattendu’,
value: etatAttendu
},
{
op: ‘add’,
path: ‘/fields/Custom.Etatobservable’,
value: etatObservable
},
{
op: ‘add’,
path: ‘/fields/Custom.Affectedversion’,
value: affectedVersion
},
{
op: ‘add’,
path: ‘/fields/Custom.Environnement’,
value: environnement
},
{
op: ‘add’,
path: ‘/fields/Custom.Titredulot’, //versionCible
value: titredulot
} ,
{
op: ‘add’,
path: ‘/fields/Custom.PutonCreation’,
value: {
displayName: accounts[0].name
}
}

Combining multiple pipeable NgRx selectors

Is it possible to combine multiple pipeable selectors the same way we can combine multiple regular selectors?

Combining regular selectors:

export const selectActiveOrganization = createSelector(
    selectOrganizations,
    selectActiveOrganizationId,
    (organizations, activeOrgId) => organizations[activeOrgId],
);

Above there are two selectors selectOrganizations and selectActiveOrganizationId, which are passed into createSelector to create a selectActiveOrganization. Problem here is that selectActiveOrganization can also return undefined.


Now let’s rewrite this to pipeable selector:

const _selectActiveOrganization = createSelector(
    selectOrganizations,
    selectActiveOrganizationId,
    (organizations, activeOrgId) => organizations[activeOrgId],
);

export const selectActiveOrganizationPipeable = pipe(
    select(_selectActiveOrganization),
    filter(activeOrg => !!activeOrg),
);

In selectActiveOrganizationPipeable we improved the selectActiveOrganization selector to only emit value if there is any active organization.

So far so good. Now let’s say we want to build on to of our pipeable selector and create a new one which is returning only the organization name.

export const selectActiveOrganizationNamePipeable = pipe(
    select(selectActiveOrganizationPipeable),
    map(organization => organization.name), // --> TS ERROR: Property 'name' does not exist on type 'Observable<Organization>'.ts(2339)
);

Is there a way to reuse existing selectActiveOrganizationPipeable? (similarly as we reuse regular selectors)

How can I update the a list of items in React without refreshing

My code has a form that can be filled up and once the form is filled up, the credentials of that form is displayed on the employees’ portal. However, the website needs to be refreshed in order for the new entries to be displayed.

Here’s my useReducer.

import { createContext, useReducer } from "react";

export const FireInsuranceContext = createContext();

export const FireInsuranceReducer = (state, action) => {
  switch (action.type) {
    case "SET_FIREINSURANCES":
      return {
        fireInsurances: action.payload,
      };
    case "CREATE_FIREINSURANCE":
      return {
        fireInsurances: [action.payload, ...state.fireInsurances],
      };
    case "DELETE_FIREINSURANCE":
      return {
        fireInsurances: state.fireInsurances.filter(
          (f) => f._id !== action.payload._id
        ),
      };
    case "RESOLVE_FIREINSURANCE":
      return {
        fireInsurances: state.fireInsurances.map((fire) =>
          fire._id === action.payload._id 
            ? { ...fire, resolved: action.payload.resolved }
            : fire
        ),
      };

    default:
      return state;
  }
};

export const FireInsuranceContextProvider = ({ children }) => {
  const [state, dispatch] = useReducer(FireInsuranceReducer, {
    fireInsurances: [],
  });

  return (
    <FireInsuranceContext.Provider value={{ ...state, dispatch }}>
      {children}
    </FireInsuranceContext.Provider>
  );
};

Here is the formhandler function for the form

const formHandler = async (e) => {
//other stuff

try {
      const response = await fetch("http://localhost:2213/api/fire-emailer", {
        mode: "cors",
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(requestBody),
      });

      const json = await response.json();
      if (!response.ok) {
        setError(json.error);
        setLoading(false);
        console.log(json.error);
      }
      if(response.ok) {
        dispatch({ type: "CREATE_FIREINSURANCE", payload: json });
        console.log("workoutadded", json)
        setNotif(true);
        setLoading(false);
        setError("");
        setName("");
        setAddress("");
        setContact("");
        setEmail("");
        setCompany("");
        setInfrastructure("");
        setConstruction("");
      }

      console.log(json);
    } catch (error) {
      console.log(error);
      setError("An error occurred. Please try again later.");
      setLoading(false);
    }
}

and here is the code for the display of forms

const FireInsuranceList = () => {
  const { fireInsurances, dispatch } = useContext(FireInsuranceContext);

  useEffect(() => {
    const fetchFireInsurance = async () => {
      const response = await fetch(
        "http://localhost:2213/api/getInsurance/fire-insurance",
        {
          mode: "cors",
          headers: {
            "Content-Type": "application/json",
          },
        }
      );

      const json = await response.json();

      if (response.ok) {
        dispatch({ type: "SET_FIREINSURANCES", payload: json });
        console.log("useEffect ran")
      }
    };
    fetchFireInsurance();
  },[dispatch]);

  return (
    <div className="px-2 mt-3">
      <div className="flex justify-between flex-wrap">
        <div className="flex gap-x-2">
          <form className="relative">
            <input
              className="border border-gray-800 rounded-md text-sm p-1"
              placeholder="Search Name"
              type="search"
            />
            <button className="absolute top-1/2 -translate-y-1/2 right-1">
              <FontAwesomeIcon icon={faMagnifyingGlass} />
            </button>
          </form>
          <select className="text-sm p-1 rounded-md border-gray-800 border bg-white">
            <option value="all">All</option>
            <option value="solved">Solved</option>
            <option value="unresolved">Unresolved</option>
          </select>
        </div>

        <h3 className="font-bold">Fire Insurance Inquiries</h3>
      </div>
      <div>
        {fireInsurances.length !== 0 ? (
          <div className="flex flex-wrap justify-around gap-3 my-10">
            {fireInsurances.map((fireInsurance) => (
              <FireInsuranceDetails
                key={fireInsurance._id}
                fireInsurance={fireInsurance}
              />
            ))}
          </div>
        ) : (
          <div className="text-center text-xl font-bold mt-10 text-gray-700">
            No Fire Insurance Inquiries
          </div>
        )}
      </div>
    </div>
  );
};

export default FireInsuranceList;

removeEventListener doesn’t work inside useEffect logic

In ReactJS, if I have a useEffect checking for an observer like this:

// ...observer code here

useEffect(() => {

    function handleParallax() {
        let items = document.querySelectorAll('.item')
        items.forEach(item => {
            let distance = (window.scrollY || window.pageYOffset),
                distanceFinal = item.parentNode.offsetTop - distance,
                multi = 45;
            console.log((distanceFinal * multi)/500);
            let calc = `translate3d(0, calc(370px + ${((distanceFinal * multi)/500)}px), 0)`;
            item.setAttribute('style',
                `transform: ${calc};
                -ms-transform: ${calc};
                -webkit-transform: ${calc};`
            );
        });
    }

    if (isIntersecting) {
        console.log('enter')
        window.addEventListener('scroll', handleParallax, true)
    }else{
        console.log('exit')
        window.removeEventListener('scroll', handleParallax, true);
    }
}, [isIntersecting]);

the removeEventListener doesn’t work, in fact I receive a console log in browser of the enter/exit state of the observed area, but the console log inside the handleParallax function still logs as I scroll outside of the observer bounds, why is that?

How to set value when using an existing component with vuejs/storybook

I would like to map stories in Storybook using Quasar components. I would like to pass on their properties 1:1 so that they can be changed in Storybook. Unfortunately, I have not been able to set a value. In concrete terms, the code looks like this:

// preview.js

import Vue from 'vue';
import Quasar from 'quasar';
import VueI18n from "vue-i18n";
import messages from "../src/i18n";
import VueRouter from 'vue-router'

// Import quasar extras, required for fonts/icons
import 'quasar-extras/fontawesome'
import 'quasar-extras/material-icons'
import 'quasar-extras/roboto-font'
import 'quasar/dist/quasar.css'
import '../src/css/app.scss'
import storyRouterDecorator from "./storyRouterDecorator";

Vue.use(Quasar, { config: {}, directives: {} });
Vue.use(VueI18n);
Vue.use(VueRouter)

const i18n = new VueI18n({
  locale: "de-de",
  fallbackLocale: "en-us",
  messages
});

Vue.prototype.$t = function(...args){
  return i18n.t(...args);
}

Vue.prototype.$storybook = true;

const preview = {
  parameters: {
    actions: {argTypesRegex: "^on[A-Z].*"},
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/
      }
    }
  },
  decorators: [
    // This global decorator allows for the use of vue router components in stories.
    // It might be able to facilitate some routing as well, but that has not been tested yet
    storyRouterDecorator({},
      {
        routes: []
      })
  ],
};

export default preview;

// VTabs.vue

<script>
import { defineComponent } from 'vue'
import { QTab } from "quasar";
import { QRouteTab } from "quasar";

export default defineComponent({
  name: "VTabs",
  components: {
    QTab
  },
  props: QRouteTab.options.props
})
</script>

<template>
  <q-tabs
    no-caps
    class="col-auto text-subtitle2 text-left"
    :exact="false"
    active-class="text-primary"
  >
    <slot />
  </q-tabs>
</template>

<style scoped lang="scss">
</style>

// VTabs.stories.vue

import VTabs from './VTabs.vue';
import { transformVueComponentPropListToArgTypes } from "../../../../.storybook/storybookHelpers.js"
import { ref } from 'vue'

export default {
  component: VTabs,
  tags: ['autodocs'],
  argTypes: transformVueComponentPropListToArgTypes(VTabs.props),
  args: {
  }
};

const Template = (args, {argTypes}) => {
  return {
    props: Object.keys(argTypes),
    components: {
      VTab
    },
    directives: {},
    setup() {
      let model = ref('tab1')
      const updateModel = (event) => model.value = event
      return { args, model, updateModel }
    },
    template:
      `
        <q-tabs v-bind="$props" v-on="$listeners" @update:modelValue="updateModel" :modelValue="model">
          <template v-slot:default>
            <v-tab name="tab1" label="Tab 1" />
            <v-tab name="tab2" label="Tab 2" />
          </template>
        </q-tabs>
      `,
  }
}

export const standard = Template.bind({})

Now, I can change

        <q-tabs v-bind="$props" v-on="$listeners" @update:modelValue="updateModel" :modelValue="model">

to

        <q-tabs v-bind="args" v-on="$listeners" @update:modelValue="updateModel" :modelValue="model">

and here the property for the selected tab is applied, but nothing else. If i change back, I can apply everything except the property for the active tab.
I thing, i have to combine somehow both, but how?

How do I get the Windows 10 working directory in JavaScript? [duplicate]

I am writing a JavaScript code that runs in a Windows 10 application to scan a 3D surface for specific errors. To do so, this application generates multiple surfaces and saves them in different folders and run the JavaScript to each surface. The application uses the Windows command line to run the JavaScript and I want to get the working directory of the command line to search for the surface in question. Here is how I achieved this in python:

import os
orig_work_dir = os.getcwd()
surfaceDat = open(orig_work_dir + "\surface.3D")
problemFile = open(orig_work_dir + "\results.txt", 'w+')

And here is my current code in JavaScript:

var dir = path.dirname(__filename);
var input_surface_file = dir + "surface.3D"
var output_report_file = dir + "report.txt"

However, Windows cannot recognize path.

Next.js getServerSideProps returns empty query object when I pressed go back button

On the first page, I do router.replace() with new a query. so the URL becomes similar to someUrl?timestamp=1000.
After this I move to second page with router.push() and press back button on the browser, which takes me back to someUrl?timestamp=1000.

Now in getServerSideProps, I get empty query object. but if I refresh this page, I get the correct query object. My goal is to get query.timestamp (1000).

What’s wrong with going back feature? The result is same with router.back().

export const getServerSideProps: GetServerSideProps<PrimaryPageProps> = async (
  context: GetServerSidePropsContext,
) => {
  console.log(context.query); // it returns {}
  const { timestamp } = context.query;
  return {
    props: {
      timestamp: timestamp === undefined ? null : Number(timestamp),
    },
  };
};

This is how I updated the query on the first page.

        <Btn
          onClick={() =>
            router.replace(router.pathname, {
              query: { timestamp: Date.now() },
            })
          }
        >
          Update query
        </Btn>

Behaviour of event object when the onchange handler of a controlled react component is asynchronous

function Test(){
async function changer(ev:any){
let a=10;
console.log(ev.target.value) // reads correct updated state value
await chrome.storage.sync.get("sync") //---> fails to update the value if await is used 
// works correctly //chrome.storage.sync.get("sync").then((val)=>{
//  console.log(ev.target.value,a)
//})    
console.log(ev.target.value) // ev.target.value reads the older state value 
setVal(ev.target.value);
}
let [val,setVal]=useState("one");
return <>
<select value={val} onChange={changer}>
    <option value="one">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
</select>
</>
}

let root=createRoot(document.querySelector(“body”));
root.render(<></>)`

`
Questions:

  1. since react 17, the event object is not pooled. So, it must be the same even if the handler is asynchronous. But, statements after await read state value rather than the new click value fo the controlled select component. why is that ?

  2. since the value prop is assigned to the state, event.target.value should point to the state rather than the clicked value of the select element. How is that react able to distinguish the value even thought the component it points to has the value={state} prop? is the event.target not live ?

  3. will the event object be destroyed once the async handler returns an unfulfilled promise? what happens to the event object(which react claims to be synthetic) ?

I expected that the values between the console statements will point to the updated value but I get the state value rather than live clicked value in the second console statement.

output

Blank page after deploying a React Js app (create-react-app) on GitHub pages

`
I followed a tutorial and built a ReactJs app. I have this issue of the deployed app being blank when opened in a browser after the deployment of my ReactJS application in GitHub pages. It works well on my localhost but not when deployed in GitHub pages. Here is the deployed app url: https://sandeshshahapur.github.io/portfolio/

Here is the repository: https://github.com/sandeshShahapur/portfolio

In the console of the browser (firefox), when the deployed app is opened, this error appears: Loading failed for the <script> with source “https://sandeshshahapur.github.io/static/js/main.74cdc73a.js”.

App.js

import './App.scss'
import { Routes, Route } from 'react-router-dom'
import Layout from './components/Layout'
import Home from './components/Home'
import About from './components/About'
import Contact from './components/Contact'

function App() {
  return (
    <>
      <Routes>
        <Route path="/" exact element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="/About" element={<About />} />
          <Route path="/Contact" element={<Contact />} />
        </Route>
      </Routes>
    </>
  )
}

export default App

Index.js

import React from 'react'
import ReactDOM from 'react-dom'
import reportWebVitals from './reportWebVitals'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
import './index.css'

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter basename={process.env.PUBLIC_URL}>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
)

reportWebVitals()

I am a beginner, sorry if I missed providing any additional required information.

Few solutions on other forums mentioned having to have to include basename prop in <BrowserRouter and adding deploy to scripts in package.json but implementing them did not resolve the issue.`

Show/Hide Polylinedecorators dynamically (based on other variable) in React Leaflet (using a for loop)

I have succesfully implemented Polylinedecorators, but I am not able to easily hide them based on a boolean statement in React Leaflet. ‘Normal’ polylines are displayed/hided based on a certain variable (for example the boolean ‘certainBool’). I can not seem to find an easy way to easily add polyLineDecorators as a JSX component directly, without using the addToMap functionality. The problem with the addToMap functionality is that it is difficult to remove the elements added to the map in this way. Especially as my polylines (and polylinedecorators) are created in a (large) for loop. See the following code:

import React from 'react';
import { Polyline, useMap } from 'react-leaflet';
import 'leaflet-polylinedecorator';
import L from 'leaflet';

function showTrajectories() {
  const { trajectories, certainBool } = React.useContext(certainContext);

  const arrow = [
    {
      offset: '52%',
      endOffset: '52%',
      repeat: '100%',
      symbol: L.Symbol.arrowHead({
        pixelSize: 3,
        polygon: false,
        pathOptions: { stroke: true, opacity: 0.4 },
      }),
    },
  ];


  function PolylineDecorator({ patterns, polyline, id }) {
    const map = useMap();

    var decorator = L.polylineDecorator(polyline, {
      id: id,
      patterns,
    });
    decorator.addTo(map);
    return null;
  }

  if (trajectories.length > 0) {
    return trajectories.map((trajectory, i) => {
      if (certainBool) {
        return (
          <>
            <PolylineDecorator polyline={trajectory.coordinates} patterns={arrow} id={i} />
            <Polyline
              positions={trajectory.coordinates}
              className='line'
              key={i}
              noClip={true}
            ></Polyline>
          </>
        );
      }
    });
  }
}

export default showTrajectories;

Access child element of a component from a parent component

I have a Form component which renders 3 InputContainer components. I want to access the value of the input element on the submit event of the form. Right now, my submitResource function logs the div which contains both label and input element.

If not necessary, I don’t want to emit any events with @change handler. The only way I’ve managed to access the input element is by console.log(titleRef.value.$el.querySelector('input')); but I think its not the right way to do it.

Thank you!

Form.vue

<template>
  <form @submit.prevent="submitResource">
    <InputContainer ref="titleRef" />
    <InputContainer ref="descriptionRef"/>
    <InputContainer ref="linkRef" />
    <BaseButton type="submit" class="submit">Add Resource</BaseButton>
  </form>
</template>

<script setup>
import BaseButton from './BaseButton.vue';
import InputContainer from './InputContainer.vue';
import { ref } from 'vue';

const titleRef = ref(null);
const descriptionRef = ref(null);
const linkRef = ref(null);

const submitResource = () => {
  console.log(titleRef.value.$el);
};
</script>

InputContainer.vue

<template>
  <div class="input-container">
    <label for="example">Example</label>
    <input
      type="text"
      id="example"
      name="example"
    />
  </div>
</template>