react onBlur setState doesn't work (jsbin) - javascript

I've been struggling with debugging react. In jsbin, there's no way I can know what error it is, when I open the console or console of my broswer there's no clear indication of what my error is about.
http://jsbin.com/doletanole/1/edit?html,js,console,output
class HelloWorldComponent extends React.Component {
constructor() {
super()
this.getInput = this.focusHandler.bind(this)
this.state = {hasError:false}
}
focusHandler(e) {
if(e.target.value === ''){
this.setState({hasError:true})
}
}
render() {
return (
<input placeholder="username" type="text" onBlur={this.focusHandler}/>
{this.state.hasError ? <span>Username is required</span> : ''}
);
}
}
Any better way to debug react? I just want to show the error msg if when the user go away of the input base on the state.

Whenever binding the methods in the constructor, try to use the same name to avoid these kind of mistakes, i think you need to reset the state value to false if the username is not blank, Try this Code:
class HelloWorldComponent extends React.Component {
constructor() {
super()
this.focusHandler = this.focusHandler.bind(this)
this.state = {hasError:false}
}
focusHandler(e) {
this.setState({hasError: e.target.value != '' ? false : true});
}
render() {
return (
<div>
<input placeholder="username" type="text" onBlur={this.focusHandler}/>
{this.state.hasError ? <span>Username is required</span> : ''}
</div>
);
}
}
Check working example: http://jsbin.com/cozenariqo/1/edit?html,js,console,output

First of all, you must return only one top level element from a component (or an array, but that's less common). Wrap your rendered output in a single element:
render() {
return (
<div>
<input placeholder="username" type="text" onBlur={this.focusHandler}/>
{this.state.hasError ? <span>Username is required</span> : ''}
</div>
);
}
Secondly, you're not correctly binding the focusHandler event. Change it to onBlur={this.focusHandler.bind(this)}. Suggested reading: React, ES6, Autobinding, and createClass()
The error blocking your code from loading was from the wrapping element. JS Bin does not propagate Babel errors to the user well. I would suggest not using it and set up a local development environment with Babel and Webpack instead.

Related

Browser error says "Cannot add property *, object is not extensible" - Even though property does exist in the class definition

I using React w/Sails.js backend. I think this question really only pertains to React/javascript.
I am getting the following browser console error even though the property being changed does exist in the object:
Cannot add property *, object is not extensible
Below is the class definition and the error occurs in the use of:
onExchangeSelect={selectedExchange => this.setState({selectedExchange})
in the render function below. That is, the browser complains the object is not extensible and gives that lines as the reason (and when I remove the onExchangeSelect function the error goes away).
class ExchangeContainer extends Component {
constructor(props) {
super(props);
this.state = {
exchanges:[
{
name:"binance",
url:"https://bittrex.com"
},
{
name:"bittrex",
url:"https://bittrex.com"
}
],
selectedExchange:null
};
}
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => this.setState({selectedExchange}) }
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
}
My question, what might be causing the error and subsequent failure for the React component to render? Why can't I change that property?
Try to spread/copy the object (otherwise, it is just using same memory location).
onExchangeSelect={selectedExchange =>
this.setState({
selectedExchange: {...selectedExchange}
})
}

Can't edit input in React app

I'm having an issue with editing a value in my React app. I'm aware of how controlled components work, and my problem isn't related to that.
I can paste text into it and see state for the input change, but when I try to change it myself nothing happens. The input resides inside of a TableHeader component.
import React from "react";
import classNames from "classnames";
class TableHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
columnFilterText : "",
filterBoxOpen : false
}
this.toggleSortBox = this.toggleSortBox.bind(this);
this.handleColumnInputChange = this.handleColumnInputChange.bind(this);
}
toggleSortBox(event, value) {
if(event.target === event.currentTarget) {
this.setState({
filterBoxOpen: !this.state.filterBoxOpen
});
}
}
handleColumnInputChange(event) {
console.log(event)
this.setState({
columnFilterText: event.target.value
})
}
render() {
let tableHeaderClasses = classNames({
"sortable" : true,
"filter-box-open" : this.state.filterBoxOpen
});
let sortOptionClasses = classNames({
"sort-option" : true
});
return (
<th className={tableHeaderClasses} onClick={this.toggleSortBox}>
<div className="sort-box">
<div className="sort-option-container">
<div className={sortOptionClasses}>Sort - ascending</div>
</div>
<div className="sort-option-container">
<div className={sortOptionClasses}>Sort - descending</div>
</div>
<hr className="divider" />
<input onChange={this.handleColumnInputChange} type="text" value={this.state.columnFilterText} />
<div className="row">
<button className="six columns">Apply</button>
<button className="six columns">Clear</button>
</div>
</div>
{this.props.label}
</th>
);
}
}
export default TableHeader;
I've checked if it's a css issue, by disabling styles, but the input field is still disabled, so no luck there. Any ideas what might be causing the issue?
I'm an idiot. The reason for this was that I had a keyDown event on the parent component for keyboard navigation, with event.preventDefault(); which of course affected the child component.
Thanks to everyone for contributing and for trying to help!

Passing data from one component to another component

I have started to get my hand-on reactjs. I have three components which are placed in separate files. mainPage.js list.js and tableDisplay.jsare the three different files. I have got few doubt after working with reactjs.
The output from mainPage.js is passed as inputs to the list.js, so here
mainPage.js is parent and list.js is the child(if wrong please correct
me).Likewise, list.js output is passed as input to the tableDisplay.js,my doubt here is, does list.js remain as child component or act as parent component for the list.js.
The output fetched in the list.js is a table from the DB. So Im trying to
display the same table in the tableDisplay.js page, for which Im storing the fetched data to be an object. But Im getting an error Objects are not valid as a React child (found: object with keys {Name, Emp.no, Designation, WorkOff}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of tableDispay. So what does this error mean and how to overcome this error ad display the table in the tableDisplay.js
list.js :
class list extends React.Component {
constructor(props) {
super(props);
this.state = {
content: false,
query : '' ,
};
this.clickEvent= this.clickEvent.bind(this);
}
onChange(e) {
this.setState({ query : e.target.value });
}
clickEvent(event) {
event.preventDefault();
this.setState({
content: true,
});
connectDataBase.query(this.state.query, (err, result) => {
var dataFetched = result;
this.setState({
htmlTable: dataFetched,
});
})
}
render() {
return (
<div>
<div id="listClass">
<label> SQL </label>
<br />
<textarea rows="4" cols="50" onChange={this.onChange.bind(this)} value={this.state.query}> Query </textarea>
</div>
<button onClick={this.clickEvent.bind(this)} > Run </button>
<div id="third" >
{this.state.content && <TableDisplay tableData={this.state.htmlTable}/>}
</div>
</div>
)
}
}
export default list;
tableDisplay.js:
class tableDisplay extends React.Component{
constructor(props) {
super(props);
this.state = {
};
}
render(){
return(
<div id="tableClass" >
<label> Result </label>
<br/>
{this.props.tableData.map((x,y)=>
<table key={y}>
{x}
</table>
)}
{this.props.tableData};
</div>
)
}
}
export default tableDisplay;
I think error is in this line:
{this.props.tableData};
tableData is an array (as you are using map on that), and we can't render any array/object directly inside JSX, remove that line it will work.
Note: You can convert the array to string by using join then you can print the data directly.
Use this:
{this.props.tableData.join(' ')};
I think there is a issue with table rendering also, inside table you are directly putting the {x}, but you need to use some td/tr to render data.
You need to define the htmlTable and content in state variable, initial value of content should be false and once you get the data update the content value to true.
Content of tableData is:
[{Name : 'Sam', Emp.No:'12809', Designation:'Engg.', WorkOff :'UK'}]
Use this to render table:
<table>
{tableData.map((obj,y) => {
return <tr key={obj['Emp.No']}>
{Object.keys(obj).map((x,y) => <td key={y}> {obj[x]} </td>)
</tr>
})}
</table>

How to run script in react

Hey I have a react application and I have a input field that I would like to mask (type="password") while typing the actual password.
I have found a javascript code that does what I need but I cannot seem to make it run with React.
here is the code of the masking function:
http://pastebin.com/vqqaiDuB
but I just cant use it in my view component.
I did try to :
module.exports = MaskedPassword;
but was not able to use the class?!
I am surely missing something big...
how I import it:
import maskedInput from './../../public/MaskedPassword';
this is how my component looks like:
export default class DriversLicense extends Component {
constructor(props){
super(props);
this.state ={};
}
componentDidMount() {
maskedInput(document.getElementById("demo-field"), '\u25CF');
}
render() {
return (
<div>
<form id="demo-form" action="#">
<fieldset>
<input type="password" className="password" id="demo-field" name="pword" onChange={this.demoChange}/>
</fieldset>
</form>
</div>
);
}
}
which gives me:
this.createContextWrapper is not a function
Normally this is the way to call external libraries to make changes to components after render, I would suggest to find the react version of your library because maybe It will have problems with the binding (this). Hope this example helps.
function maskedInput(ele, symbol, obj) {
//this here is not the function
ele.value = this.someOtherFunction()
}
maskedInput.prototype = {
someOtherFunction: function(){
return "Hello"
}
}
function maskedInputGood(ele, symbol, obj) {
const someOtherFunction = function(){
return "Hello"
}
ele.value = someOtherFunction()
}
maskedInput.prototype = {
someOtherFunction: function(){
return "Hello"
}
}
var App = React.createClass({
componentDidMount() {
maskedInputGood(document.getElementById("demo-field"), '\u25CF');
maskedInput(document.getElementById("demo-field"), '\u25CF');
},
render() {
return (
<div>
<form id="demo-form" action="#">
<fieldset>
<input type="password" className="password" id="demo-field" name="pword" onChange={this.demoChange}/>
</fieldset>
</form>
</div>
);
}
})
ReactDOM.render(<App />,document.getElementById('app'))
<html>
<body>
<div id='app'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
</body>
</html>
It seems to me the library is not properly encapsulated, or some similar problem. Have you tried using a React component like this one: https://www.npmjs.com/package/react-password-mask
Since its a React component, it will be more natural to integrate it in your code.
Does your maskedPassword library have any feature that react-password-mask is missing?

I can't get the html output from draft-js?

I've been playing around with draft-js by Facebook, but I can't actually figure out how to get the html output of the editor. The console.log in the following example outputs some _map properties, but they don't seem to contain my actual content?
class ContentContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
editorState: EditorState.createEmpty()
};
this.onChange = (editorState) => this.setState({editorState});
this.createContent = this.createContent.bind(this);
}
createContent() {
console.log(this.state.editorState.getCurrentContent());
}
render() {
const {editorState} = this.state;
const { content } = this.props;
return (
<Template>
<br /><br /><br />
<ContentList content={content} />
<div className="content__editor">
<Editor editorState={editorState} onChange={this.onChange} ref="content"/>
</div>
<FormButton text="Create" onClick={this.createContent.bind(this)} />
</Template>
);
}
}
There is a handy library I used, draft-js-export-html. Import the library and you should be able to see HTML once you invoke the function, stateToHTML:
console.log(stateToHTML(this.state.editorState.getCurrentContent()));
I'm pretty new to React so hopefully this works for you. I looked under the hood of contentState and there is a fair bit going on there that makes using a library to parse out the entities that much more enticing.
The author, sstur, answers a tangentially-related question where I learned about his libraries.
Ewan. I am also playing with Draft.js and came across the same problem. Actually, Victor has provided a great solution.
Here are two libraries that I found. The one mentioned by Victor has more stars on GitHub.
https://github.com/sstur/draft-js-export-html
https://github.com/rkpasia/draft-js-exporter
I just want to add that there is a way to print out the content (in JSON format) without using an external library. It is documented under the Data Conversion session.
Here is how I print out user input using the "convertToRaw" function
console.log(convertToRaw(yourEditorContentState.getCurrentContent()));
Make sure you imported the convertToRaw function from Draft.js by writing:
import { convertFromRaw, convertToRaw } from 'draft-js';
Here is a great blog written by rajaraodv named How Draft.js Represents Rich Text Data. It explained data conversion in detail.
There is readonly attribute to generate just HTML:
<Editor editorState={editorState} readOnly/>
If not willing to add another library to your code, #farincz's approach can work well.
<Editor editorState={this.state.editorState} readOnly/>
The editor state can be directly stored in your storage layer and when you are rendering it to the DOM it is easily available and can help in editing.
By clicking on the text you can make it editable, or bind that click with an edit button. You cannot directly bind click to 'Editor' component, but you can have it on the wrapper containing the 'Editor'.
<div className="editor" onClick={this.editContent.bind(this)}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
handleKeyCommand={this.handleKeyCommand}
readOnly={this.state.edit}
/>
</div>
Just add 'edit' to your state as true, making sure that readOnly is true (you can make the name 'edit' of the state more obvious, if it is confusing).
this.state = {
editorState: EditorState.createEmpty(),
edit: true
};
Finally change the value of 'edit' to false on click
editContent() {
this.setState({
edit: false
})
}
To expand on the libraries shared above, here's another good one : draftjs-to-html
It converts raw editor state (JSON object) into plain HTML.
import draftToHtml from 'draftjs-to-html';
import {convertToRaw} from "draft-js";
const rawContentState = convertToRaw(editorState.getCurrentContent());
const markup = draftToHtml(rawContentState);
The most suitable package to convert to HTML and from HTML is draft-convert
However, you should be aware to use the Advanced usage to be able to convert links and to customize the convert process:
const htmlResult = convertToHTML({
entityToHTML: (entity, originalText) => {
if (entity.type === 'LINK') {
return <a href={entity.data.url}>{originalText}</a>;
}
return originalText;
}
})(editorState.getCurrentContent());
const contentState = convertFromHTML({
htmlToEntity: (nodeName, node, createEntity): any | void => {
if (nodeName === 'a') {
return createEntity(
'LINK',
'MUTABLE',
{url: node.href}
)
}
}
})(htmlInput);

Categories