ReactJS can not disable a dynamically created button - javascript

Using ReactJS I create a form dynamically using custom JSON data.
render() {
return (
<div>
<ShowForm src={this.state.data} />
</div>
);
}
With componentDidUpdate I would like to disable all submit buttons. While the label of the buttons is changed successfully, I constantly fail to disable the button.
componentDidUpdate() {
var submitButtons = document.querySelectorAll('button[type=submit]');
submitButtons.forEach(btn => {
btn.innerText = 'PREVIEW';
btn.disabled = true;
});
}
The chrome inspector returns the following HTML code for the buttons. Also, the form objects are using Bootstrap for the CSS styling.
<button lang="en" class="btn btn-warning btn-md" type="submit" name="data[Draft]" ref="button">PREVIEW</button>
What prevents JS to apply the disable action?

Web components is the preferred solutions
https://reactjs.org/docs/web-components.html
Alternatively, you can manipulate the JSON data before they are rendered from react-dom.
Another solution I found is simply set pointer-events: none; style.
componentDidUpdate() {
var submitButtons = document.querySelectorAll('button[type=submit]');
submitButtons.forEach(btn => {
btn.setAttribute('style', 'pointer-events: none;');
});
}

Related

disabled={true} HTML button attribute does not work right in JavaScript + React

Having issues with disabled={true} HTML button. App is in JavaScript + React. I set button initial value disabled={true} .For example purposes I will call it id="button1". Once I click another button let's say id=button2, I re-enable my button1 with code document.getElementById('button1').disabled=false;. Button re-enables but once clicked it has no functionality, it looks like it is still disabled. What am I doing wrong ?
OK here is my simplified code:
function App() {
const approve = () => {
console.log('test');
};
const filterWeek2 = () => {
document.getElementById('approve').removeAttribute("disabled");
};
return (
<div className="App">
<nav>
<ul className="nav-area">
<li><button id="Week2" onClick={filterWeek2}>WEEK 2</button></li>
<li><button id="approve" onClick={approve} disabled="disabled">APPROVE</button></li>
</ul>
</nav>
</div>
);
}
export default withAuthenticator(App);
The disabled is a boolean attribute, Its presence on an HTML elements disables the element. If it is present on the element, it will disable the HTML element, doesn't matter what value it has.
You have to remove the attribute using removeAttribute to make it editable
const disabled = document.querySelector(".disabled");
const normal = document.querySelector(".normal");
normal.addEventListener("click", () => {
if (disabled.hasAttribute("disabled")) disabled.removeAttribute("disabled");
else disabled.setAttribute("disabled", true);
})
<button disabled class="disabled">button</button>
<button class="normal">toggle</button>
Since you are using React, then you can toggle disabled using state. DEMO
disabled={active}
If active is true then the HTML element is disable else enabled.

React jsx version of html (using different tags, but same attribute and logic) isn't triggering jquery on('change') method

I'm migrating jQuery/javascript code into React piecemeal and for some reason I can't activate the "change" event when a value is changed React/Redux as it it's down in html. Does anyone know why this might be the case that the "change" event isn't being fired?
The original html code:
<div class="form-group row" style="margin-top: 10px!important;" >
<div class="col-md-2"><lang data-key="Resolution" /></div>
<div class="col-md-4">
<select class="form-control" id="screensize" style="width:100%;">
<option value="1920x1080" >1920 x 1080</option>
<option value="1680x1050">1680 x 1050</option>
<option value="1440x900">1440 x 900</option>
<option value="1280x800">1280 x 800</option>
<option value="1024x768">1024 x 768</option>
<option value="800x640" selected>800 x 640</option>
</select>
</div>
</div>
My react version of this.
import React from 'react';
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
...
settings: state.settings,
};
};
class DomStateWrapper extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
...
<input
id="screensize"
value={this.props.settings.resolution} //** I have confirmed that this attribute gets its value from the redux store successfully
/>
...
</div>
)
}
}
export default connect(mapStateToProps)(DomStateWrapper);
The jQuery code I'm using to consume the change
$(document).on("change", "#screensize", function(e) {
var sizes = $(this)
.val()
.split("x");
if (showWin != null) showWin.resizeTo(sizes[0], sizes[1]); // resize the popup
});
Overall, the original html version of this code which uses , and sets its value and triggers the change method in the jquery code, but when I do it in react/redux, using , that .on() method is never triggered. I also used this website as reference for the "change" event.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event
So getting a lot of flak for this question for having jQuery in React. I don't like it either, but it's not by choice when the task is to migrate from jQuery to React. Anyways, for anyone interested, the reason why this was happening is because it seems that the jQuery onChange event is being called either before or simultaneously with redux changing state. So to keep the jQuery change method while also updating state, the quick fix implemented was adding the action to the window:
window.reduxStore = store;
window.reduxActions = {resizeProjector}
So giving jQuery access to the redux action function resizeProjector, allowed us to update the jQuery code with:
$(document).on('change', '#screensize', function(e) {
var sizes = $(this)
.val()
.split('x');
reduxStore.dispatch(
reduxActions.resizeProjector({
width: sizes[0],
height: sizes[1],
}),
);
});
You should not use jQuery in your ReactJS app.
Do this instead:
<input
onChange={resizeWin}
value={this.props.settings.resolution} //** I have confirmed that this attribute gets its value from the redux store successfully
/>
const resizeWin = e => {
var sizes = e.target.value.split("x");
if (showWin != null) showWin.resizeTo(sizes[0], sizes[1]); // resize the popup
}

How can I automatically open file selection rather than pressing the upload button? [duplicate]

I have a hidden file input element. Is it possible to trigger its select file dialog box from a button's click event?
If you're looking to have your own button to upload a file instead of using <input type="file" />, you can do something like:
<input id="myInput" type="file" style="visibility:hidden" />
<input type="button" value="Show Dialog" onclick="$('#myInput').click();" />
Note that I used visibility: hidden, instead of display: none. You cannot call the click event on a non-displayed file input.
Most answers here are lacking a useful information:
Yes, you can programmatically click the input element using jQuery/JavaScript, but only if you do it in an event handler belonging to an event THAT WAS STARTED BY THE USER!
So, for example, nothing will happen if you, the script, programmatically click the button in an ajax callback, but if you put the same line of code in an event handler that was raised by the user, it will work.
P.S. The debugger; keyword disrupts the browse window if it is before the programmatical click ...at least in chrome 33...
Just for the record, there is an alternative solution that does not require javascript. It is a bit of a hack, exploiting the fact that clicking on a label sets the focus on the associated input.
You need a <label> with a proper for attribute (points to the input), optionnaly styled like a button (with bootstrap, use btn btn-default). When the user clicks the label, the dialog opens, example :
<!-- optionnal, to add a bit of style -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
<!-- minimal setup -->
<label for="exampleInput" class="btn btn-default">
Click me
</label>
<input type="file" id="exampleInput" style="display: none" />
I'm not sure how browsers handle clicks on type="file" elements (security concerns and all), but this should work:
$('input[type="file"]').click();
I've tested this JSFiddle in Chrome, Firefox and Opera and they all show the file browse dialog.
Nowadays a hybrid solution like this can have the best experience,
let fileHandle;
async function fileOpen() {
[fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
console.log(await file.text());
}
// The advantage of this is fileHandle can be used to save to
// the opened file itself later, read more on this in https://web.dev/file-system-access/
// in April 2021, window.showOpenFilePicker still not support in Safari
// so one should have this around also
function legacyFileOpen() {
var input = document.createElement('input');
input.type = 'file';
input.onchange = function () {
input.files[0].arrayBuffer().then(function (arrayBuffer) {
console.log(new TextDecoder().decode(arrayBuffer));
});
}
input.click();
}
I wrap the input[type=file] in a label tag, then style the label to your liking, and hide the input.
<label class="btn btn-default fileLabel" data-toggle="tooltip" data-placement="top" title="Upload">
<input type="file">
<span><i class="fa fa-upload"></i></span>
</label>
<style>
.fileLabel input[type="file"] {
position: fixed;
top: -1000px;
}
</style>
Purely CSS Solution.
Natively the only way is by creating an <input type="file"> element and then simulating a click, unfortunately.
There's a tiny plugin (shameless plug) which will take the pain away of having to do this all the time: file-dialog
fileDialog()
.then(file => {
const data = new FormData()
data.append('file', file[0])
data.append('imageName', 'flower')
// Post to server
fetch('/uploadImage', {
method: 'POST',
body: data
})
})
The best solution, works in all browsers.. even on mobile.
<div class="btn" id="s_photo">Upload</div>
<input type="file" name="s_file" id="s_file" style="opacity: 0;">';
<!--jquery-->
<script>
$("#s_photo").click(function() {
$("#s_file").trigger("click");
});
</script>
Hiding the input file type causes problems with browsers, opacity is the best solution because it isn't hiding, just not showing. :)
There is no cross browser way of doing it, for security reasons. What people usually do is overlay the input file over something else and set it's visibility to hidden so it gets triggered on it's own. More info here.
Make sure you are using binding to get component props in REACT
class FileUploader extends Component {
constructor (props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
onChange=(e,props)=>{
const files = e.target.files;
const selectedFile = files[0];
ProcessFileUpload(selectedFile,props.ProgressCallBack,props.ErrorCallBack,props.CompleatedCallBack,props.BaseURL,props.Location,props.FilesAllowed);
}
handleClick = () => {
this.refs.fileUploader.click();
}
render()
{
return(
<div>
<button type="button" onClick={this.handleClick}>Select File</button>
<input type='file' onChange={(e)=>this.onChange(e,this.props)} ref="fileUploader" style={{display:"none"}} />
</div>)
}
}
browse file programatically
function browseFile(accept) {
const promise = resolvingPromise();
const input = document.createElement('input');
input.type = "file";
input.accept = accept;
input.onchange = function (e) {
const files = e.target.files;
promise.resolve(files);
}
setTimeout(function () {
click(input);
}, 0);
return promise;
}
function click(node) {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
const evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
node.dispatchEvent(evt);
}
}
Using jQuery you can call click() to simulate a click.
This worked for me:
$('#fileInput').val('');
For those who want the same but are using React
openFileInput = () => {
this.fileInput.click()
}
<a href="#" onClick={this.openFileInput}>
<p>Carregue sua foto de perfil</p>
<img src={img} />
</a>
<input style={{display:'none'}} ref={(input) => { this.fileInput = input; }} type="file"/>
<div id="uploadButton">UPLOAD</div>
<form action="[FILE_HANDLER_URL]" style="display:none">
<input id="myInput" type="file" />
</form>
<script>
const uploadButton = document.getElementById('uploadButton');
const myInput = document.getElementById('myInput');
uploadButton.addEventListener('click', () => {
myInput.click();
});
</script>

Add & Remove CSS classes with React

I am new to React. I have a few buttons in a button group:
<div className="btn-group">
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type1")} >Button1</button>
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type2")} >Button2</button>
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type3")} >Button3</button>
</div>
Whenever the user clicks on one of the buttons, this button should become the active, selected one. I found out that I need to add the CSS class active to the corresponding button, but I am not sure how to implement this.
I thought about this for a bit. I have a changeDataType function connected to my buttons, in which I do some other stuff. Would I then, in there, somehow manipulate the CSS?
So I guess my questions are first, how to target the button I need to target, and second, how I could change that button's CSS with React.
In react when state changes react re-renders. In your case if you want to change the way something looks then you probably want to force another render. What you can do is have the className be part of state and then update the state when you want, causing the component to re-render with the new className. For example:
constructor() {
super();
this.state = {
className: 'btn'
}
}
render () {
return (
<Button className={this.state.className}>Click me</Button>
)
}
Since the className is bound to state updating state will cause the button to render again with the new className. This can be done like this:
updateClass() {
let className = this.state.className;
className = className + ' ' + 'btn-primary'
this.setState({className})
}
This is an example of the function you can call on the click of a button and update the className for the button.
There's a nice utility you can use for classname logic + joining classNames together
https://github.com/JedWatson/classnames
Based on setting React state for active you could do something like the following. You can get as complex as you need to with the logic. If the logic result is falsy, that key won't be included in the output.
var classNames = require('classnames');
var Button = React.createClass({
// ...
render () {
var btnClass = classNames({
btn: true,
'btn-active': this.state.isActive
});
return <button className={btnClass}>{this.props.label}</button>;
}
});
Here how I did this:
//ChatRoomPage component
function ChatRoomPage() {
const [showActionDropdown, setShowActionDropdown] = useState('hide');
function showActionDropdownHandler(){
console.log("clicked")
if(showActionDropdown=='hide')
setShowActionDropdown('show')
else
setShowActionDropdown('hide')
}
return (
<div>
<button onClick={ () => showActionDropdownHandler() } className="btn " type="button">Actions</button>
<div className={`action_menu ${showActionDropdown}`}>
...
</div>
</div>
);
}
export default ChatRoomPage;

Getting HTML element by Id and switch its CSS through React

I have some files that load into my react components, which have HTML code.
As it is now, the pure HTML code renders just fine, however there is some 'hidden' code that appears whenever you click certain buttons in other parts of the application or on the text above (think of it like panels that expand when you click on it).
The HTML is hidden just using the good old <div id="someId" style="display:none">.
Anyway I am trying to get the correct panel to expand upon clicking their respective buttons.
So in theory, what I need to do is find the element by id, and switch it's display to block whenever needed, and then switch it back when the parent is clicked again.
Unfortunately I have no idea how to do this and so far have gotten nowhere. As it is now, I have access to the component's ids. What I want to know is how in the world can I access that and get to change whatever is rendering?
Create your function:
function element_do(my_element, what_to_do) {
document.getElementById(my_element).style.display = what_to_do;
}
and latter in code you can append wherever you want through javascript onclick or not depends what do you need:
element_do("someId", "none"); // to hide
element_do("someId", "block"); // to show
or create yourself toggle:
function toggle_element(element_id) {
var element = document.getElementById(element_id);
element.style.display = (element.style.display != 'none' ? 'none' : 'block' );
}
// and you can just call it
<button onClick="toggle_element('some_id')">toggle some element</button>
The react way to do it would be with states. Assuming that you know how to use states I'd do something like this:
class ShowHide extends React.Component {
constructor() {
super();
this.state = {myState: true};
this.onClick = this.onClick.bind(this)
}
onClick() {
this.setState({myState: !this.state.myState}) //set the opposite of true/false
}
render() {
const style = {myState ? "display: none" : "display:block"} //if myState is true/false it will set the style
return (<div>
<button onClick={this.onClick}>Click me to hide/show me </button>
<div id="myDiv" style={style}> Here you will hide/show div on click </div>
</div>)
}
}

Categories

Resources