Updating attributes with search bar in react - javascript

I am trying to dynamically render and update views when string contains substring with addition of attribute.
I need to use JavaScript object like this: var ObjectArray =[{"title:"Great Title"},{"title":"Interesting Title"},{"title":"Boring Title"}];
This is what i found but it uses react kind of object and renders only fitting matches.
let contacts = [{
id: 1,
name: 'Sherlock',
phone: '221 221 221'
}, {
id: 2,
name: 'Watson',
phone: '332 333 331'
}]
class App extends React.Component {
render() {
return (
<div>
<h2>Contact List</h2>
<br />
<ContactList contacts={this.props.contacts} />
</div>
)
}
}
class Contact extends React.Component {
render() {
return (
<li>{this.props.contact.name} {this.props.contact.phone}</li>
)
}
}
class ContactList extends React.Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
this.setState({
search: event.target.value.substr(0, 10)
});
}
render() {
let filteredContacts = this.props.contacts.filter(
(contact) => {
return contact.name.toLowerCase().includes(this.state.search.toLowerCase());
}
);
console.log(filteredContacts);
return (
<div>
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
<hr />
<ul>
{filteredContacts.map((contact) => {
return <Contact contact={contact} key={contact.id} />
})}
</ul>
</div>
)
}
}
ReactDOM.render(<App contacts={contacts} />, document.getElementById('container'));
ReactDOM.render(
<FilterableProductTable products={PRODUCTS} />,
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>
<body>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
I had my attempts at changing this code but it used all static solutions which did not update.
This is a concept i had:
var ObjectArray =[{"title":"Great Title"},{"title":"Interesting Title"},{"title":"Boring Title"}];
var BoolArray = Array(ObjectArray.length).fill(false);
class App extends React.Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
this.setState({
search: event.target.value.substr(0, 10)
});
}
render() {
return(
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
)
{ObjectArray.map((obj, index) => {
return(
<h1 className={BoolArray[index] ? 'red' : 'blue'}>{obj.title}</h1>
)
}
)
}
}
ReactDOM.render(
<App/>
document.getElementById('root')
);
.red{
color : red;
}
.blue{
color: blue
}
<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">

yes is expected to be an object map but is not defined, that will cause issues.
return(
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
)
so, you return that expression and then continue under it? that's dead code because function has exited.
react can only currently return 1 root level element. if you need to return more, you have to wrap into an element.
so
render(){
return <div>
<input ... />
{something.map(el => <h1>{el.title}</h1>)}
</div>
}

Related

Hi ! React issues i need assistance with event handlers

I'm trying to make a components props(sideBarInfo) details show up on the left column of a Page after clicking on a corresponding component(thumbnail) on the right column of the same Page.
Please note that all imports and exports are used in the main project(i removed them here).
I've also imported all components into the main (Page.js). Yet i keep getting a Type error for the onClick.
This is the first component - Thumbnail
class Thumbnail extends React.Component {
render(){
return (
<div className="Work" onClick={(e) => this.props.click(this.props.work)} >
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc}/>
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
);
} }
This is the ThumbnailList
class ThumbnailList extends React.Component {
constructor(props){
super(props);
this.state= {
works: [
{
id: 0,
work: 'Work 1',
imageSrc: W1,
view: '#',
selected: false
},
{
id: 1,
work: 'Work 2',
imageSrc: W2,
view: '#',
selected: false
},
]
}
}
handleCardClick = (id,card) => {
console.log(id);
let works= [...this.state.works];
works[id].selected = works[id].selected ? false : true ;
works.forEach(work=>{
if(work.id !== id){
work.selected = false;
}
});
this.setState({
works
})
}
makeWorks = (works) => {
return works.map(work => {
return <Thumbnail work={work} click={(e => this.handleCardClick(work.id,e ))} key={work.id} />
})
}
render(){
return(
<div>
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
);
}
}
This is the sidebarInfo
function SidebarInfo(props) {
return (
<img width="370" height="370" src= {props.imageSrc} />
<p> {props.work} </p>
);}
This is the problematic Page - the boldened keeps giving a Type error(cannot read property 'selected' of undefined.)
class Page extends React.Component {
render() {
return (
<span>
<div className="column left">
<div className="">
**{this.props.work.selected && <SidebarInfo imageSrc={this.props.imageSrc} /> }**
</div>
</div>
<div className="column right" >
<div>
<ThumbnailList />
</div>
</div>
</span>
)
}
}
You may need to add a check in this.props.work.selected like this this.props.work && this.props.work.selected
To ensure that this.props.work is defined before checking on this.props.work.selected
I was able to answer this for anyone interested.
there were some foundational errors in my file arrangement which have been corrected.
After refactoring, i was able to achieve what i wanted using 3 classes/functions in; App.js, Thumbnail.js and SideBarInfo.js
see one working solution with styling on this sandbox: https://codesandbox.io/s/modern-sky-y9d3c
See Solution below;
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
this.handleCardClick = this.handleCardClick.bind(this);
this.makeWorks = this.makeWorks.bind(this);
this.showWorks = this.showWorks.bind(this);
}
handleCardClick = (id, Thumbnail) => {
console.log(id);
let works = [...this.state.works];
works[id].selected = works[id].selected ? false : true;
works.forEach((work) => {
if (work.id !== id) {
work.selected = false;
}
});
this.setState({
works
});
};
makeWorks = (works) => {
return works.map((work) => {
return (
<Thumbnail
work={work}
click={(e) => this.handleCardClick(work.id, e)}
key={work.id}
/>
);
});
};
showWorks = (works) => {
let i = 0;
var w = [];
while (i < works.length) {
if (works[i].selected) {
w = works[i];
}
i++;
}
return ( <SidebarInfo imageSrc={w.imageSrc} work={w.work} /> );
};
render() {
return (
<div className="App">
<span>
<div> { this.showWorks(this.state.works)} </div>
<div className="">
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
</span>
</div>
);
}
}
class Thumbnail extends React.Component {
render() {
return (
<div>
<div className="column left">
{/* this.props.work.selected && <SidebarInfo work={this.props.work.work} imageSrc={this.props.work.imageSrc}/> */}
</div>
<div className="column right">
<div className="Work" onClick={(e) => this.props.click(this.props.work)}>
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc} />
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
</div>
</div>
);
}
}
export default Thumbnail;
function SidebarInfo(props) {
return (
<div className="one">
<div className="Work">
<h1> NAME </h1>
<div className="image-container">
<img
width="370"
height="370"
src={props.imageSrc}
alt={props.imageSrc}
/>
</div>
<p> {props.work} </p>
<p> {props.view} </p>
</div>
</div>
);
}
export default SidebarInfo;

How to render simple text with br tag?

I have a simple component:
class News extends Component {
state = {
isSimple: this.props.isSimple
}
render() {
return (
<div>
<div className="extended">extended</div>
simple text
</div>
);
}
}
export default News;
I would like to display only either extended or simple, so I do:
class News extends Component {
state = {
isSimple: this.props.isSimple
}
render() {
var text;
if (this.state.isSimple) {
text = "simple <br /> text";
} else {
text = <div className="extended">extended</div>
}
return (
{text}
);
}
}
But if state isSimple = true then this show me:
simple <br /> text
instead of:
simple
text
Besides, it is not very legible. Can I make an if condition in the middle of the render method?
Why you need to save text and return it? instead return jsx statement, and instead of using if statement, use operators. something like:
class News extends Component {
state = {
isSimple: this.props.isSimple
}
render() {
const { isSimple } = this.state;
return (
{ isSimple ? <div>simple <br /> text</div>
: <div className="extended">extended</div>
}
);
}
}
You can wrap the string in an object with {__html: 'your string here..'} and then use it using dangerouslySetInnerHTML props:
render() {
var text;
if (this.state.isSimple) {
text = <div dangerouslySetInnerHTML={{ __html: "simple <br /> text" }} />;
} else {
text = <div className="extended">extended</div>;
}
return text;
}
Fragments doesn't support dangerouslySetInnerHTML, so I had to use div there.
class News extends React.Component {
state = {
isSimple: this.props.isSimple
};
render() {
var text;
if (this.state.isSimple) {
text = <div dangerouslySetInnerHTML={{ __html: "simple <br /> text" }} />;
} else {
text = <div className="extended">extended</div>;
}
return text;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<News isSimple={true} />, rootElement);
<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>
I think your are missing the return part of the render methods
render() {
var text;
if (this.state.isSimple) {
return <div>simple <br /> text</div>;
} else {
return <div className="extended">extended</div>;
}
}

React - iterating over key value pairs in array

I cant get this snippet to output tacos
im not sure what I am doing wrong
let tacos = [{ John: "Guacamole" }, { Sally: "Beef" }, { Greg: "Bean" }];
class Parent extends React.Component {
render() {
return (
<div className="parent-component">
<h3>List of tacos:</h3>
<TacosList tacos={tacos} />
</div>
);
}
}
class TacosList extends React.Component {
render() {
return (
<div className="tacos-list">
{this.props.tacos.map((taco) => {
return
<Parent taco={taco}/>
})}
</div>
);
}
}
render(<Parent />, document.getElementById("root"));
Your problem is that you are breaking into a new line in after return which it's returning undefined while iterating the tacos list.
Furthermore, You will create an infinite loop rendering if you call <Parent /> inside <TacosList />
Either you create a new component to render the items or you do it within the <TacosList /> component
let tacos = [{
person: "John",
ingredient: 'Guacamole'
}, {
person: 'Sally',
ingredient: 'Beef'
}, {
person: 'Greg',
ingredient: 'Bean'
}];
class Parent extends React.Component {
render() {
return (
<div className="parent-component">
<h3>List of tacos:</h3>
<TacosList tacos={tacos} />
</div>
);
}
}
class TacosList extends React.Component {
render() {
return (
<div className="tacos-list">
{this.props.tacos.map((taco, index) => (
<p key={index}>{taco.person}: {taco.ingredient}</p>
))}
</div>
);
}
}
ReactDOM.render(<Parent />, 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>
The problem is
<Parent taco={taco}/>
First parent is not expecting a taco property.
Second I think you intend to actually render the elements to display the taco information there, not a Parent component for each taco.
Start up with creating an atomic component (div, span or IMG) to show the tacos list, in TacosList.
The map in TacosList will work only at the first level, because every item is a JavaScript object, which means you have to know the key, to have the value, or use Object.keys and Object.items to show names.

bind(this) in ReactJS and onChange update to state

I have the following code:
index.js
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Header homeLink={this.state.homeLink}/>
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
And
Home.js
export class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onChangeLink() {
this.props.changeLink(this.state.homeLink);
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<p>In a new Component!</p>
<p>Your name is {this.props.name}, your age is {this.state.age}</p>
<p>Status: {this.state.status}</p>
<hr/>
<button onClick={() => this.onMakeOlder()} className="btn btn-primary">Make me older!</button>
<hr/>
<button onClick={this.props.greet} className="btn btn-primary">Greet</button>
<hr/>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={this.onChangeLink.bind(this)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
Would onChange in the input tag be triggered as soon as I write something in the input field and update to state? I can't see the state change in the React Developer Tool extension in Chrome when I write something in the input field.
When I click the button this.onChangeLink it triggers the onChangeLink function. The onChangeLink doesn't seem to take any arguments since the brakets are empty, still I'm able to pass this.state.homeLink to this.props.changeLink inside the onChangeLink function. this.props.changeLink which is also a function in index.js takes an argument newName. I guess this is where the bind(this) comes in. What does bind(this) do? Could I rewrite it with a fat arrow function like (event) => this.onChangeLink(event)?
bind is a function in Function.prototype which returns a function object which is bound to the current this.
onClick={this.onChangeLink.bind(this)}
Here onClick function will be passed as a handler with the current context.
An arrow function does not create a new this context at all. The this will refer to the context in which the function is defined.
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
onChange={(event) => this.onChangeLink(event)}
Here even though onChangeLink is not bound, it is called within an arrow function within the same this context.
So.. yes, you can replace it with a fat arrow notation to get the same effect. Although you have to rewrite the list of arguments in this case twice.
You dont need to onChangeLink in Home component. You can directly pass the value to App component.
class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={()=>this.props.changeLink(this.state.homeLink)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
console.log(this.state)
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"))
<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="app"></div>

Passing properties through components in ReactJS, ES6 example

I'm new to React and need some help. I'm trying to rewrite this Facebook's offical example into something own in ES6:
http://codepen.io/gaearon/pen/rrJNJY?editors=0010#0
My code looks like this:
class Person extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>{this.props.user.name}</h3>
<h4>{this.props.user.surname}</h4>
<h4>{this.props.user.age}</h4>
</div>
)
}
}
class VisualAppearance extends Component {
render() {
return(
<div>
<p>{this.props.user.visuals.eyes}</p>
<p>{this.props.user.visuals.height}</p>
<p>{this.props.user.visuals.hair}</p>
</div>
);
}
}
class CreatePerson extends Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/>
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/>
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
var use = {
user: {
name: 'Dude',
surname: 'Dude Surname',
age: 30,
visuals: {
eyes: 'blue',
height: 180,
hair: 'dark'
}
},
dateCreated: new Date()
}
ReactDOM.render(
<CreatePerson name={use.user.name}
surname={use.user.surname} age={use.user.age} eyes={use.user.visuals.eyes} height={use.user.visuals.height}
hair={use.user.visuals.height} date={use.user.dateCreated}
/>
, document.getElementById('project'));
I get the following error: Cannot read property 'name' of undefined
If I change this just to this.props.user it goes through but the same error as above is reported on the surname.
In the link provided there is: props.user.avatarUrl , so it's a nested structure of the object.
How can I make this work and nesting object's properties like this.props.sth.sthElse.sthElse1 on ES6 Classes in React?
CreatePerson expects a property called user here:
class CreatePerson extends Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/> // <====
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/> // <====
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
You're not passing it one. You're passing it name, surname, and a bunch of others, but not user.
It works if you remove all those individual properties and pass it user instead:
ReactDOM.render(
<CreatePerson user={use.user} />
, document.getElementById('project'));
Example:
class Person extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>{this.props.user.name}</h3>
<h4>{this.props.user.surname}</h4>
<h4>{this.props.user.age}</h4>
</div>
)
}
}
class VisualAppearance extends React.Component {
render() {
return(
<div>
<p>{this.props.user.visuals.eyes}</p>
<p>{this.props.user.visuals.height}</p>
<p>{this.props.user.visuals.hair}</p>
</div>
);
}
}
class CreatePerson extends React.Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/>
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/>
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
var use = {
user: {
name: 'Dude',
surname: 'Dude Surname',
age: 30,
visuals: {
eyes: 'blue',
height: 180,
hair: 'dark'
}
},
dateCreated: new Date()
}
ReactDOM.render(
<CreatePerson user={use.user} />
, document.getElementById('project'));
<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="project"></div>

Categories

Resources