display image in draftjs editor - javascript

I am using draftjs editor. I could render the content but I could not show images. How can i show image when using draftjs? Right now the url is only shown instead of images.The server sends the data as following
img src="http://image_url" style="argin:30px auto; max-width: 350px;"
Sorry i could not use img tag html way so excluded the tag syntax.
function findImageEntities(contentBlock, callback, contentState) {
contentBlock.findEntityRanges(character => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
contentState.getEntity(entityKey).getType() === "IMAGE"
);
}, callback);
}
const Image = props => {
const { height, src, width } = props.contentState
.getEntity(props.entityKey)
.getData();
return <img src={src} height={height} width={width} />;
};
class AdminEditor extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
editorContent: undefined,
contentState: "",
touched: false
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.htmlMarkup !== this.props.htmlMarkup) {
const content = nextProps.htmlMarkup;
const blocksFromHTML = convertFromHTML(content);
const plainState = ContentState.createFromBlockArray(
blocksFromHTML.contentBlocks,
blocksFromHTML.entityMap
);
this.setState(state => ({
editorState: EditorState.createWithContent(plainState, decorator)
}));
}
}
onEditorStateChange = editorState => {
this.setState({
editorState
});
};
onEditorChange = editorContent => {
this.setState({
editorContent
});
};
handleChange = event => {
this.props.setEditorState(
this.state.editorState.getCurrentContent().hasText() && this.state.touched
);
};
render() {
const { editorState } = this.state;
const { stateOfEditor } = this.props;
return (
<div>
<Editor
tabIndex={0}
editorState={editorState}
initialContentState={this.props.htmlMarkup}
toolbarClassName="home-toolbar"
onEditorStateChange={this.onEditorStateChange}
toolbar={{
history: { inDropdown: true },
inline: { inDropdown: false },
link: { showOpenOptionOnHover: true },
image: {
uploadCallback: this.imageUploadCallBack,
defaultSize: { height: "auto", width: "50%" }
}
}}
onContentStateChange={this.onEditorChange}
onChange={this.handleChange}
/>
</div>
);
}
}
export default AdminEditor;
exact copy of decorator is in top of the findImageEntities which i haven't pasted just to reduce the number of lines of code

I saw the props onEditorStateChange={this.onEditorStateChange} . I doubt you're using the draft-js-wysiwyg not draft-js.
In draft-js-wysiwyg , u can visit here :
https://github.com/jpuri/react-draft-wysiwyg/issues/589

Related

React Input onSelect Component shows Previous Selection

I've create an autocomplete search input bar using AWS Cloudscape. When I attempt to use the onSelect to save state, it does not save state. When I select a second item from the search bar, the first item then shows up. I assume this is a state async issue. I need the most recent selection, how do I get that?
import React from "react";
import Regions from "./trailforks_regions.json"
import RegionNames from "./region_names.json"
import * as dfd from "danfojs";
import { Autosuggest } from '#cloudscape-design/components';
export class AutoCompleteInputComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
df: new dfd.DataFrame(Regions),
value: null,
final_value: "",
options: [],
status: "loading",
regionContext: [],
uri_value: "",
loaded: false
};
}
lookupRegionUriName() {
console.log("Checking for uri region name on:" + this.state.final_value)
let region_name_split = this.state.final_value.split(",")[0]
let query_df = this.state.df.query(this.state.df["name"].eq(region_name_split))
let uri_name = query_df["region_uri_name"].values
console.log("found:" + uri_name)
return uri_name
}
handleChange = event => {
this.setState({ value: event.detail.value });
};
handleSelect = event => {
console.log(event) // This shows the correct data! But the set state does not set this data.
this.setState({ final_value: event.detail.value });
this.lookupRegionUriName(this.state.final_value)
};
handleLoadItems = ({ detail: { filteringText, firstPage, samePage } }) => {
this.filteringText = filteringText;
var my_options = RegionNames.filter(regions => regions.toLowerCase().startsWith(this.filteringText.toLowerCase()))
var region_values = []
for (var i = 0; i <= my_options.length; i++) {
region_values.push({ value: my_options[i] })
}
this.setState({
options: region_values.slice(0, 25),
status: 'loading',
});
};
enteredTextLabel = value => `Use: "${value}"`;
renderInput() {
if (this.state.df != null) {
const { status, value, options, final_value, uri_value } = this.state;
return (
<>
<Autosuggest
onChange={this.handleChange}
onSelect={this.handleSelect}
onLoadItems={this.handleLoadItems}
value={value}
options={options}
enteredTextLabel={this.enteredTextLabel}
ariaLabel="Autosuggest example with suggestions"
placeholder="Enter Trailforks Region Name"
empty="No matches found"
finishedText={this.filteringText ? `End of "${this.filteringText}" results` : 'End of all results'}
//status={status}
loadingText="searching"
filteringType="manual"
/>
</>
)
} else {
return (<></>)
}
}
render() {
return (
<>
{this.renderInput()}
</>
)
}
}
Figured it out. It was a state issue, here are the changes for future people:
import React from "react";
import Regions from "./regions.json"
import RegionNames from "./region_names.json"
import * as dfd from "danfojs";
import { Autosuggest } from '#cloudscape-design/components';
export class AutoCompleteInputComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
df: new dfd.DataFrame(Regions),
value: null,
final_value: "",
options: [],
status: "loading",
regionContext: [],
uri_value: "",
loaded: false
};
}
updateRegion(state_object) {
this.lookupRegionUriName()
return state_object.final_value
}
lookupRegionUriName() {
console.log("Checking for uri region name on:" + this.state.final_value)
let region_name_split = this.state.final_value.split(",")[0]
let query_df = this.state.df.query(this.state.df["name"].eq(region_name_split))
let uri_name = query_df["region_uri_name"].values
this.setState({uri_value: uri_name})
console.log("found:" + uri_name)
}
handleChange = event => {
this.setState({ value: event.detail.value });
};
handleSelect = event => {
console.log(event) // This shows the correct data! But the set state does not set this data.
this.setState({ final_value: event.detail.value });
this.lookupRegionUriName(this.state.final_value)
};
handleLoadItems = ({ detail: { filteringText, firstPage, samePage } }) => {
this.filteringText = filteringText;
var my_options = RegionNames.filter(regions => regions.toLowerCase().startsWith(this.filteringText.toLowerCase()))
var region_values = []
for (var i = 0; i <= my_options.length; i++) {
region_values.push({ value: my_options[i] })
}
this.setState({
options: region_values.slice(0, 25),
status: 'loading',
});
};
enteredTextLabel = value => `Use: "${value}"`;
renderInput() {
if (this.state.df != null) {
const { status, value, options, final_value, uri_value } = this.state;
return (
<>
<Autosuggest
onChange={this.handleChange}
onSelect={event => {this.setState({final_value: event.detail.value}, () => {this.updateRegion(this.state)})}}
//onSelect={this.handleSelect}
onLoadItems={this.handleLoadItems}
value={value}
options={options}
enteredTextLabel={this.enteredTextLabel}
ariaLabel="Autosuggest example with suggestions"
placeholder="Enter Trailforks Region Name"
empty="No matches found"
finishedText={this.filteringText ? `End of "${this.filteringText}" results` : 'End of all results'}
status={status}
loadingText="searching"
filteringType="manual"
/>
</>
)
} else {
return (<></>)
}
}
render() {
return (
<>
{this.renderInput()}
</>
)
}
}

setState is not updating or re rendering DOM or component

I cant figure out why my Login component is not re-rendering what is on the page. The state is changed to loginShow after I click on a "Log In" button on top of my form.
import React from 'react';
import SignUp from '../SignUp';
import Cards from '../Articles/Cards';
import Login from '../LogIn';
export default class Gecko extends React.Component {
constructor(props) {
super(props);
this.state = { requestedPostsThatWeGotFromGecko: null, }
this.clickMe = this.clickMe.bind(this)
this.state = {
loginStatus: "loginHide",
authType: "signup"
};
this.loginClose = this.loginClose.bind(this);
this.loginOpen = this.loginOpen.bind(this);
}
loginClose(e) {
e.stopPropagation();
this.setState({
loginStatus: "loginHide"
});
}
loginOpen() {
this.setState({
loginStatus: "loginShow"
});
}
clickMe = () => {
const {requestedPostsThatWeGotFromGecko} = this.state;
this.setState({ requestedPostsThatWeGotFromGecko: !requestedPostsThatWeGotFromGecko })
}
/* mainLogIn = () => {
const {loginStatus} = this.state;
this.setState({ loginStatus: 'loginHide' })
} */
render() {
const { requestedPostsThatWeGotFromGecko } = this.state;
const { loginStatus } = this.state;
console.log(loginStatus);
// const { authType } = this.state;
// if (loginStatus === "loginHide") return <SignUp login={() => this.clickMe()} />
// if (requestedPostsThatWeGotFromGecko.props === true) return <Cards />
if (loginStatus !== "loginShow") return (
<div className="gecko">
{requestedPostsThatWeGotFromGecko ? (
<Cards />
): (
<SignUp login={() => this.clickMe()} />
)
}
</div>
);
if (loginStatus === "loginShow") return <Login />
}
}
I believe the issue lies where I am trying to set what is being displayed using the conditional operator at the end of the code above. I have included where I am setting the state and props from my other components in the code below.
const onClick = () => {
this.props.login();
console.log('rich');
}
const mainLogIn = () => {
this.setState({
loginStatus: "loginShow"
});
console.log('rich1');
console.log(this.state);
}
const onClick = () => {
this.props.login();
console.log('rich');
}
const mainSignUp = () => {
this.props.signup();
this.setState({
loginStatus: "loginHide"
});
console.log('rich2');
}

How to fix onClick element. ReactJS

I new in ReactJS and i have one few question. I defined function showModal and but console.log() and
this.setState({show:!this.state.show});.
And after that I applied
this function onClick event for div element inside map function.
1st question: When I click on div element showModal work but in console I don't see my console.log.
2nd question: I want to make when you click on one div element it must add/show few new div elements but only for one div element (on which I clicked). But now when I click on one div element it add/show new elements for all div elements which had this showModal function.
How can i fix this
import React, { Component } from "react";
import Modal from '../components/modal/form'
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'URL which work correct';
class Actions extends React.PureComponent{
constructor(){
super();
this.state = {
result:null,
show:false,
helpId:null
};
this.setSearchTopStories = this.setSearchTopStories.bind(this);
this.showModal = this.showModal.bind(this);
this.handleClickFromParent = this.handleClickFromParent.bind(this);
this.onClose = this.onClose.bind(this);
}
onClose = e => {
this.setState({ show: false});
}
handleClickFromParent = e => {
this.setState({show: !this.state.show});
}
showModal = e => {
console.log('BABE');
this.setState({show: !this.state.show})
};
setSearchTopStories(result) {
this.setState({ result });
};
componentDidMount() {
fetch(`${PATH_BASE}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
.catch(error => error);
};
render(){
const { searchTerm, result } = this.state;
console.log('* Actions Pure*');
console.log(result);
console.log('=');
return(
<div>
{
(result !== null) ?
result.map(
(item,index) =>
<div>
<div onClick={()=>this.showModal()}>{item.name}</div>
<Modal
id = {index}
handleClickFromParent {this.handleClickFromParent}
item = {[item]}
show = {this.state.show}
onClose = {this.onClose}>
YOLO
</Modal>
</div>
)
: null
}
</div>
)
}
}
export default Actions;
While selecting u can pass the item on method, and on click u can set the item value. Please check the below code.
Demo:
https://codesandbox.io/s/stackoverflowmodal-19i36
this.state = {
result: null,
show: false,
selectedItem:null,
helpId: null
};
//
showModal = (selectedItem) => {
this.setState({
show: !this.state.show,
selectedItem
});
};
//
class Actions extends React.PureComponent {
constructor() {
super();
this.state = {
result: null,
show: false,
selectedItem: null,
helpId: null
};
this.setSearchTopStories = this.setSearchTopStories.bind(this);
this.showModal = this.showModal.bind(this);
this.handleClickFromParent = this.handleClickFromParent.bind(this);
this.onClose = this.onClose.bind(this);
}
onClose = e => {
this.setState({
show: false
});
};
handleClickFromParent = e => {
this.setState({
show: !this.state.show
});
};
showModal = selectedItem => {
this.setState({
show: !this.state.show,
selectedItem
});
};
setSearchTopStories(result) {
this.setState({ result });
}
componentDidMount() {
fetch(`${PATH_BASE}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
.catch(error => error);
}
render() {
const { searchTerm, result, selectedItem } = this.state;
return (
<div>
{result && result.length
? result.map((item, index) => (
<div>
<div onClick={() => this.showModal(item)}>{item.name}</div>
</div>
))
: null}
{selectedItem && (
<Modal
id={index}
handleClickFromParent={this.handleClickFromParent}
item={[selectedItem]}
show={this.state.show}
onClose={this.onClose}
>
YOLO
</Modal>
)}
</div>
);
}
}
export default Actions;

How can I map elements which Ive got from database?

I want to ask you how can I map elements from database. I basically want to make something like: (name = {name}, isOn = {isOn}).
And the code of the component which should get assigned data:
const Islbutton = props => {
const [name, setName] = useState('');
const [isOn, setIsOn] = useState(true);
// some functions
return (
<div>
<img src = {isOn ? islon : isloff} alt= "" onClick={() =>toggleImage()}/>
</div>
);
}
You need to use useEffect to handle external property change in a function component. See the example below,
const { Component, useState, useEffect } = React;
const { render } = ReactDOM;
const Islbutton = props => {
const { toggleLight } = props;
const [name, setName] = useState('');
const [isOn, setIsOn] = useState(false);
useEffect(() => {
setName(props.naem);
setIsOn(props.isOn);
});
const islon =
"https://cdg-webhosting.com/wp-content/uploads/2011/02/help-hint-icon.png";
const isloff =
"https://i.ya-webdesign.com/images/light-bulb-on-off-png-16.vnd";
// some functions
return (
<img src={isOn ? islon : isloff} alt={name} onClick={toggleLight} />
);
};
class App extends Component {
state = {
lights: [
{ name: "light1", isOn: true },
{ name: "light2", isOn: false },
{ name: "light3", isOn: false },
{ name: "light4", isOn: true },
{ name: "light5", isOn: true }
]
};
constructor(props) {
super(props);
}
toggleLight = light => {
return () => {
this.setState(prevState => ({
lights: prevState.lights.map(_light => {
return _light === light
? {
...light,
isOn: !light.isOn
}
: _light;
})
}));
};
};
render() {
const { lights } = this.state;
return (
<div>
{lights.map(light => (
<Islbutton
key={light.name}
name={light.name}
isOn={light.isOn}
toggleLight={this.toggleLight(light)}
/>
))}
</div>
);
}
}
render(<App />, document.querySelector("#root"));
img {
width: 50px;
height: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

ReactJS: Adding multiple input fields of different types on click

I've created a React app for a school project that can add multiple types of input fields to a view by clicking a button (sort of like Wordpress Gutenberg).
Currently, I can add one of each type of item onto the view. However, if I click the button again, it erases the current text that was added. I'd like the ability to click the button to add as many fields as I'd like on click.
Also, the items are only added into the view in the order they were created meaning, even if I choose photo first and I click headline after, it (headline) will appear at the top of the list above the initial item.
I've had a look at these solutions (which were pretty good) but they didn't provide what I need.
Dynamically adding Input form field issue reactjs
and "update delete list elements using unique key": https://www.youtube.com/watch?v=tJYBMSuOX3s
which was closer to what I needed to do.
Apologies in advance for the length of the code,(there are two other related components for text input and an editform). I'm sure there is a much more simple way to do this. I haven't been able to find an npm package or solution to this specific problem online and am open to a simpler solution.
Edit.jsx
export default class Edit extends React.Component {
state = {
texts: {
hl: '',
shl: '',
txt: '',
photo: []
},
coms: {
hl: false,
shl: false,
txt: false,
photo: null
},
labels: {
// Replace with icons
hl: 'Headline',
shl: 'Sub',
txt: 'Text Area',
photo: 'Photo'
},
selectedItem: '',
}
componentDidMount() {
const saveData = localStorage.getItem('saveData') === 'true';
const user = saveData ? localStorage.getItem('user') : '';
this.setState({ user, saveData });
}
createPage = async () => {
await this.props.postPage(this.state.texts)
}
// add options
addOptions = (item) => {
const { coms } = this.state
coms[item] = !coms[item]
this.setState({ coms: coms })
}
// ADD TEXT
addTxt = () => {
this.setState({ texts: [...this.state.texts, ""] })
}
enableAllButtons = () => {
this.setState({ selectedItem: '' })
}
handleChange = (e, index) => {
this.state.texts[index] = e.target.value
//set the changed state.
this.setState({ texts: this.state.texts })
}
setDisable = (selectedItem) => {
this.setState({ selectedItem })
}
handleRemove = () => {
// this.state.texts.splice(index, 1)
this.setState({ texts: this.state.texts })
}
handleSubmit = (e) => {
console.log(this.state, 'all text')
}
handleChange = (e, item) => {
let { texts } = this.state
texts[item] = e.target.value
//set the changed state.
this.setState({ texts })
console.log(texts)
}
render() {
const { coms, labels, selectedItem, texts } = this.state
let buttons = Object.keys(coms)
let showItems = Object.keys(coms).filter(key => coms[key] === true)
return (
<div>
<InnerHeader />
{/* Make a route for edit here */}
<Route path='/edit/form' render={() => (
<EditForm
texts={texts}
coms={coms}
labels={labels}
addOptions={this.addOptions}
setDisable={this.setDisable}
selectedItem={selectedItem}
showItems={showItems}
handleChange={this.handleChange}
enableAllButtons={this.enableAllButtons}
/>
)} />
{/* Make route for preview */}
<Route path='/edit/preview' render={(props) => (
<Preview
{...props}
createPage={this.createPage}
/>
)}
/>
</div>
)
}
}
AddText.jsx:
export default class AddText extends Component {
state = {
}
// ADD TEXT
addTxt(item) {
const {
addOptions } = this.props
addOptions(item)
}
render() {
const { coms, labels } = this.props
const { selectedItem } = this.props
let buttons = Object.keys(coms)
console.log('here', selectedItem)
return (
<div>
<Card>
<Card.Body>
{
buttons.map((item, index) => <button
value={(selectedItem === "") ? false : (selectedItem === item) ? false : true} key={index} onClick={() => this.addTxt(item)}>
{labels[item]}
</button>
)
}
</Card.Body>
</Card>
</div>
)
}
}
EditForm.jsx
export default function EditForm(props) {
return (
<div>
<div className='some-page-wrapper-sm'>
<div className="dash-card-sm">
<button><Link to={{
pathname: '/edit/preview',
item: props.texts
}}>preview</Link></button>
<br />
<br />
<AddText
coms={props.coms}
labels={props.labels}
addOptions={props.addOptions}
setDisable={props.setDisable}
selectedItem={props.selectedItem}
/>
<div>
{
props.showItems.map((item, index) => {
return (
<InputFieldComponent
// setDisable={props.setDisable}
onChangeText={(e) => props.handleChange(e, item)}
enableAllButtons={props.enableAllButtons}
key={index}
item={item}
labels={props.labels}
texts={props.texts}
/>
)
})
}
</div>
</div>
</div>
</div>
)
}
InputFieldComponent.jsx
export default class InputFieldComponent extends React.Component {
setWrapperRef = (node) => {
this.wrapperRef = node;
}
render() {
const { labels, item, onChangeText, texts } = this.props
return (
<div>
<textarea
className="txt-box"
ref={this.setWrapperRef}
onChange={onChangeText}
placeholder={labels[item]}
value={texts[item]} />
</div>
)
}
}

Categories