Image larger than it's container in comments section - javascript

usually in a blog website user can comment with text or an image and so on ,and in my case when user comment with an image that have a dimension larger than the container the view affected as below :
and actually i'am storing the images in Firebase storage and i can't control those images .
this is the code of this page
Article.js :
import React from 'react';
import './Articles.css' ;
import {Link } from 'react-router-dom';
import ImageUploader from 'react-images-upload';
import { Editor } from '#tinymce/tinymce-react';
import {storage} from '../firebase/firebase';
class Articles extends React.Component{
constructor(props){
super(props);
this.state={
title:this.props.location.title,
comment:'',
postid:this.props.location.postid,
arraycomments:this.props.location.arraycomments,
postcontent:this.props.location.postcontent,
image:null,
url:'',
progress:0
}
this.handleChange = this.handleChange.bind(this)
this.handleChange = this.handleChange.bind(this)
}
onchangecomment=(event)=>{
this.setState({comment:event.target.value});
console.log(this.state.comment)
}
handleChange(event) {
if(event.target.files[0]){
const image=event.target.files[0];
this.setState(()=>({image}));
console.log(this.state.image)
}
}
handleUpload=()=>{
const {image}=this.state;
const uploadTask=storage.ref(`images/${image.name}`).put(image);
if(image){
document.getElementById('progress').style.display="block";
}
uploadTask.on('state_changed',
(snapshot)=>{
const progress=Math.round((snapshot.bytesTransferred/snapshot.totalBytes)*100);
this.setState({progress})
}
,(error)=>{
console.log(error)
},
()=>{
storage.ref('images').child(image.name).getDownloadURL().then(url=>{
this.setState({url})
document.getElementById('txtarea').value +=`<img src=${this.state.url} alt='image'/>`;
document.getElementById('placehoder').style.display="block";
document.getElementById('progress').style.display="none";
})
})
}
addcomment=()=>{
fetch('http://localhost:3002/Addcomment',{
method:'post',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({
comment:this.state.comment,
postid:this.state.postid
})
}).then(resposne=>{})
.catch(err=>{console.log('not added from the quesiotns')})
document.getElementById('txtarea').value='';
}
render()
{
const {postcontent}=this.state;
return(
<div className='article'>
<div dangerouslySetInnerHTML={{ __html:postcontent }} />
<h4>Discussion</h4>
<div className='submitcommentform'>
<textarea id='txtarea' placeholder='Add discussion'
onChange={this.onchangecomment}
style={{height:'127px', width:'687px',padding:'6px 6px'}}>
</textarea>
<div className='submit-wrapper-actions'>
<Link to='' ><img className='wrapperimgage' src='https://practicaldev-herokuapp-com.freetls.fastly.net/assets/info-b2ce6a88ddd367e1416cd4c05aab2edee2d0b2c355d7b2aae1821eec48014e11.svg' height='21px'/></Link>
<label for="choosefile" class="btnimage">Select Image</label>
<input id='choosefile'type='file' onChange={this.handleChange} style={{visibility:'hidden'}} />
<button id='btnuplod' onClick={this.handleUpload}>Upload Image</button>
<button id='btnsubmit'onClick={this.addcomment}>Submit</button>
</div>
<div className='placeh-progr'>
<img id='placehoder' alt='uploaded image' src={this.state.url || "https://via.placeholder.com/150"} width='150px' height='150px'
style={{display:'none'}}
/>
<progress id='progress' value={this.state.progress} max="100" style={{display:'none'}} />
</div>
</div>
<div>
{
this.state.arraycomments.map((post,i)=>{
return (
<div className='commentsection' key={i} dangerouslySetInnerHTML={{ __html:post.comm_content }} />
);
})
}
</div>
</div>
);
}
}
export default Articles;
My question : is there any way to make the image smaller than the container.

Why not use CSS for that?
.your-image-class,
.container-class img {
max-width: 100%;
}
Either put a class for an image or do it "globally" for images in a container class.

Related

Can't figure out how to redirect to home page

I just started watching some guide on youtube how to make simple fronend in React with bootstrap. I'm stuck for hours on one step since on react-router-dom v6 I can't use history anymore and as I'm using React class comp, I don't know how to implement "useNavigate" to my code. Thing that I want to do is when I add new book to go back to home page which is "/books". Here is my code:
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import BookService from '../services/BookService';
class CreateBookComponent extends Component {
constructor(props){
super(props)
this.state={
bookName: "",
authorName: ""
}
this.changeBookNameHandler = this.changeBookNameHandler.bind(this);
this.changeAuthorNameHandler = this.changeAuthorNameHandler.bind(this);
this.saveBook = this.saveBook.bind(this);
}
changeBookNameHandler = (event) => {
this.setState({bookName: event.target.value});
}
changeAuthorNameHandler = (event) => {
this.setState({authorName: event.target.value});
}
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
**here is where did guy in guide called this.props.history.push('books');**
});
}
render() {
return (
<div>
<div className='container mt-2'>
<div className='row'>
<div className='card col-md-6 offset-md-3 offset-md-3'>
<h1 className='text-center'>Add Book</h1>
<div className='card-body'>
<form>
<div className='form-group'>
<label> Book Name</label>
<input placeholder='Book Name' name='bookName' className='form-control'
value={this.state.bookName} onChange={this.changeBookNameHandler}/>
</div>
<div className='form-group mt-2'>
<label> Author Name</label>
<input placeholder='Author Name' name='authorName' className='form-control'
value={this.state.authorName} onChange={this.changeAuthorNameHandler}/>
</div>
<button className='btn btn-success mt-2' onClick={this.saveBook}>Save</button>
<Link to="/books" className="btn btn-danger mt-2" style={{marginLeft: '10px'}}>Cancel</Link>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default CreateBookComponent;
You can try this:
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
window.location.href = "youWebsiteUrl" + "/books"
});
}

Dynamically expand/collapse on click of header

I have a set of items that needs to be shown in the UI, like a header and list of items under it. There is a parent component where I am passing this data to a file that is shown below. Based on this the parent-child layout is shown. Now I need to expand/collapse based on the click of the header.
There is a class "open" and "close " that can be attached to the div. Based on it the it gets collapse/expands. The point is how do it item wise
Can someone help
import React from "react";
import Child from "./Child";
import Parent from "./Parent";
export default class Helper extends React.Component{
constructor(props: any) {
super(props);
this.state = {
parent:{},
children:{},
};
}
componentDidMount() {
this.setParentValue();
this.setChildValue();
}
render() {
const { parent, children } = this.state;
const { name } = this.props;
return (
<>
<div className="an-panel expand-panel expand-close">
<div className="an-panel-header">
<div className="title-holder">
<span className="toggle-icon far fa-plus-square" />
<span className="toggle-icon far fa-minus-square" />
<h5>{name}</h5>
</div>
<div className="action-holder">
<div className="status-holder">
<Parent
parent = {parent}
onSelect={this.handleParentClick}
/>
</div>
</div>
</div>
{children.map(({ id, name },id) => (
<div className="an-panel-body" key={id}>
<ul className="applications-list-holder">
<li>
<div className="name">{name}</div>
<div className="status">
<Child
children={children}
onSelect={this.setChildSwitchValue}
/>
</div>
</li>
</ul>
</div>
))}
</div>
</>
);
}
}
Ok let me explain it to you, here is your code
import React from "react";
import Child from "./Child";
import Parent from "./Parent";
export default class Helper extends React.Component{
constructor(props: any) {
super(props);
this.state = {
parent:{},
children:{},
navBarStatus: false,
};
}
componentDidMount() {
this.setParentValue();
this.setChildValue();
}
changeNavBar = (e, status)=>{
this.setState({navBarStatus: !status});
}
render() {
const { parent, children } = this.state;
const { name } = this.props;
return (
<>
<div className={`an-panel expand-panel ${this.state.navBarStatus ? "expand-open" : "expand-close"}`}>
<div className="an-panel-header" onClick={(e)=>this.changeNavBar(e, this.state.navBarStatus)}>
<div className="title-holder">
<span className="toggle-icon far fa-plus-square" />
<span className="toggle-icon far fa-minus-square" />
<h5>{name}</h5>
</div>
<div className="action-holder">
<div className="status-holder">
<Parent
parent = {parent}
onSelect={this.handleParentClick}
/>
</div>
</div>
</div>
{children.map(({ id, name },id) => (
<div className="an-panel-body" key={id}>
<ul className="applications-list-holder">
<li>
<div className="name">{name}</div>
<div className="status">
<ChildSetting
children={children}
onSelect={this.setChildSwitchValue}
/>
</div>
</li>
</ul>
</div>
))}
</div>
</>
);
}
}
You can see I have taken a new property in state navBarStatus. Based on navBarStatus value I am changing CSS class which will expand/close your attached div

Passing props from one component to another in ReactJS returns undefined

I am a newbie in React and I am trying to pass props from one React component to another. Please consider my code below and tell me what could I possibly doing wrong.
As you will notice, I am trying to do so with this.props.value, but all I got in the console is "undefined". I managed to run the code by putting all HTML elements in one component and it was working perfectly fine.
class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.state.input}
onChange={this.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
render() {
return (
<div id="wrapper">
<Editor />
<Previewer />
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
It should look like this:
class Editor extends React.Component {
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.props.input}
onChange={this.props.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div id="wrapper">
<Editor input={this.state.input} inputChanges={this.inputChanges}/>
<Previewer value={this.state.input}/>
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
The idea is that the Wrapper component will be the one which hold the state and control the state change. The Editor and Previewer are its children which receive data to display and invoke the callback prop.
If two components share state lift the state to the parent component - in this case Wrapper. And since neither of the two children components have state they can be coded as stateless functions.
function Editor({ text, handleChange }) {
return (
<div>
<div id="editorBar">Editor
<i className="fa fa-expand expand" />
</div>
<textarea id="editor" value={text} onChange={handleChange} />
</div>
);
}
function Previewer({ text }) {
return (
<div>
<div id="previewerBar">Preview
<i className="fa fa-expand expand"></i>
</div>
<div id="preview" dangerouslySetInnerHTML={{__html: text}}></div>
</div>
);
}
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state={ input: props.defaultText }
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({ input: e.target.value });
}
render() {
return (
<div id="wrapper">
<Editor text={this.state.input} handleChange={this.handleChange} />
<Previewer text={this.state.input} />
</div>
);
}
}
const defaultText = 'Some default text';
ReactDOM.render(<Wrapper defaultText={defaultText} />, document.getElementById('root'));
<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>
<div id="root"></div>

Making a custom radio button for Redux-Form Wizard

I'm following the example here: https://redux-form.com/6.6.3/examples/wizard/
I've managed to make everything I needed up until now, but I'm getting stuck on how to make custom radio buttons.
This is what I have so far, but I can't get the radio button to change when clicking on the divs that represent it
import React, { Component } from 'react'
import './pictureCard.css'
import '../../../../app.css'
import MaterialIcon from 'react-google-material-icons'
import { Field } from 'redux-form'
export default class PictureCard extends Component {
constructor(props) {
super(props)
this.state = {
isChecked: false
}
}
handleTick = event => {
const card = event.target
card.classList.toggle('question__checkbox--selected')
this.setState(prevState => {
return { isChecked: !prevState.isChecked }
})
}
render() {
const {
tabOrder,
cardName,
cardKey,
cardLabel,
thumbnail,
thumbnailAlt
} = this.props
return (
<li
className="question__choice"
tabIndex={tabOrder}
onClick={this.handleTick}
>
<Field
name={cardName}
type="radio"
component="input"
value={cardLabel}
checked={this.state.isChecked}
/>
<div className="question__tick-wrap">
<MaterialIcon icon="check" />
</div>
{thumbnail === undefined ? null : (
<div className="question__image-wrap">
<img src={thumbnail} alt={thumbnailAlt} />
</div>
)}
<div className="question__text-wrap flex flex--center-vertical">
<div className="question__label">
<div className="question__letter">
<span>{cardKey}</span>
</div>
</div>
<div className="question__text-label">{cardLabel}</div>
</div>
<div className="question__bg" />
</li>
)
}
}
I can programatically change the value, but it doesn't update in the store, and I don't know why :(
This is what I tried:
import React, { Component } from 'react'
import './pictureCard.css'
import '../../../../app.css'
import MaterialIcon from 'react-google-material-icons'
import { Field } from 'redux-form'
export default class PictureCard extends Component {
constructor(props) {
super(props)
this.state = {
valueTest: false
}
}
handleTick = event => {
const card = event.target
card.classList.toggle('question__checkbox--selected')
this.setState({ valueTest: 'Hello' })
}
render() {
const {
input,
tabOrder,
cardName,
cardKey,
cardLabel,
thumbnail,
thumbnailAlt
} = this.props
return (
<li
className="question__choice"
tabIndex={tabOrder}
onClick={this.handleTick}
>
<input
{...input}
name={cardName}
value={this.state.valueTest}
type="text"
tabIndex={tabOrder}
/>
<div className="question__tick-wrap">
<MaterialIcon icon="check" />
</div>
{thumbnail === undefined ? null : (
<div className="question__image-wrap">
<img src={thumbnail} alt={thumbnailAlt} />
</div>
)}
<div className="question__text-wrap flex flex--center-vertical">
<div className="question__label">
<div className="question__letter">
<span>{cardKey}</span>
</div>
</div>
<div className="question__text-label">{cardLabel}</div>
</div>
<div className="question__bg" />
</li>
)
}
}

React - How to show component from an image onClick event in another component?

I have 3 React components:
-Home - need to display the component here when image is
clicked from the Header component
-Header- Contains the image tag that will be clicked to
show the AllSites Component.
-AllSites - component that needs displayed in Home component when Image is
clicked in the Header component.
Header
export class Header extends React.Component<any, any> {
private readonly searchServerUrl = "";
private appButtonElement: HTMLElement;
constructor(props: any) {
super(props);
this.state = { showAppMenu: false };
}
render() {
const { showAppMenu } = this.state;
const { className, navItems, singleColumn, appItems } = this.props;
return (
<header className={className}>
<div className="app-icon">
<button className="nav-button" onClick={() => this.toggleAppMenu()} ref={(menuButton: any) => this.appButtonElement = menuButton}><i className="ms-Icon ms-Icon--Waffle" aria-hidden="true"></i></button>
</div>
***When image is clicked, show the <AllSites/> component in the HomeComponent below.***
<img src="/Styles/Images/logo/loop-logo-white.png" className="nav-logo" onClick={} />
{showAppMenu ? <ApplicationMenu navItems={appItems} targetElement={this.appButtonElement} onDismiss={() => this.onDismiss()} /> : null}
<div className="nav-container"><TopNavigation classNam
e={className} navItems={navItems} singleColumn={singleColumn} /></div>
<div className="search-container">
<SearchBox onSearch={(searchTerm: string) => this.executeSearch(searchTerm)} />
</div>
</header>
);
}
Home
export class HomeComponent extends React.Component<any, any> {
constructor(props: any) {
super(props);
this.state = { navItems: [], appItems: [], singleColumnLayout: false, showAllSites: false };
}
componentDidMount() {
this.checkWidth();
window.addEventListener("resize", this.checkWidth.bind(this));
this.fetchNavigation()
.then(nav => this.setState({ navItems: nav }));
this.fetchAppIcons()
.then(icons => this.setState({ appItems: icons }));
}
componentWillUnmount(): void {
window.addEventListener("resize", this.checkWidth.bind(this));
}
render() {
const { navItems, appItems, singleColumnLayout } = this.state;
return (
<Fabric>
<Header navItems={navItems} appItems={appItems} singleColumn={singleColumnLayout} />
<div className="main-container">
<AlertBar />
<div className="main-content">
<div className="ms-Grid">
When the image tag is clicked, I need to render the <AllSites/> component here
<Hero singleColumn={singleColumnLayout} />
<div className="ms-Grid-row">
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<UpcomingEvents />
</div>
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<EmployeeNews />
</div>
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<div className="ms-Grid-row">
<div className="ms-Grid-col ms-sm12 webpart-container">
<IndustryNews />
</div>
<div className="ms-Grid-col ms-sm12 webpart-container">
<Quote />
</div>
</div>
</div>
</div>
</div>
<Footer navItems={navItems} />
</div>
</div>
</Fabric>
);
}
In the simplest approach you will need a common parent component for your Home and Header that will hold some shared state for them and that will pass a callback to update this state as a prop to Header. In the shared state you need a flag that will be responsible for showing/hiding AllSites component, this flag you will pass as a prop to Home.
You can see a basic example here
If you need a more advanced state management solution, you can check redux library

Categories

Resources