Passing Variables to/from Modal - javascript

I implemented a Modal which uses a custom Hook in my App that should function as a login mask for a WiFi network. So far the Modal is working and I also already managed to pass the name of the selected SSID to it. However I'm struggling with getting back a variable into my other component from where I launched the modal.
Modal.js:
import React from 'react';
import { createPortal } from 'react-dom';
const Modal = ({ isShowing, connect, ssid, hide }) => isShowing ? createPortal(
<React.Fragment>
<div className="modal-overlay" />
<div className="modal-wrapper" aria-modal aria-hidden tabIndex={-1} role="dialog">
<div className="modal">
<div className="modal-header">
<button type="button" className="modal-close-button" data-dismiss="modal" aria-label="Close" onClick={hide}>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<p>Connect to: {ssid}</p>
<label>
<form onSubmit={connect}>
<input
id="password"
name="Password"
type="password"
value={"password"}
/>
<button type="submit">Connect</button>
</form>
</label>
</div>
</div>
</div>
</React.Fragment>, document.getElementById("modal")
) : null;
export default Modal;
useModal.js:
import { useState } from 'react';
const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
const [password, setPassword] = useState("password");
function toggle() {
setPassword("HOW");
setIsShowing(!isShowing);
}
return {
password,
isShowing,
}
};
export default useModal;
Settings.js:
import React from "react";
import { useState, useEffect } from "react";
import Modal from "../../components/Modal";
import useModal from "../../components/useModal";
const electron = window.require('electron');
const { ipcRenderer } = electron;
const Settings = ({ reqReload }) => {
const [wifiList, setWifiList] = useState([{ id: "", ssid: 'No Networks available' }]);
const [ssidSelected, setSsidSelected] = useState("127.0.0.1");
const { isShowing, toggle } = useModal();
const updateWifi = (event, args) => {
setWifiList(args);
};
function openDialogue(ssid) {
setSsidSelected(ssid);
toggle();
};
/*
function connectWifi(password) {
console.log("Aktuelles Passwort: ", password);
toggle();
}
*/
useEffect(() => {
ipcRenderer.send('updateWifi');
ipcRenderer.on('wifi_list', updateWifi);
return function cleanup() {
ipcRenderer.removeListener('wifi_list', updateWifi);
};
}, []);
return (
<div className="settings">
<Modal
isShowing={isShowing}
connect={connectWifi}
ssid={ssidSelected}
hide={toggle}
/>
<div className="settings__header">
<h2></h2>
</div>
<div className="settings__body">
<div className="settings__connections">
<div className="settings__connections__wifi">
<p><i>Available Wifi-Networks:</i></p>
<div className="settings__connections__wifi__list">
{wifiList.map((item, i) => (
<div className="settings__connections__wifi__list__item" key={i}>
<button className="selectNetworkButton" type="button" onClick={() => openDialogue(item.ssid)}>{item.ssid}</button>
</div>
))}
</div>
</div>
</div>
</div>
</div>
)
};
export default Settings;
The code above already contains some things I tried. As stated before, passing the SSID to the modal worked, but I dont have a clue how to get the password back to Settings.js to handle the data there.
I'd be happy if someone can point me in the right direction!

in order to get back a variable from a child component, you can have the variable you would like to get back as a state in your parent component:
const [yourVariable, setYourVariable] = useState('')
then pass setYourVariable as a props to your modal.
this way you can set youVariable from inside the modal component, and get back its value this way :
// inside modal component
setYoutVariable(...)

I stumbled over another article just now and it seems like using a stateless component as my model leads to a dead end. Will have to convert it to a stateful component in order to extract the data from the form.

Related

Create and download image of a react component without rendering it

My use case is simple. I have a react component that takes some props and renders something. Now I want to download it as an image without rendering it basically not showing it to the user.
I have tried html2canvas and react-component-export-image. In both of these libraries, I managed to capture the screenshot but both of them required me to render the component.
I used code from this page for react-component-export-image https://www.npmjs.com/package/react-component-export-image
Suppose the following is my component
const Component1 = ({ reference }) => {
return (
<div ref={reference} >
<div className="share-cause-header">
Some header stuff
</div>
<div className="share-cause-body">
some body stuff
</div>
<div className="share-cause-footer">
some footer stuff
</div>
</div>
);
};
Now on another Component2, I want to send some props to my Component1 and then download that component as an image without showing anything to the user. A user should only see the download button and the downloaded image
const Component2 = () => {
const shareButtonImageDownload = (e) => {
e.stopPropagation();
console.log("Hi there");
};
return (
<div >
<button onClick={shareButtonImageDownload } ></button>
</div>
);
};
If the component is not visible, then you can't take a screenshot of it. But you can bring them out of the visible view, like this:
https://codesandbox.io/embed/laughing-http-w3ndr?fontsize=14&hidenavigation=1&theme=dark
import {
exportComponentAsJPEG,
exportComponentAsPDF,
exportComponentAsPNG
} from "react-component-export-image";
import React, { useRef } from "react";
const ComponentToPrint = React.forwardRef((props, ref) => (
<div ref={ref} style={{ marginTop: "-50px" }}>
<div className="share-cause-header">Some header stuff</div>
<div className="share-cause-body">some body stuff</div>
<div className="share-cause-footer">some footer stuff</div>
</div>
));
const MyComponent = () => {
const componentRef = useRef();
return (
<React.Fragment>
<ComponentToPrint ref={componentRef} />
<button onClick={() => exportComponentAsJPEG(componentRef)}>
Export As JPEG
</button>
<button onClick={() => exportComponentAsPDF(componentRef)}>
Export As PDF
</button>
<button onClick={() => exportComponentAsPNG(componentRef)}>
Export As PNG
</button>
</React.Fragment>
);
};
export default MyComponent;

props.onAddNewExpense is not a function . wrong in js.react

hi guys i am trying to send the data from NewComponent component to App component in react while i am trying to do this it gives me an error and i tried hrad to solve this problem but i coudn't
here as you see this is the component that i will take the information form it and i will send it to newcomponent component exactly i will send expenseData object's information up (from child to parent ) but when i do this it gives me this error (props.onAddNewExpense is not a function)
this is the expense form component
import React , {useState} from "react";
import "./ExpenseForm.css"
const ExpenseForm = (props) => {
//the setEnteredTitle will be like a function i can do a refreshing with it .
const [enteredTitle,setEnteredTitle]=useState("")
const [enteredAmount,setEnteredAmount]=useState("")
const [enteredDate,setEnteredDate]=useState("")
const TitleChangeHandeler=(eo) => {
setEnteredTitle(eo.target.value)
console.log(setEnteredTitle)
}
const amountChangeHnadeler= (eo) => {
setEnteredAmount(eo.target.value)
}
const DateChangeHnadeler= (eo) => {
setEnteredDate(eo.target.value)
}
const submitHandeler=(eo) => {
eo.preventDefault(); // it make me to prevent the dafoult that make the page refresh
const expenseData={
Title:enteredTitle,
Amount:enteredAmount,
Date:new Date(enteredDate)
}
console.log(expenseData)
props.onSaveExpenseData(expenseData)
//when the user make a submit it will give a empty data for the sates
setEnteredTitle("");
setEnteredAmount("");
setEnteredDate("");
}
return (
<form onSubmit={submitHandeler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input type="text" className="input" onChange={TitleChangeHandeler} value={enteredTitle} />
</div>
<div className="new-expense__control">
<label> Amount </label>
<input type="number" step="0.01" min="0.01" className="input" onChange={amountChangeHnadeler} value={enteredAmount}/>
</div>
<div className="new-expense__control">
<label>DATE</label>
<input type="date" min="3-12-2021" max="01-01-2025" onChange={DateChangeHnadeler} value={enteredDate} />
</div>
<div className="new-expense__actions">
<button type="submit"> Add expense </button>
</div>
</div>
</form>
);
};
export default ExpenseForm;
and this is the parent component
import React from 'react'
import "./NewComponent.css"
import ExpenseForm from "./ExpenseForm"
const NewComponent = (props) => {
const saveExpenseDataHandeler= (enteredExpenseData) => {
const expenseData = {
...enteredExpenseData ,
id:Math.random().toString()
}
props.onAddNewExpense(expenseData)
}
//here we just point to the function we did not execute it here
return (
<div className="new-expense">
<ExpenseForm onSaveExpenseData={saveExpenseDataHandeler} />
</div>
)
}
export default NewComponent
we can see that i fetch the component props and i am trying to take the child data from there
thanks alot for any answer will come

My hooks aren't opening and closing my modals

I'm new to react and redux, I'm trying to do things the newish hooks way and running into issues opening and closing a Modal using a redux state.
Basically, as soon as my page loads, the modal opens, even though the initial state in the slice is set to false and the close button in the modal footer doesn't close it.
I'm trying to learn from the example that compiles from npx create-react-app redux-demo --template redux but I'm clearly missing something.
Thanks!
AffinityModal.js
import React from 'react';
import { Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader, Row, } from 'reactstrap';
import { affinOpen, toggleAffinAsync } from '../modalSlice'
import { useDispatch } from 'react-redux';
function AffinityModal() {
const dispatch = useDispatch();
return (
<Modal isOpen={affinOpen} toggle={() => dispatch(toggleAffinAsync())}>
<ModalHeader>
<h5 className="modal-title" id="exampleModalLabel">New Ingredient Affinity</h5>
<Button data-dismiss="modal" aria-label="Close" className="close">
<span aria-hidden="true">×</span>
</Button>
</ModalHeader>
<ModalBody>
<div className="container-fluid">
<Form>
<FormGroup>
<Row>
<div className="col-12">
<Label for="mainIngName" className="col-form-label">Main Ingredient:</Label>
</div>
</Row>
<Row>
<div className="col-12">
<Input readOnly type="text" id="mainIngName"></Input>
</div>
</Row>
</FormGroup>
<FormGroup>
<Row>
<div className="col-12">
<Label for="added-ing-text" className="col-form-label">Combines Well With:</Label>
</div>
</Row>
<Row id="secondaryIngs">
<div className="col-10">
<Input type="text" id="added-ing-text" className="secIngInputs"></Input>
</div>
<div className="col-2">
<Button id="ingPlusButton">+</Button>
</div>
</Row>
</FormGroup>
</Form>
</div>
</ModalBody><ModalFooter>
<Button data-dismiss="modal" onClick={() => dispatch(toggleAffinAsync())} color="secondary">Close</Button>
<Button id="submitNewIngButton" color="primary" className="submitButton">Submit</Button>
</ModalFooter>
</Modal >
)
}
export default AffinityModal
modalSlice.js
import { createSlice } from '#reduxjs/toolkit';
export const modalSlice = createSlice({
name: 'openAffinityModal',
initialState: {
isAffinityModalOpen: false,
isRecipeModalOpen: false
},
reducers: {
toggleAffinityModal: state => {
state.isAffinityModalOpen = !state.isAffinityModalOpen
},
toggleRecipeModal: state => {
state.isRecipeModalOpen = !state.isRecipeModalOpen
}
}
})
export const { toggleAffinityModal, toggleRecipeModal } = modalSlice.actions;
export const toggleAffinAsync = isAffinityModalOpen => dispatch => {
dispatch(toggleAffinityModal);
};
// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state) => state.counter.value)`
//useSelector((state) => state.openAffinityModal.isAffinityModalOpen)
export const affinOpen = state => state.openAffinityModal.isAffinityModalOpen;
export default modalSlice.reducer;
You don't need toggleAffinAsync at all. Just use the regular action creator toggleAffinityModal.
affinOpen is a selector function. It is not a value. Right now your Modal is always open because you are passing this function to the isOpen prop and a function is truthy when cast to a boolean.
In order to get the boolean value from the state, you need to call affinOpen with useSelector.
function AffinityModal() {
const dispatch = useDispatch();
const isOpen = useSelector(affinOpen);
return (
<Modal isOpen={isOpen} toggle={() => dispatch(toggleAffinityModal())}>
...
Code Sandbox Demo
Did you try the original version from the reactstrap docs?
const toggle = () => dispatch(toggleAffinAsync());
<Modal isOpen={affinOpen} toggle={toggle} >
...
</Modal>

How can I append a React component to an html element i?

I am using the modal library winbox. It works well if use simple html and javascript. But I can't append a React node to it.
The modal has a html parameter, that accept an html string such as div.innerHTML = <div>hello</div> . The code source is: this.body.innerHTML = html;.
So adding a classic React element makes the modal crash. The only solution I found is to use react-dom's renderToString method: html: renderToString(children). But the component is not dynamic anymore (no state update, etc.).
I also tried to surround React.renderDOM by a div inside the modal and attach the component to it, as the app is attached to index.js's #root div.
html: <div id="modal">
{render(
<div children={content} />,
document.querySelector("#modal")
)},
</div>
My question is thus: how to pass a dynamic React component to the body of this modal?
Here is my code:
import React from "react";
import useModal from "./useModal";
const Counter = () => {
const [count, setCount] = useState(1);
return (
<div>
The count is {count}
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};
export default function App() {
const [open, setOpen] = useState(false);
useModal(open, setOpen, <Counter />);
return (
<div id="#hi">
<button onClick={() => setOpen(!open)}>toggle</button>
</div>
);
}
// useModal
import WinBox from "winbox/src/js/winbox.js";
import "winbox/dist/css/winbox.min.css";
import React from "react";
import { render } from "react-dom";
export default function useModal(open, onToggle, content) {
const modal = open
? new WinBox({
title: "Hello",
max: true,
html: content, // INSERT DYNAMIC COMPONENT HERE
onclose: () => onToggle(false)
})
: null;
return modal;
}
Thank you!
You can use winbox-react package from npm. winbox-react npm link Example code is given below. Youcan use normal jsx as children of the WinboxReact component.
const Hero = () => {
const [show, setShow] = useState(false)
const clickHandeler = () => {
setShow(!show)
}
return (
<div className='text-center'>
{show && (
<WinboxReact
onClose={clickHandeler}
background='linear-gradient(90deg, rgba(49,36,239,1) 0%, rgba(67,0,168,1) 100%)'
><h1>Hello</h1></WinboxReact>
)}
<button onClick={clickHandeler} className='btn btn-custom btn-lg mt-4'>
Show Example
</button>
</div>
)
}
export default Hero

Wrong pass prop in react component

I have simple Reactjs app that includes the Card and Modal components. every Card must have a Modal that when clicking on "Show More" button, open it.
Modal should only show the title on its Card and my problem is passed props to Modal, just send the title of the last Card And not about itself!
In summary, the prop of title received properly in Card component but Card component can't pass title to Modal correctly.
Here is my app in CodeSandBox: Demo
Card Components:
const Card = props => {
const { children, title } = props;
const { isShowModal, setIsShowModal } = useContext(MainContext);
const showModalHandler = () => {
setIsShowModal(true);
};
return (
<div className="card">
<div className="card-header">
<h2>{title}</h2>
</div>
<div className="card-content">{children}</div>
<div className="card-footer">
<button onClick={showModalHandler}>Show More</button>
</div>
{isShowModal && <Modal title={title} />}
</div>
);
};
Modal Component:
const Modal = props => {
const { setIsShowModal } = useContext(MainContext);
const closeModalHandler = () => {
setIsShowModal(false);
};
const { title } = props;
return (
<div className="modal">
<h2>Modal: {title}</h2>
<p>
You cliked on <b>{title}</b> Card
</p>
<hr />
<button onClick={closeModalHandler}>Close</button>
</div>
);
};
Note: I use Context for control open/close modal in isShowModal state and maybe that's the problem?
Just as you thought the problem seems to be the useContext that you are using. So I made a couple of changes to the code, most importantly using useState. I recommend you read the documentation about useContext and when to use it. Here is the updated code:
Card.js
import React, { useState } from "react";
import Modal from "./Modal";
import "./Card.scss";
const Card = props => {
const { children, title } = props;
const [ isShowModal, setIsShowModal ] = useState(false);
return (
<div className="card">
<div className="card-header">
<h2>{title}</h2>
</div>
<div className="card-content">{children}</div>
<div className="card-footer">
<button onClick={() => setIsShowModal(true)}>Show More</button>
</div>
{isShowModal && <Modal setIsShowModal={setIsShowModal} title={title} />}
</div>
);
};
export default Card;
Modal.js
import React from "react";
import "./Modal.scss";
const Modal = props => {
const { title } = props;
return (
<div className="modal">
<h2>Modal: {title}</h2>
<p>
You cliked on <b>{title}</b> Card
</p>
<hr />
<button onClick={() => props.setIsShowModal(false)}>Close</button>
</div>
);
};
export default Modal;
As you can see, Modal.js component doesn't have to be a stateful component. You can pass as a prop the setIsShowModal function from Card.js component. That way you can make the modal a reusable component.

Categories

Resources