Prevent React form submit on state update

I am trying to prevent the form submission on the Input component showPassword state update. It appears that, for some reason, this happens all the time:

Input component:

const renderIconFromType = (
    type: HTMLInputTypeAttribute,
    iconProps?: IconProps
) => {
    const defaultHeight = 20
    const defaultWidth = 20

    switch (type) {
        case 'email':
            return (
                <Mail
                    height={defaultHeight}
                    width={defaultWidth}
                    {...iconProps}
                />
            )
        case 'password':
            return (
                <Lock
                    height={defaultHeight}
                    width={defaultWidth}
                    {...iconProps}
                />
            )
        default:
            return null
    }
}

export const Input = ({
    register,
    placeholder,
    name,
    errors,
    type,
    defaultValue,
    validation,
    isTheme,
    disabled,
    ...rest
}: Props) => {
    const [showPassword, setShowPassword] = useState<boolean>(false)

    return (
        <div className="my-3">
            <div className="flex flex-col relative">
                <div
                    className={classNames(
                        'absolute top-1/2 left-3 -translate-y-1/2 text-global-disabled',
                        {
                            'text-global-warning': errors[name],
                        }
                    )}
                >
                    {renderIconFromType(type)}
                </div>
                <input
                    id={name}
                    type={showPassword ? 'text' : type}
                    placeholder={placeholder}
                    defaultValue={defaultValue}
                    disabled={disabled}
                    autoComplete="off"
                    {...register(name, validation)}
                    {...rest}
                />
                {type === 'password' && (
                    <button
                        onClick={() => setShowPassword(!showPassword)}
                        className="absolute top-1/2 right-3 -translate-y-1/2 text-global-disabled"
                    >
                        {showPassword ? (
                            <Eye height={20} width={20} />
                        ) : (
                            <EyeOff height={20} width={20} />
                        )}
                    </button>
                )}
            </div>
            {errors[name] && (
                <p className="text-sm text-global-warning mt-2">
                    {errors[name]?.message}
                </p>
            )}
        </div>
    )
}

export default Input

Form component:

const { error, loading, authWithEmailAndPassword } = useAuthUserContext()

const onSubmit: SubmitHandler<FormProps> = async (data) => {
        if (!isValid) {
            return
        }

        const { email, password } = data
        await authWithEmailAndPassword(email, password)
    }

<form onSubmit={handleSubmit(onSubmit)}>
            <Input
                name="email"
                type="email"
                placeholder="Email"
                errors={errors}
                register={register}
                validation={{
                    required: {
                        value: true,
                        message: 'Email is required!',
                    },
                    maxLength: {
                        value: 30,
                        message: 'Maximum email length is 30!',
                    },
                    minLength: {
                        value: 8,
                        message: 'Minimum email length is 8!',
                    },
                }}
            />
</form>

I have performed the following actions that keep displaying error messages on clicking the showPassword button, which I would like to prevent:

  1. Used useMemo and useCallback hooks
  2. Used the e.preventDefault() within the form submission function (onSubmit)

(Vue.js 2) Can’t update the value after POST function

The Vue.js 2 code below is the data form that I sent it to the backend. I used vuex to deal with my data status. After I use POST function, the result which returns from the backend changes the data value of sampleId. The value is created by the database and will automatically plus one every time there is a new piece of data. I’ve used console log to check my status after use POST function and the status successfully changed (which means it not only successfully created by the backend but also sent it back to frontend successfully.). However, I still can’t see the updated result of sampleId in the frontend after I press button. Can any one please help me to revised my code? Thanks!

<form @submit.prevent="handleSubmit">
    <h2 class="newSample">2. Add New Sample Data</h2>
         <div class="form-group">
              <label for="productName">Product Name</label>
              <input type="text" v-model="sample.productName" name="productName" v-validate="'required'" class="form-control" :class="{ 'is-invalid': submitted && errors.has('productName') }" />
                        <div v-if="submitted && errors.has('productName')" class="invalid-feedback">{{ errors.first('productName') }}</div>
                    </div>

                    <div class="form-group">
                        <label for="OracleItemNum">Oracle Item Number</label>
                        <input type="number" v-model="sample.OracleItemNum" name="OracleItemNum" class="form-control" :class="{ 'is-invalid': submitted && errors.has('OracleItemNum') }" />
                        <div v-if="submitted && errors.has('OracleItemNum')" class="invalid-feedback">{{ errors.first('OracleItemNum') }}</div>
                    </div>
                    <div class="form-group">
                        <label for="batchSize">Batch Size</label>
                        <input type="number" v-model="sample.batchSize" name="batchSize" class="form-control" :class="{ 'is-invalid': submitted && errors.has('batchSize') }" />
                        <div v-if="submitted && errors.has('batchSize')" class="invalid-feedback">{{ errors.first('batchSize') }}</div>
                    </div>
                    <div class="form-group">
                        <label for="numCntrRecv">Number of Containers Received</label>
                        <input type="number" v-model="sample.numCntrRecv" name="numCntrRecv" class="form-control" :class="{ 'is-invalid': submitted && errors.has('numCntrRecv') }" />
                        <div v-if="submitted && errors.has('numCntrRecv')" class="invalid-feedback">{{ errors.first('numCntrRecv') }}</div>
                    </div>
                    <div class="form-group">
                        <label for="aqlLevel">AQL Level</label>
                        <select name="aqlLevel" v-model="sample.aqlLevel">
                            <option value="I" v-if="samples.all.qualified == 'I' || !checkOracleItemNum.length || samples.all.qualified == 'S-3'">I</option>
                            <option value="II" v-if="samples.all.qualified == false || !checkOracleItemNum.length" >II</option>
                            <option value="III" v-if="samples.all.qualified == 'I' || !checkOracleItemNum.length">III (Tighted Level)</option>
                            <option value="S-3" v-if="samples.all.qualified == 'S-3' || !checkOracleItemNum.length || samples.all.qualified == 'I'" >S-3</option>
                        </select>
                    </div>
                    <div class="form-group" v-if="sample.aqlLevel == 'I'">
                        <label for="fullOrReduced">FULL or REDUCED</label>
                        <select name="fullOrReduced" v-model="sample.fullOrReduced" v-if="sample.fullOrReduced !== null">
                            <option value="FULL" v-if="sample.aqlLevel == 'I'">FULL</option>
                            <option value="REDUCED" v-if="sample.aqlLevel == 'I'">REDUCED</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <button class="btn btn-primary" :disabled="!sample.productName.length || !sample.OracleItemNum.length || !sample.batchSize.length || !sample.numCntrRecv.length || !sample.aqlLevel.length">Add</button>
                        <img v-show="sample.adding" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
                    </div>
                </form>
                <!-- TODO not showing sampleId instantly -->
                <div class="qualified" v-if="samples.sample !== undefined && samples.sample.sampleId !== undefined && submitted === true" :key="samples.sample.sampleId">The Sample ID is {{samples.sample.sampleId}}  </div>

The Javascript part for the form page:

<script>
import { mapState, mapActions } from 'vuex'

export default {
    data () {
        return {
            sample:{
                productName: '',
                OracleItemNum: 0,
                batchSize: 0,
                numCntrRecv: 0,
                aqlLevel: '',
                fullOrReduced: '',
                sampleSize: 0,
                referenceNum: 0,
                sampleId: 0
            },
            checkOracleItemNum: 0,
            showIorS3: false,
            submitted: false,
            showResult: false,
            canNotEmpty: false,
            sampleId: 0
        }
    },
    created () {
        //this.getSampleId();
    },
    computed: {
        
        // workable
        // ...mapState({
        //     account: state => state.account, 
        //     users: state => state.users.all}, ['sample'])
        ...mapState({
            account: state => state.account, 
            users: state => state.users.all,
            samples: state => state.samples
        }),
        count() {
            console.log(this.$store.samples);
        }
    },
    methods: {
        ...mapActions('samples', {
            addNewSample: 'addNewSample',
            testQualified: 'testQualified'
        }),
        ...mapActions('users', {
            getAllUsers: 'getAll',
            deleteUser: 'delete'
        }),
        handleSubmit (e) {
            this.submitted = true;
            this.addNewSample(this.sample);
        },
        handleTest (e){
            //this.qualified = true;
            // if(this.checkOracleItemNum == ''){
            //     sample.qualifying = false
            // }
            this.testQualified(this.checkOracleItemNum);
            //console.log(e.target.elements.);
            //console.log(this.testQualified(this.checkOracleItemNum));            
        },
        getResult(){
            this.showResult = true;
        },
        reload(){
            this.$forceUpdate();
        }
    },
    watch: {
        sampleId(newValue, oldValue) {
        console.log(`Updating from ${oldValue} to ${newValue}`);

        // Do whatever makes sense now
        // if (newValue === 'success') {
        //     this.complex = {
        //     deep: 'some deep object',
        //     };
        // }
    }}
};
</script>

This is what I did in the action part in the store:

addNewSample({dispatch, commit}, sample){
        commit('addNewSampleRequest', sample);
        sampleService.addNewSample(sample).then(
            sample => {
                console.log(sample.sampleId);
                if(sample != null && sample.sampleId != undefined || sample.sampleId != null) commit('addNewSampleSuccess', sample);
            },
            error => {
                commit('addNewSampleFailure', error);
                dispatch('alert/error', error, { root: true });
            }
        )
    },

This is the mutation part of the code:

    addNewSampleRequest(state, sample) {
        state.sample = sample;
    },
    addNewSampleSuccess(state, sample) {
        state.sample = sample;
        console.log(state);
    },
    addNewSampleFailure(state, error) {
        state.sample = null;
    }

I add index.js file to below to reply @Phil ‘s question. (The code above this file is written in samples.module.js file)


import Vue from 'vue';
import Vuex from 'vuex';

import { alert } from './alert.module';
import { account } from './account.module';
import { users } from './users.module';
import { samples } from './samples.module';

Vue.use(Vuex);

export const store = new Vuex.Store({
    modules: {
        alert,
        account,
        users,
        samples
    }
});

This is what I get in my console after I press the button. 130 is the sampleId and the object below is the new status that return from the backend.
enter image description here

How to Update an “Array of Arrays”, Convert it to CSV, and Download the File?

Forenote: I am extremely inexperienced with HTML and Javascript. Apologies for any part of the snippet that may seem inefficient or nonsensical.

In my application, the user inputs values to multiple textboxes, a bubble select, a dropdown menu, and a file upload in the form of a png image. Every time the submit button is pressed, I want these inputs saved into an array, and then that array is placed into another array, essentially creating an “array of arrays.” An additional array is added each time the user submits their input. At any point, the user can request to download this continually updated “master array” containing all inputs submitted up to this point.

However, in my current code, whenever I download the CSV file, none of the previous submitted values are contained in the retrieved file. Essentially, an empty CSV is downloaded save for the default values that the array was initially declared with.

What I am wondering is, have I perhaps misunderstood a concept partway and created ineffectual code somewhere in my implementation. Any and all help is greatly appreciated.

I initialized a global array called Log in Javascript with the first element of the array being another array containing the “Date”, “Time”, “Employee ID”, etc. strings so that these default elements act as a sort of column header when converted to excel.

<script>
    var log = [["Date ", "Time ", "Employee ID ", "Project Code ", "Task Number ", 
"Action Type ", "Chip Count ", "Chip ID String ", "Image "]];
</script>

Following the master array declaration, I implemented code to receive user input.

I then created a submit button that would save the current inputs by the user into a variable and place them into an array. This array will be one instance of a “log entry” and will be placed into a master array (“log”) containing all log entries.

Date and Time are retrieved through the date constructor.

EmployeeID, ProjectCode, and Task Number is retrieved through input from a text box.

Action Type is retrieved through a bubble select input.

ChipCount is retrieved through a dropdown menu

ChipIDStrings are retrieved through multiple textboxes appended together into one string depending on if
the string is empty or not.

Container Image is retrieved by converting a PNG into base64 (I have a suspicion that any issues with code implementation may be pinpointed here).

<!-- Submit Button -->
<button onclick="saveToLog()">Submit</button>
<script>
    function saveToLog() {

    // Preparing to Write to CSV File 

    // get date and set to variable 
    var today = new Date();
    var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();


    // get time and set to variable 
    var today = new Date();
    var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();


    // Set employee ID input to variable 
    var EmployeeID = document.getElementById("EmployeeID").value;

    //Set project code input to variable
    var ProjectCode = document.getElementById("ProjectCode").value;

    //Set task number input to variable
    var TaskNumber = document.getElementById("TaskNumber").value;


    // Set Action type to variable 
    var ActionType = document.getElementById("ActionType").value;


    // Create a variable that counts how many chips are being registered 
    var ChipCount = document.getElementById("elementreg").value;


    // Create a string containing all non blank chip IDs separated by a comma and space-->
    var ChipIDString = "";

    if (document.getElemendById("First Chip ID").value !== "") {
        var ChipIDString = ChipIDString + document.getElementById("First Chip ID").value + ", ";
    }

    if (document.getElemendById("Second Chip ID").value !== "") {
        var ChipIDString = ChipIDString + document.getElementById("Second Chip ID").value + ", ";
    } 

    if (document.getElemendById("Third Chip ID").value !== "") {
        var ChipIDString = ChipIDString + document.getElementById("Third Chip ID").value + ", ";
    }

    if (document.getElemendById("Fourth Chip ID").value !== "") {
        var ChipIDString = ChipIDString + document.getElementById("Fourth Chip ID").value + ", ";
    }


    // Create variable that converts picture to base64 string 
    var ContainerImage = document.getElementById("photo").toDataUrl();

    // Create an array containing all the variables and add it to the log array
    var logEntry = [date, time, EmployeeID, ActionType, ChipCount, ChipIDString, ContainerImage];
    log.push( logEntry );

    }
</script>

`

I then created a Download Button that would convert the master array into CSV formatting and download the file. However, when downloaded, nothing appears in the resulting CSV file save for the default string values.

<script>
function downloadCSV() {
    let csvContent = "data:text/csv;charset=utf-8," + log.map(e => e.join(",")).join("n")

    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "my_data.csv");
    document.body.appendChild(link); // Required for FF

    link.click(); // This will download the data file named "my_data.csv".
}
</script>

There was an option to use the Blob method to download the CSV file. However, some of my inputs such as the text boxes were required and did not allow the download button to be pressed without the inputs containing some arbitrary values that would never be submitted to begin with. I was unsure how to bypass this issue.

How do I get each and every item in a div

I have the following divs:

 <div  id='1'   title='A'  description='B' activity-note='C'  grouped-as='Test'>  </div>
 <div  id='4'   title='Z'  description='Z' activity-note='Z'  grouped-as='Soil Prep'>  </div>
 <div  id='5'   title='Q'  description='Q' activity-note='Q'  grouped-as='Soil Prep'>  </div>

I would like to get the values for each of the assigned items in the div.

I have tried using the following (as an example) but I get an error:

title=document.getElementById('1').getAttribute("title");

Obviously I am confused and so any help and/or guidance would be appreciated.

How to dynamically call javascript files in an html file with jinja?

I’m trying to dynamically call different javascript files into my HTML by passing the filename through jinja, but it’s not working for some reason. My website is a survey/quiz website, and I only want to have one html file for all of the quizzes. Using my variable in jinja doesn’t yield any results for some reason. Any idea what to do to make it work?

Here’s my python routing.

@app.route("/my-quiz")
def myQuiz():
    script =  "myquiz.js"
    return render_template("survey.html", script=script)

And here is that info being rendered in HTML.

<script src="{{ url_for('static', filename='scripts/script') }}"></script>

I haven’t really read any documentation on how jinja handles variables so I’m just kinda guessing at how I think it works. Is there a better way to do this?

How do I update the contents of one Form Select based on the selection of a preceding Form Select?

For my code, I am trying to update the selectProf list based on what course is selected. I am able to find the relevant professors based on a course change but am unable to figure out how to force the prof select list to update based on the course selection. Any help is much appreciated!

import { Modal, Button, Form, Row, Col } from "react-bootstrap";
import { useState } from "react";

export default function CreateReview(props) {
  const [show, setShow] = useState(false);

  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

  const yearOptions = [];
  for (let i = 2020; i <= new Date().getFullYear(); i++) {
    yearOptions.push(
      <option key={i} value={i}>
        {i}
      </option>
    );
  }

  var selectedCourseID;

  const handleCourseChange = (e) => {
    selectedCourseID = e.target.value;
    relevantProfessors();
  };

  var relevantProfs = [];

  function relevantProfessors() {
    relevantProfs = [];
    props.profData.map((prof) => {
      if (prof.courseID == selectedCourseID) {
        relevantProfs.push(prof.professor);
      }
    });
    console.log(relevantProfs);
  }

  function submitHandler() {}

  return (
    <>
      <Button variant="primary" onClick={handleShow}>
        Create a Review
      </Button>

      <Modal show={show} onHide={handleClose}>
        <Modal.Header closeButton>
          <Modal.Title>Create New Review</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <Form onSubmit={submitHandler}>
            <Form.Select
              placeholder="selectCourse"
              required={true}
              aria-label="Course Selection"
              onChange={handleCourseChange}
            >
              <option key="blankChoice" hidden value>
                Select a Course
              </option>
              {props.courseData.map((course) => (
                <option key={course.courseID} value={course.courseID}>
                  CIT {course.courseID}: {course.courseName}
                </option>
              ))}
            </Form.Select>
            <Row>
              <Col>
                <Form.Select
                  placeholder="selectSemester"
                  required={true}
                  aria-label="Semester Taken"
                >
                  <option key="blankChoice" hidden value>
                    {" "}
                    Semester{" "}
                  </option>
                  <option>Fall</option>
                  <option>Spring</option>
                  <option>Summer</option>
                </Form.Select>
              </Col>
              <Col>
                <Form.Select
                  placeholder="selectYear"
                  required={true}
                  aria-label="Year Taken"
                >
                  <option key="blankChoice" hidden value>
                    {" "}
                    Year{" "}
                  </option>
                  {yearOptions}
                </Form.Select>
              </Col>
            </Row>
            <br />
            <Form.Select
              placeholder="selectProf"
              required={true}
              aria-label="Professor Selection"
            >
              <option key="blankChoice" hidden value>
                Select a Professor
              </option>
              {relevantProfs.forEach((prof) => {
                console.log(prof);
                return <option>{prof}</option>;
              })}
            </Form.Select>

            <Form.Group className="mb-3" controlId="formBasicPassword">
              <Form.Label>Password</Form.Label>
              <Form.Control type="password" placeholder="Password" />
            </Form.Group>
            <Form.Group className="mb-3" controlId="formBasicCheckbox">
              <Form.Check type="checkbox" label="Check me out" />
            </Form.Group>
            <button>Publish Review</button>
          </Form>
        </Modal.Body>
      </Modal>
    </>
  );
}

I’ve tried adding:

const [show, setShow] = useState(false);
  const [selectedCourseID, setSelectedCourseID] = useState("");
  const [relevantProfs, setRelevantProfs] = useState([]);

  const handleCourseChange = (e) => {
    const courseID = e.target.value;
    setSelectedCourseID(courseID);
    const profs = props.profData.filter((prof) => prof.courseID === courseID);
    setRelevantProfs(profs.map((prof) => prof.professor));
  };

but it has the same effect as what I currently have. Thank you!

Google Maps API: Need Markers to only show on map after user puts in input

I have a react app that’ll display markers on a map using Google Maps API that will display locations of bars associated with certain football clubs.

I have it set up so the locations inside the array are displayed on the map but the problem is every single location is displayed simultaneously, I would like it so I can put in a country (E.g: “United States of America”) and a football club (E.g: Liverpool) and on the map it’ll display just the bars in the array that matches those inputs. I’m not sure what the problem is.

Map.jsx Component:

import React, { useState } from "react";
import NavBar from "./NavBar";
import Image from "../Haaland.png";
import MapComponent from "./MapComponent";
import { LoadScript } from "@react-google-maps/api";
import Footer from "./Footer";
import CountryAutoComplete from "./CountryAutoComplete";
import ClubAutocomplete from "./ClubAutoComplete";

function Map() {
  const [selectedCountry, setSelectedCountry] = useState("");
  const [selectedClub, setSelectedClub] = useState("");
  const [searchClicked, setSearchClicked] = useState(false);

  // Set initial center and zoom level
  const center = { lat: 0, lng: 0 };
  const zoom = 3;

  return (
    <>
      <NavBar />

      <section id="InputSection">
        <div className="InputDiv">
          <h1 className="MapPageHeaderText">Type in your Location and Club</h1>

          <div className="CountryDiv">
            <i
              class="fa-solid fa-earth-europe"
              style={{
                color: "white",
                fontSize: "xx-large",
                marginBottom: "15px",
                marginRight: "10px",
              }}
            ></i>

            <CountryAutoComplete
              suggestions={[
                "Australia",
                "Belgium",
                "Canada",
                "England",
                "France",
                "Germany",
                "Ireland",
                "Italy",
                "Japan",
                "Spain",
                "South Korea",
                "Sweden",
                "United States of America",
              ]}
              onChange={(value) => setSelectedCountry(value)}
            />
          </div>

          <div className="ClubDiv">
            <i
              class="fa-regular fa-futbol"
              style={{
                color: "white",
                fontSize: "xx-large",
                marginBottom: "15px",
                marginRight: "10px",
              }}
            ></i>

            <ClubAutocomplete
              suggestions={[
                "Arsenal",
                "AC Milan",
                "Barcelona FC",
                "Bayern Munich",
                "Chelsea",
                "Juventus",
                "Manchester City",
                "Manchester United",
                "Liverpool",
                "Real Madrid",
                "Tottenham Hotspurs",
                "West Ham United",
              ]}
              onChange={(value) => setSelectedClub(value)}
            />
          </div>

          <a href="#MapSection">
            <button
              type="submit"
              className="SearchButton"
              onClick={() => setSearchClicked(true)}
              style={{ width: "300px", height: "50px" }}
            >
              Search
            </button>
          </a>
        </div>

        <div className="ImageDiv">
          <img
            className="PlayerImage2"
            src={Image}
            alt="Erling Haaland holding Premier League Trophy"
          />
        </div>
      </section>

      <section id="MapSection">
        <h1 className="MapDivText">Results</h1>
        <LoadScript googleMapsApiKey="API_KEY">
          <div
            style={{
              marginLeft: "auto",
              marginRight: "auto",
              marginTop: "50px",
            }}
          >
            <MapComponent
              center={center}
              zoom={zoom}
              selectedCountry={selectedCountry}
              selectedClub={selectedClub}
              searchClicked={searchClicked}
            />
          </div>
        </LoadScript>

        <a href="/map">
          <button className="ResetButton">Reset</button>
        </a>
      </section>

      <Footer />
    </>
  );
}

export default Map;

Here is my MapComponent.jsx:

import { GoogleMap, InfoWindow } from "@react-google-maps/api";
import { MarkerF } from "@react-google-maps/api";
import React, { useState } from "react";

// Array of bar data with country, football club, and coordinates
const bars = [
  {
    country: "Australia",
    club: "Arsenal",
    lat: -33.885055433597,
    lng: 151.20966156719123,
  },
  {
    country: "Australia",
    club: "Manchester United",
    lat: -34.94636965495918,
    lng: 138.62657079153266,
  },
  {
    country: "Canada",
    club: "Liverpool",
    lat: 49.28637807745695,
    lng: -123.11695651719553,
  },
  {
    country: "Germany",
    club: "Bayern Munich",
    lat: 48.175002206190136,
    lng: 11.592748746031473,
  },
  {
    country: "Japan",
    club: "Liverpool",
    lat: 35.64857860594483,
    lng: 139.71303475978445,
  },
  {
    country: "South Korea",
    club: "Manchester United",
    lat: 53.4631,
    lng: -2.2913,
  },
  {
    country: "South Korea",
    club: "Tottenham Hotspurs",
    lat: 37.552079094148446,
    lng: 126.9226752350085,
  },
  {
    country: "South Korea",
    club: "Liverpool",
    lat: 37.56004882603966,
    lng: 126.92511388465444,
  },
  {
    country: "United States of America",
    club: "Arsenal",
    lat: 40.74496672417892,
    lng: -73.99249257407631,
  },
  {
    country: "United States of America",
    club: "Arsenal",
    lat: 32.74202567965132,
    lng: -117.1289996550291,
  },
  {
    country: "United States of America",
    club: "Liverpool",
    lat: 34.007969428759544,
    lng: -118.41245218835955,
  },
  {
    country: "United States of America",
    club: "Manchester United",
    lat: 39.750624531403766,
    lng: -104.9853437709032,
  },

  // Add more bar data as needed
];

const mapOptions = {
  mapId: "cb21e6acbb31cd1",
  scrollwheel: true, // Enable scroll wheel zooming
  minZoom: 2,
  maxZoom: 20,
};

function MapComponent({
  center,
  zoom,
  selectedCountry,
  selectedClub,
  searchClicked,
}) {
  const [selectedMarker, setSelectedMarker] = useState(null);

  const onMarkerClick = (marker) => {
    setSelectedMarker(marker);
  };
  return (
    <GoogleMap
      mapContainerStyle={{ width: "75%", height: "600px", margin: "0 auto" }}
      mapid="map"
      center={center}
      zoom={zoom}
      options={mapOptions}
    >
      {searchClicked &&
        bars.map((bar, index) => {
          if (
            (!selectedCountry || bar.country === selectedCountry) &&
            (!selectedClub || bar.club === selectedClub)
          ) {
            console.log(`Creating marker for: ${bar.country} - ${bar.club}`);
            return (
              <MarkerF
                key={index}
                position={{ lat: bar.lat, lng: bar.lng }}
                onClick={() => onMarkerClick(bar)}
              >
                {selectedMarker === bar && (
                  <InfoWindow onCloseClick={() => setSelectedMarker(null)}>
                    <div>
                      <h4>{`${bar.country} - ${bar.club}`}</h4>
                    </div>
                  </InfoWindow>
                )}
              </MarkerF>
            );
          }
          return null;
        })}
    </GoogleMap>
  );
}

export default MapComponent;

Inputs inside the CountryAutoComplete.jsx and ClubAutoComplete.jsx components:

    <input
        type="text"
        placeholder="Enter a Country"
        onChange={onChange}
        onKeyDown={onKeyDown}
        value={input}
      />
    <input
        type="text"
        placeholder="Enter a Football Club"
        onChange={onChange}
        onKeyDown={onKeyDown}
        value={input}
      />

How to fetch data of nested html file on website

I am trying to fetch all html from a website. Fetch is returning 3 levels of nested information while I know there are at least 11. I have tried many different ways of parsing the data but the info that I know is available (I see on inspector on website) is not coming through.

Dynamically add link to javascript generated AJAX HTML table

I am generating HTML tables with javascript, populating the cells with data from an AJAX file. I want to dynamically add links to certain cells. Linking to myfile.php. I’ll let the PHP deal with the requests.

But, how can I add the links?

Take this simple example. Only two fields. So I want each cell to have a unique link back to my server so I can then serve another JSON file for expanded info.

I was thinking of a conditional, depending on the key.

 `if(index == 'username') {

    ADD THE LINK
    } else { 
    .....
    }
    `

I am having trouble with the correct syntax, I having trouble getting it to work. All these years, I never programmed Javascript.

See my code below.

`<HTML>
    ...

    <script>
    var data = [
        {
            "id": "3",
            "username": "foo",
            "email": "[email protected]"
        },
        {
            "id": "9",
            "username": "foobarbam",
            "email": null
        },
        {
        "id": "10",
        "username": "bar",
        "email": "[email protected]"
        },
        {
        "id": "11",
        "username": "bam",
        "email": null
        },
        {
        "id": "12",
        "username": "snoopy",
        "email": null
        },
        {
        "id": "15",
        "username": "rogerwaters",
        "email": "[email protected]"
        }
       ];



    var keys = [];

   document.write("<table><tr>");
   var tr;
    for (var i = 0; i < data.length; i++) {
        tr = $('<tr/>');
        tr.append("<td>" + data[i].username + "</td>");
        tr.append("<td>" + data[i].email + "</td>");
        
        $('table').append(tr);
    }

    document.write("</table>");
    </script>
    </body>`
    ```

I am having trouble trying to play a modpack on minecraft

I keep getting error code 1 i have done everything to try and fix it. Here is the crash report

A fatal error has been detected by the Java Runtime Environment:

No core dump will be written. Minidumps are not enabled by default on client versions of Windows

i couldnt post full thing so i just got a little bit

  1. reinstall minecraft
  2. reinstall Java
  3. restart pc
  4. update everything
  5. adjust settings
    mostly everything

Using dynamically created components without remounting in React?

In a codebase I’m working on, it’s pretty common to return non-stable dynamically created React Component from hooks. E.g.:

function useSomeHook() {
  const val = useVal();

  return {
    val,
    DynamicComponent: () => {
      doSomething1(val);

      return ...;
    },
  };
}

It would be used like:

function App() {
  const { val, DynamicComponent } = useSomeHook();
  doSomething2(val);

  return <DynamicComponent />;
}

App gets val from useSomeHook instead of rerunning useVal because useVal might be expensive or it would take effort to refactor.

The issue is that React treats every DynamicComponent as a different component, since it’s not stable. Every time App rerenders, DynamicComponent would be remounted. It seems like the only ways to fix this are:

  1. Refactor so useSomeHook doesn’t return a dynamic component
  2. Make DynamicComponent stable (e.g. wrap it with useRef), then use some hack to access the non-stale val from the useSomeHook scope

Is there another way to fix this by making React treats DynamicComponent as the same component after rerendering, even though it’s not referentially equal?

Here’s a JSFiddle demo: https://jsfiddle.net/fj3Lg1o5/6/

And a related question with a concrete use-case: React: swap a parent component without remounting the child component?

Vue.js: add new component (sw-modal) to existing async selector

I overwrite my admin panel component in Shopware 6 in such a way that when I add the next item, it displays the sw-modal with the information that it adds more than it should.

Original Vue.js component:

    <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
    {% block sw_entity_multi_id_select %}
    <sw-entity-multi-select
        :entity-collection="collection"
        :context="context"
        :criteria="criteria"
        :disabled="disabled"
        v-bind="$attrs"
        v-on="getListeners"
        @change="updateIds"
    >
    
        <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
        {% block sw_entity_multi_id_select_label_property %}
        <template #selection-label-property="{ item, index, labelProperty, valueProperty }">
            <slot
                name="selection-label-property"
                v-bind="{ item, index, labelProperty, valueProperty }"
            ></slot>
        </template>
        {% endblock %}
    
        <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
        {% block sw_entity_multi_id_select_results_list_before %}
        <template #before-item-list>
            <slot name="before-item-list"></slot>
        </template>
        {% endblock %}
    
        <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
        {% block sw_entity_multi_id_select_results_list_result_label %}
        <template #result-label-property="{ item, index, labelProperty, valueProperty, searchTerm, getKey, highlightSearchTerm }">
            <slot
                name="result-label-property"
                v-bind="{ item, index, labelProperty, valueProperty, searchTerm, getKey, highlightSearchTerm }"
            ></slot>
        </template>
        {% endblock %}
    
        <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
        {% block sw_entity_multi_id_select_results_list_result_description %}
        <template #result-description-property="{ item, searchTerm, highlightSearchTerm }">
            <slot
                name="result-description-property"
                v-bind="{ item, searchTerm, highlightSearchTerm }"
            ></slot>
        </template>
        {% endblock %}
    
        <!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
        {% block sw_entity_multi_id_select_results_list_after %}
        <template #after-item-list>
            <slot name="after-item-list"></slot>
        </template>
        {% endblock %}
    
        <template #label>
            <slot name="label"></slot>
        </template>
    </sw-entity-multi-select>
    {% endblock %}

import template from './sw-entity-multi-id-select.html.twig';

const { Component, Context, Mixin } = Shopware;
const { EntityCollection, Criteria } = Shopware.Data;

// eslint-disable-next-line sw-deprecation-rules/private-feature-declarations
Component.register('sw-entity-multi-id-select', {
    template,
    inheritAttrs: false,

    mixins: [
        Mixin.getByName('remove-api-error'),
    ],

    model: {
        prop: 'ids',
        event: 'change',
    },

    props: {
        ids: {
            type: Array,
            required: false,
            default() {
                return [];
            },
        },

        repository: {
            type: Object,
            required: true,
        },

        criteria: {
            type: Object,
            required: false,
            default() {
                return new Criteria(1, 25);
            },
        },

        context: {
            type: Object,
            required: false,
            default() {
                return Context.api;
            },
        },

        disabled: {
            type: Boolean,
            required: false,
            default: false,
        },
    },

    data() {
        return {
            collection: null,
        };
    },

    computed: {
        getListeners() {
            const listeners = {};

            Object.keys(this.$listeners).forEach(listener => {
                if (listener !== 'change') {
                    listeners[listener] = this.$listeners[listener];
                }
            });

            return listeners;
        },
    },

    watch: {
        ids() {
            if (this.collection === null) {
                this.createdComponent();
                return;
            }

            if (this.collection.getIds() === this.ids) {
                return;
            }

            this.createdComponent();
        },
    },

    created() {
        this.createdComponent();
    },

    methods: {
        createdComponent() {
            const collection = new EntityCollection(
                this.repository.route,
                this.repository.entityName,
                this.context,
            );

            if (this.collection === null) {
                this.collection = collection;
            }

            if (this.ids.length <= 0) {
                this.collection = collection;
                return Promise.resolve(this.collection);
            }

            const criteria = Criteria.fromCriteria(this.criteria);
            criteria.setIds(this.ids);
            criteria.setTerm('');
            criteria.queries = [];

            return this.repository.search(criteria, { ...this.context, inheritance: true }).then((entities) => {
                this.collection = entities;
                return this.collection;
            });
        },

        updateIds(collection) {
            this.collection = collection;
            this.$emit('change', collection.getIds());
        },
    },
});

Modified Component overriding the parent:

    {% block sw_entity_multi_id_select %}
    {% parent %}

    <sw-modal title="My Alert" v-if="isModalVisible">
        {{ isModalVisible }}
    </sw-modal>
{% endblock %}

import template from './sw-entity-multi-id-select-extend.html.twig';

const { Component } = Shopware;

Component.extend('sw-entity-multi-id-select-extend', 'sw-entity-multi-id-select', {
    template,

    data() {
        return {
            isModalVisible: true
        };
    }
});

It seems that this could be an async problem but I can’t figure it out. I use this as a plugin configuration and add the component field to the xml.
I wonder what the problem might be.

Javascript, if other condition is met, set a bool

I have an if statement, but I want it to change a bool from false to true only if condition 2 is met. If condition 1 is satisfied it should do nothing.

I tried setting a var in the if statement but that obviously threw a syntax error, played around with the nesting but I need this to be an if or.

Is there a way to implement this?

if (/* condition 1 */|| /* condition 2 */) {

}

Gomoku (Connect Five) Minimax algorithm not finding obvious win

I’m developing a very simple connect five (gomoku) AI for fun in Javascript using minimax and alpha beta pruning. I’ve just been following some tutorials online, but for some reason I can’t quite get it to work. I think I have a logical bug somewhere, because in the following code, there is a fork if the AI places a piece in the second row and third column, but it’s not being found as the bestMove.

Weirdly enough, if I set a breakpoint, that position (row: 2, col: 1) is often found as the winningMove, but for whatever reason, the minimax function never calculates bestMove to be that move, even though I believe it clearly should be. That is, if the AI places a piece there, it’s basically an immediate win next turn, because it causes a win in multiple directions.

That is, if the AI places a move at the white 2, then there can either be a vertical win, or a horizontal win, in the next AI move, because the human could only block one of them:

enter image description here

const ROWS = 9;
const COLS = 9;
const LEN = 5;

const EMPTY = 0;
const HUMAN = 1;
const COMP = 2;

function checkDirection(grid, who, currChain, sRow, sCol, incRow, incCol) {
  let newChain = 0;

  while (currChain + newChain < LEN) {
    const row = sRow + (incRow * (newChain + 1));
    const col = sCol + (incCol * (newChain + 1));

    if (grid[row * COLS + col] !== who) {
      break;
    }
    
    newChain++;
  }

  return newChain;
}

function lineCheck(grid, who, sRow, sCol, mRow, mCol) {
  let chain = 1;

  chain += checkDirection(grid, who, 0, sRow, sCol, mRow, mCol);
  chain += checkDirection(grid, who, chain, sRow, sCol, -mRow, -mCol);

  return chain >= LEN;
}

function isWinningMove(grid, who, row, col) {    
  return lineCheck(grid, who, row, col, 1, 0) || 
         lineCheck(grid, who, row, col, 0, 1) || 
         lineCheck(grid, who, row, col, 1, 1) || 
         lineCheck(grid, who, row, col, -1, 1);
}

function getTile(grid, row, col) {
  if (row < 0 || col < 0 || row >= ROWS || col >= COLS) {
    return -1;
  }

  return grid[row * COLS + col];
}

function hasNeighbor(board, row, col) {
  if (getTile(board, row - 1, col - 1) > 0) { return true; }
  if (getTile(board, row - 1, col + 1) > 0) { return true; }
  if (getTile(board, row + 1, col - 1) > 0) { return true; }
  if (getTile(board, row + 1, col + 1) > 0) { return true; }

  if (getTile(board, row - 1, col) > 0) { return true; }
  if (getTile(board, row + 1, col) > 0) { return true; }

  if (getTile(board, row, col - 1) > 0) { return true; }
  if (getTile(board, row, col + 1) > 0) { return true; }

  return false;
}

let bestMove = Number.MIN_SAFE_INTEGER;

function minimax(board, depth, alpha, beta, player, latestRow, latestCol) {
  if (depth === 0) {
    return evaluatePlayerBoard(board, player, player === COMP ? HUMAN : COMP, latestRow, latestCol);
  }

  if (isWinningMove(board, player, latestRow, latestCol)) {
    return 1000000;
  }

  if (player === COMP) {
    let maxEval = Number.MIN_SAFE_INTEGER;

    for (let row = 0; row < ROWS; row++) {
      for (let col = 0; col < COLS; col++) {
        const idx = row * COLS + col;
        const tileValue = board[idx];

        if (tileValue > 0 || !hasNeighbor(board, row, col)) { continue; }

        board[idx] = player;
        const evaluation = minimax(board, depth - 1, alpha, beta, HUMAN, row, col);
        board[idx] = tileValue;

        if (evaluation > maxEval) {
          maxEval = evaluation;
          bestMove = idx;          
        }

        alpha = Math.max(alpha, evaluation);

        if (beta <= alpha) {
          return maxEval;
        }
      }
    }

    return maxEval;
  } else {
    let minEval = Number.MAX_SAFE_INTEGER;

    for (let row = 0; row < ROWS; row++) {
      for (let col = 0; col < COLS; col++) {
        const idx = row * COLS + col;
        const tileValue = board[idx];

        if (tileValue > 0 || !hasNeighbor(board, row, col)) { continue; }

        board[idx] = player;
        const evaluation = minimax(board, depth - 1, alpha, beta, COMP, row, col);
        board[idx] = tileValue;

        if (evaluation < minEval) {
          minEval = evaluation;
        }

        beta = Math.min(beta, evaluation);

        if (beta <= alpha) {
          return minEval;
        }
      }
    }

    return minEval;
  }
}

function evaluatePlayerBoard(grid, who, latestRow, latestCol) {
  let idx = 0;
  let score = 0;

  if (isWinningMove(grid, who, latestRow, latestCol)) {
    debugger;
    return 1000000;
  }

  for (let row = 0; row < ROWS; row++) {
    for (let col = 0; col < COLS; col++) {
      if (grid[idx] !== who) { idx++; continue; }

      if (getTile(grid, row - 1, col - 1) === who) { score++; }
      if (getTile(grid, row - 1, col + 1) === who) { score++; }
      if (getTile(grid, row + 1, col - 1) === who) { score++; }
      if (getTile(grid, row + 1, col + 1) === who) { score++; }

      if (getTile(grid, row - 1, col) === who) { score++; }
      if (getTile(grid, row + 1, col) === who) { score++; }

      if (getTile(grid, row, col - 1) === who) { score++; }
      if (getTile(grid, row, col + 1) === who) { score++; }
      
      if (getTile(grid, row, col) === who) { score++; }

      idx++;
    } 
  }

  return score;
}

function evaluateBoard(grid, you, opponent, latestRow, latestCol) {
  return evaluatePlayerBoard(grid, you, latestRow, latestCol) - evaluatePlayerBoard(grid, opponent, latestRow, latestCol);
}

const exampleBoard = [
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 2, 0, 2, 2, 1, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 2, 0, 0, 0, 0, 0, 0,
  0, 0, 2, 0, 0, 0, 0, 0, 0,
  0, 0, 2, 0, 0, 0, 0, 0, 0,
  0, 0, 1, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
];

minimax(exampleBoard, 2, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, COMP, -1, -1);

console.log(bestMove);

You can run the snippet above and see that 20 is logged instead of 11, even though 11 is clearly the better move as it causes an immediate win.