Convert drawing math function from ChartJs 2 to 3

I have following JSON chart configuration which is working fine on chartjs2:

{
    "type": "line",
    "data": {
        "labels": [0, 100],
        "datasets": [{
            "label": "T = const",
            "function": "function(x) { return 2; }",
            "data": [],
            "fill": false,
            "borderColor": "rgb(75, 192, 192)",
            "tension": 0.1
        }]
    },
    "options": {
        "scales": 
        {
            "x": { "title": { "display": true, "text": "[n]" }},
            "y": { "title": { "display": true, "text": "[u]" }}
        }
    },
    "plugins": [{
        "beforeInit": function(chart) {
          // We get the chart data
          var data = chart.config.data;
  
          // For every dataset ...
          for (var i = 0; i < data.datasets.length; i++) {
  
              // For every label ...
              for (var j = 0; j < data.labels.length; j++) {
  
                  // We get the dataset's function and calculate the value
                  var fct = data.datasets[i].function,
                      x = data.labels[j],
                      y = fct(x);
                  // Then we add the value to the dataset data
                  data.datasets[i].data.push(y);
              }
          }
        }
    }]
}

I’m getting following error:

Error: fct is not a function

How convert this example to make it working with ChartJs 3? I guess something has changed in chart API, but I cannot figure out what exactly and how to apply it to my datasets example.

Nuxt build with different .env files

I’m using Nuxt v2.15.8.
I have some problem using dotenv in my app.

I followed this approach in order to build different nuxt apps with specific environment variables.
https://stackoverflow.com/a/71346673/20707467

Using “–dotenv” option works fine when used for running locally (ex: “dev”: “nuxt –dotenv .env.development”). I can run different version with env values specified in each file.

But when I use it in build command (ex: “build:staging”: “nuxt build –dotenv .env.staging”), it seems that nothing happens. It reads env values only if a standard “.env” file is presente, ignoring what is specified in -dotenv option.

Any suggestion?

Thanks in advance

What way of using $model in Vuelidate is more performant and stable?

I’m refactoring a validation for a complex object and I see that some of the code is written like that:
this.v$.object.$model.param.setting.value = someValue

And the rest is
this.v$.object.param.setting.value.$model = someValue

According to the docs $model is the reference to the exact value, which means for me that if I want to refer to a value I should use ...value.$model. But both ways work correctly. So I’m wondering is it a matter of code style or there could be performance issue when instead of referring to object.param.setting.value you changing whole object object.param.setting.value?

Execute after setTimeout function finished

i want to use a different function after settimeout delivery, but i couldn’t.

  setTimeout(() => {
    wheelEl.style.transition = "all ease-out 5s";
    // Target rotation margin
    const rotMin = (sliceSize * (index)) + (sliceSize / 20);
    const rotMax = (sliceSize * (index)) - (sliceSize / 20);
    // Target rotation
    const fullRots = Math.floor(Math.random() * 5) + 5; // minimum 5 rotations max 9
    const rot = (fullRots * 360) + Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);
    wheelEl.style.transform = `rotate(-${rot}deg)`;
    
  }, 0);
  }

function start() {
    setTimeout((function () {
        alert('hey!');
    }), 4000);
}

hi, i want to use a different function after settimeout delivery, but i couldn’t.

Using EventSource with Ajax

I am trying to work out how EventSource might help solve an update problem with a web applications.

I would like to be able to notify visitors to a web page when one or another visitor has performed an update. The idea is:

  • One visitor makes some changes to a text area and submits.
  • The data is submitted using Ajax.
  • At the server, the changes are saved.
  • I would like the server to send a notification that changes have been made
  • I would like all other visitors to get this notification.

On the server in PHP, I have something like this:

if(isset($_POST['save'])) {
    //  process changes

    $data = sprintf('data: {"time": "%s","type": "save"}',$date);

    header("Cache-Control: no-store");
    header("Content-Type: text/event-stream");
    print "event: pingn$datann";
    ob_flush();
    flush();

    exit;
}

In JavaScript I have something like this:

var eventSource = new EventSource("https://example.net/ajax.php", { withCredentials: true } );
eventSource.addEventListener("ping", (event) => {
    const time = JSON.parse(event.data).time;
    const type = JSON.parse(event.data).type;
    console.log(`Ping at ${time} for ${type}`);
});

That doesn’t do the job at all. At the client end I get get an error message about the wrong headers (I think that it’s because there’s no save yet, so the PHP falls through to an empty string).

All the samples I have seen include a while(true) loop in the PHP, but non have a one-off event.

Is this possible to implement, and, if so, how?

I’m using Async/Await but it still logs after another piece of code

I want to use the Fetch API syncronously, so I wrap it in async/await, and for the testing I console.log some text after, and still this log comes before the log of the fetch call:

async function fetchData() {
    const response = await fetch(
        'fetch_url', {
            method: 'GET'
        }
    );
    return response.text();        
}

fetchData().then(response => console.log(response));

console.log("Second Log");

But the output is:

> Second Log
> Some Response From The Server

React route direct access not working, but working with navlink

the contents of app.js

function App() {
  return (
    <div className='App'>
      <BrowserRouter>
        <Routes>
          <Route path='/*' element={<CustomerLayout />} />
          <Route path='/admin/*' element={<AdminLayout />} />          
        </Routes>
      </BrowserRouter>
    </div>
  );
}

and contents of CustomerLayout.js

const CustomerLayout = () => {
  return (
    <div>
    <MainHeader />
    <Routes>
        <Route path="/" element={<Home />}></Route>
        <Route path="/shop" element={<Shop />}></Route>
        <Route path="/product-detail/:slug" element={<ProductDetail />}></Route>
        <Route path="/cart" element={<Cart />}></Route> 
        <Route path="/login" element={<Login />}></Route>       
    </Routes>
    <MainFooter />
    </div>
  )
}

now when I try to access mydomain/shop from the menu, it is working fine.
code for menu is like this
<NavLink to='/shop'>Shop</NavLink>
but if try to access the page directly mydomain/shop
I get 404 not found error.
what I am missing here.

Using Google Maps API and geocoder, how do you reverse geocode a list of coordinates to give you the country they’re located in?

I’m currently working on a project that takes a list of coordinates and plots them on a map using google maps api. I am adding a feature where you can filter the markers based off their location. So, the thought process is to loop through each coordinate and have geocode determine the location.

So far I have this function to find the location of the coordinates:

function geocodeLatLng() {
                const latlng = { lat: parseFloat(data[0][1]), lng: parseFloat(data[0][2])}; //this is the first entry of the coordinate array, coordinates are stored as string so they need to parsed
                let country = ""; //store the name of the country

                //i made a geocoders array to have a geocode opject for each coordinate pair
                geocoders[0].geocode({ location: latlng }).then((response) => {
                    if (response.results[0]) {
                        for (let i = 0; i < response.results[0].address_components.length; i++) {//loops through each address component
                            if (response.results[0].address_components[i].types.includes('country')) {//looking for the address component that stores the country field
                                country = response.results[0].address_components[i].short_name;//just need the abbreviation
                                console.log(country);
                            }
                        }
                        if (country == "") {//some coordinates are in the ocean, so if country couldn't be found, assign it ocean
                            country = "OCEAN";
                            console.log(country);
                        }
                    }
                }).catch((e) => {
                    window.alert("Geocoder failed due to: " + e);
                });
            //}
        }

This code works fine for finding a single instance of an coordinate location. However, when I try to use this code inside a for loop to find all the coordinates instead of just one, I get this error: MapsRequestError: GEOCODER_GEOCODE: OVER_QUERY_LIMIT: The webpage has gone over the requests limit in too short a period of time.

function geocodeLatLng() {
            let countries = [];//used for keeping track of all the countries
            for (let i = 0; i < data.length; i++) {
                const latlng = { lat: parseFloat(data[i][1]), lng: parseFloat(data[i][2])};
                let country = "";

                geocoders[i].geocode({ location: latlng }).then((response) => {
                    if (response.results[0]) {
                        //console.log("inside if");

                        //console.log(response.results[0].address_components);
                        for (let i = 0; i < response.results[0].address_components.length; i++) {
                            if (response.results[0].address_components[i].types.includes('country')) {
                                country = response.results[0].address_components[i].short_name;
                                countries.push(country);
                            }
                        }
                        if (country == "") {
                            country = "OCEAN";
                            countries.push(country);
                        }
                    }
                }).catch((e) => {
                    window.alert("Geocoder failed due to: " + e);
                    //country = "Ocean";
                });

            }
        }

I think the async function call is causing the loop to continue without finishing first. Is there a way to get the geocode function to wait and complete before moving on to the next loop iteration? Is there a better alternative to what I’m doing currently? Thanks for the help!

Node JS Connection Pooling for large apps with MSSQL

I’m trying to implement a connection pool for a relatively large application on Node, but I can’t seem to get it to work with the structure I have implemented. Basically, the app has routes, controllers, and the model all in separate files to help break things up. But, when I try to use the mssql connection pool discussed here and shown here, it doesn’t fit this format. It looks like this solution has each route in a separate file, which I don’t really want.

This is what I currently have:

routes.js

const express = require('express');
const router = express.Router();

const testController = require('../controllers/test.controller');

// http://localhost:5001/api/v2/competitor/queuedatamapcompetitors
router.get('/test', testController.test);


module.exports = router;

controller.js

const test = require('../models/test.model');
const db = require('../config/db.config');

exports.test = (params, res) => {
    test.test(params, function (err, result) {
        if (err) {
            res.send(err);
        }
        else {
            res.send(result);
        }
    });
};
const express = require('express')
const router = express.Router()
const { poolPromise } = require('../config/db.config');

// constructor
class testModel {
    constructor() {
    }
}

testModel.test = (params, result) => {
    var query = 'SELECT * FROM db.dbo.table'
        try {
          const pool = await poolPromise
          const result = await pool.request()
            //   .input('input_parameter', sql.Int, req.query.input_parameter)
              .query(query)      
      
          res.json(result.recordset)
        } catch (err) {
          res.status(500)
          res.send(err.message)
        }
  )
}



module.exports = testModel;

and db.js

const sql = require('mssql')

const config = {
  server: 
  authentication: {
    type: 'default',
    options: {
      userName: 
      password: 
    }
  },
  options: {
    encrypt: true,
    trustServerCertificate: true,
    rowCollectionOnRequestCompletion: true
  }
};

const pool = new sql.ConnectionPool(config)
  .connect()
  .then(pool => {
    console.log('Connected to MSSQL')
    return pool
  })
  .catch(err => console.log('Database Connection Failed! Bad Config: ', err))

module.exports = {
  sql, pool
}

Do I need to overhaul the structure of the backend? Should each route have a separate file? Or is there something I’m missing with the structure I’m already using?

Display hamburger menu only on breakpoint

I have created a hamburger menu in react it displays content on breakpoint as expected. But can any body help me to display the hamburger menu icon only on breakpoint otherwise it should display the Navigation menu?

    const [showMenu, setShowMenu] = useState(false);
        return (
        <nav className={`nav ${className}`}>
        <button  
        className = "button" 
        onClick={ () => setShowMenu(!showMenu) }
        aria-label={showMenu ? "Close Menu" : "Open Menu"}>
            <i className="gg-menu"/> 
        </button>
); 

Plotting a bubble chart (circle packing) with d3.js using a .csv file updated every n-seconds

I am trying to plot a bubble chart in d3.js using a file that is updated every few seconds and I’m having trouble with a few parts of the code.

The whole data-to-visualization pipeline is described below:

  1. Data is gathered, processed and saved using a dataproc cluster on GCP
  2. Data is retrieved from GCP and saved to a local machine as a .csv file every 10 seconds
  3. The .csv file is used to create a d3.js visualization – the visualization is updated using d3’s setInterval().

A sample of the data is shown below:

Tag Count Date
0 python 1 12/06 18:15:40
1 pandas 1 12/06 18:15:40
2 java 1 12/06 18:15:40
3 html 1 12/06 18:15:40
4 c++ 1 12/06 18:15:40

The issues I’m facing are numbered below:

  1. Ideally, I would like to be able to get the data and store just that new data (i.e. overwrite the old file) when saving it on the GCP end. I’m not able to do that because for some reason it seems that something is causing the script to clear out variables in memory (potentially?). I say this because when I run the code below, the csv variable is reset each time. To remedy this, I’m appending all data gathered so that I have all the data.

  2. Currently, it seems that every time that I run the update function, the circles are replotted (which is what is happening – I understand) but I would like to figure out how to get the circles that I already have and transition them so that they show their new values and only draw new circles for the new data. I’m unable to achieve that with my current code even though I’ve tried many different ways to transition the data.

I was expecting to be able to update the csv variable in memory so that I would not have to reprocess the data every time. I would also prefer not to append the file and pull the complete file each iteration. Furthermore, the every iteration the visuals are a complete wipe of the canvas and replotting rather than a smooth transition.

Here is my code and a couple of pictures of the visualization at different times. Any suggestion would be extremely helpful.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Real-Time Tags Analysis</title>
    <script src="https://d3js.org/d3.v4.js"></script>
    <script src="//d3js.org/d3-scale-chromatic.v0.3.min.js"></script>
</head>
<body>
    <h1>Real-Time Tags Analysis</h1>
    <div id="dataviz"></div>
    <script>
        
        //defining constant for the visualization
        const width = window.innerWidth, height = window.innerHeight, sizeDivisor = 0.1, nodePadding = 2.75, topTags = 12;

        //defining svg canvas
        let svg = d3.select("body")
            .append("svg")
            .attr("width", width)
            .attr("height", height);

        //color palette
        let color = d3.scaleSequential().domain([1,200]).interpolator(d3.interpolateViridis);

        //simulation instantiation
        let simulation = d3.forceSimulation()
            .force("forceX", d3.forceX().strength(.1).x(width * .5))
            .force("forceY", d3.forceY().strength(.1).y(height * .5))
            .force("center", d3.forceCenter().x(width * .5).y(height * .5))
            .force("charge", d3.forceManyBody().strength(-15));

        //global variables
        let csv = {}, tag, temp = {}, oldData;


        //initial bubble chart plotting
        d3.csv("bigquery_data.csv", function(error, data) {
        if (error) throw error;
        
        oldData = data;
        
        //adding new data from file to the csv variable
        data.forEach(function(d) {

            tag = d['tag'];

            if(csv[tag] == undefined) {
                    csv[tag] = +d['count']
                } else {
                    csv[tag]+= +d['count'];
            }
        });

        //converting the csv variable to d3 entries list for visualization and defining more values
        let csvlist = d3.entries(csv);

        csvlist.forEach(function(d) {
            d.value = +d.value;
            d.size = +d.value / sizeDivisor;
            d.size < 3 ? d.radius = 3 : d.radius = d.size;
            return d;
        });
        
        // sort the nodes so that the bigger ones are at the back
        csvlist = csvlist.sort(function(a,b) { return b.size - a.size; });

        //update the simulation based on the data
        simulation
            .nodes(csvlist)
            .force("collide", d3.forceCollide().strength(0.5).radius(function(d) { return d.radius + nodePadding; }).iterations(5))
            .on("tick", function(d){
                
                circle.attr("cx", function(d){ return d.x; })
                    .attr("cy", function(d){ return d.y; })
                
                text.attr("dx", function(d) { return d.x; })
                    .attr("dy", function(d) { return d.y; })

            });
        
        //setting up nodes
        let node = svg.selectAll("circle")
                    .data(csvlist)
                    .attr("class", "node")
                    .enter().append("g")
                    .call(d3.drag()
                            .on("start", dragstarted)
                            .on("drag", dragged)
                            .on("end", dragended));
                        
        //appending circles to nodes
        let circle = node.append("circle")
                        .data(csvlist)
                        .attr("r", function(d) { return d.radius; })
                        .attr("fill", function(d) { return color(d.index); })
                        .attr("cx", function(d){ return d.x; })
                        .attr("cy", function(d){ return d.y; });
        
        //appending text to nodes
        let text = node.append("text")
                    .attr("class", "text")
                    .data(csvlist)
                    .attr("dx", function(d) { return d.x; })
                    .attr("dy", function(d) { return d.y + d.size/5; })
                    .text(function(d) { return d.key; })
                    .style("font-size", function(d) {return d.size/2 > 8 ? d.size/2 : 8; })
                    .style("font-family", "Helvetica")
                    .style("text-anchor", "middle");

        });

        //helper functions for simulation
        function dragstarted(d) {
            if (!d3.event.active) simulation.alphaTarget(.03).restart();
            d.fx = d.x;
            d.fy = d.y;
        }

        function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }

        function dragended(d) {
            if (!d3.event.active) simulation.alphaTarget(.03);
            d.fx = null;
            d.fy = null;
        }

        // update function which is similar to the original plot with conditional exit
        function update() {

            d3.csv("bigquery_data.csv", function(error, data) {
            if (error) throw error;

            // exit if no new data
            if (data[data.length - 1].date  == oldData[oldData.length - 1].date ) {
                return;
            }
            
            // update for next conditional exit
            oldData = data;

            // updating the csv variable
            data.forEach(function(d) {

                tag = d['tag'];

                if(csv[tag] == undefined) {
                        csv[tag] = +d['count'];
                    } else {
                        csv[tag] += +d['count'];
                }
            });

            // converting to d3 entries list and adding other required data for visualization
            let csvlist = d3.entries(csv);

            csvlist.forEach(function(d) {
                d.value = +d.value;
                d.size = +d.value / sizeDivisor;
                d.size < 3 ? d.radius = 3 : d.radius = d.size;
                return d;
            });

            // sort the nodes so that the bigger ones are at the back
            csvlist = csvlist.sort(function(a,b) { return b.size - a.size; });

            //update the simulation based on the data
            simulation
                .nodes(csvlist)
                .force("collide", d3.forceCollide().strength(0.5).radius(function(d) { return d.radius + nodePadding; }).iterations(1))
                .on("tick", function(d) {
                    
                    circle.attr("cx", function(d){ return d.x; })
                          .attr("cy", function(d){ return d.y; })
                    
                    text.attr("dx", function(d) { return d.x; })
                        .attr("dy", function(d) { return d.y; })

                });
            
            let node = svg.selectAll(".node")
                      .data(csvlist)
                      .transition()
                      .duration(100)
                      .ease(d3.easeLinear);

            node.enter().append("g")
                .attr("class", "node")
                .call(d3.drag()
                            .on("start", dragstarted)
                            .on("drag", dragged)
                            .on("end", dragended));
                            
            let circle = node.append("circle")
                .data(csvlist)
                .attr("r", function(d) { return d.radius; })
                .attr("fill", function(d) { return color(d.index); })
                .attr("cx", function(d){ return d.x; })
                .attr("cy", function(d){ return d.y; });
            
            let text = node.append("text")
                .attr("class", "text")
                .data(csvlist)
                .attr("dx", function(d) { return d.x; })
                .attr("dy", function(d) { return d.y + d.size/5; })
                .text(function(d) { return d.key; })
                .style("font-size", function(d) {return d.size/2 > 8 ? d.size/2 : 8; })
                .style("font-family", "Helvetica")
                .style("text-anchor", "middle");

            });

            function dragstarted(d) {
            if (!d3.event.active) simulation.alphaTarget(.03).restart();
            d.fx = d.x;
            d.fy = d.y;
            }

            function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
            }

            function dragended(d) {
            if (!d3.event.active) simulation.alphaTarget(.03);
            d.fx = null;
            d.fy = null;
            }

            }
        
        // code to update the visualization every 10seconds 
        let inter = setInterval(function() {update()}, 10000);

    </script>
</body>
</html>

Bubble Chart at inception

Bubble Chart after ~10mins

Problems after upgrading webpack

Not sure what’s going on here.

I have upgraded webpack as I’ve updated Node etc to the latest, but in doing so I’ve messed up my webpack config – or perhaps more likely need to change it due to the upgrade.

Can anyone shed any light on what I need to do here?

I’m having to write some more stuff here because it’s rejecting my question as it’s mostly code. I don’t know what else to tell you. Ummm…

The project is mainly in vanilla js, it uses jquery on the front end.

ERROR in data:application/x-font-ttf;charset=utf-8;;base64,AAEAAAAOAIAAAwBgT1MvMj3hSQEAAADs
...
Module build failed: UnhandledSchemeError: Reading from "data:application/x-font-ttf;charset=utf-8;;base64,AAEAAAAOAIAAA
...QBEAAA=" is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "data:" URIs.

This is my webpack.config.js:

const path = require('path');

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';

const webpack = require('webpack');

module.exports = {
    context: __dirname,
    entry: ['./src/client/index.js'],
    output: {
        path: __dirname + '/public/assets/js/',
        publicPath: '/assets/js/',
        filename: 'bundle.js',
    },
    watch: true,

    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
        }),

        new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: devMode ? '[name].css' : '[name].[hash].css',
            chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
        }),
    ],

    module: {
        rules: [
            {
                test: require.resolve('jquery'),
                loader: 'expose-loader',
                options: {
                    exposes: ['$', 'jQuery'],
                },
            },
            {
                test: require.resolve('moment'),
                loader: 'expose-loader',
                options: {
                    exposes: ['moment'],
                },
            },
            {
                test: /.s?[ac]ss$/,
                use: [
                    devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
                    { loader: 'css-loader' }, // translates CSS into CommonJS
                    { loader: 'postcss-loader' },
                    { loader: 'sass-loader' }, // compiles Sass to CSS
                ],
            },
            {
                test: /.(jpg|jpeg|gif|png)$/,
                exclude: /node_modules/,
                use: 'url-loader?limit=1024&name=images/[name].[ext]',
            },
            {
                test: /.(woff|woff2|eot|ttf|svg)$/,
                use: 'url-loader?limit=1024&mimetype=application/octet-stream&name=fonts/[name].[ext]',
            },
        ],
    },
};

How does an auto refresh page extension works and how to recreate one with code?

I’m looking for a way to recreate the functionality of a refreshing page extension on a browser (e.g. Auto refresh plus in Chrome) by using javascript. The problem is that I have no ideia how to achieve that.
I must find a way to refresh the page every second or so, click on a link that appears on the page from time to time, add a sound effect for when it appears and send an e-mail notification every time it appears.

I’m trying to use a simple javascript snippet to run in the console in order to refresh the page:

win1 = window.open("https://www.myUrl.com/");
timer1 = setInterval(function(){win1.location.href="https://www.myUrl.com/"}, 1500);

However, this implies running code from tab A on tab B which I found very challenging.
The code can’t run on tab A alone because at the time it refreshes the page, it gets erased from the console.
I know it would have been so much easier to use an extension, but the platform I work for does not allowed any extensions.
I have basic HTML and javascript knowledge, but I find this would be a good project to learn more.
Also, if the solution involves other languages, I just need a direction to know where to look for and start this project.

whatsapp-web.js show qr code on server with node js

I’m trying to configure whatsapp-web.js on my server, and I need it to show me the qr to link it with my phone.

I can link to it locally in a terminal, but I can’t on my server, here’s what I’ve tried:

I’ve tried this, but it’s not working


//const qrcode = require('qrcode-terminal');
const {Client} = require('whatsapp-web.js');
var QRCode = require('qrcode');

const client = new Client();

var http = require('http');
var server = http.createServer(async function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    var message = 'It works!n';
    //client.initialize();
    try {
        let qr = await new Promise((resolve, reject) => {
            client.once('qr', (qr) => resolve(qr));
            client.initialize();
            setTimeout(() => {
                reject(new Error("QR event wasn't emitted in 15 seconds.")); // It's Throwing this
            }, 15000);
        })
        res.end(qr);
    } catch (err) {
        res.end(err.message);
    }
});
server.listen();

Javascript Redirect Based on a Form Selection (Before Submitting)

I am looking to redirect users to a different page (for an academic account) based on them making that selection in a Hubspot form field. This ideally would happen onchange and occur as soon as it is selected instead of happening on a form submission.

ID: license_type_of_interest-cb1da23a-da50-42f8-b281-b8845c18b0a6
value: Academic License

Attempted to get it by Id, match the values to “Academic License” and if that is the value to redirect to a new url immediately. Also, unfortunately using WordPress and Hubspot forms.

Select Snippet:

<select id="license_type_of_interest-cb1da23a-da50-42f8-b281-b8845c18b0a6" required="" class="hs-input" name="license_type_of_interest">
  <option disabled="" value="">Please Select</option>
  <option value="Silver License">Silver</option>
  <option value="Gold License">Gold</option>
  <option value="Enterprise License">Enterprise</option>
  <option value="Academic License">Academic</option>
  <option value="Researcher License">Researcher</option>
</select>