I have a searching system where user search by typing the place. If the place does not match, it should show not found and if place matches, it should show the place detail. What I did is
code
render() {
var margin = { marginTop : '13em' };
if (this.state.place){
let location = _.map(this.state.place, (place,id) => {
return(
<Room key={id}
slug={place.slug}
place={place.place}
city={place.city}
gallery={place.gallery}
property={place.property}/>
)
console.log('location',location);
});
let gallery = _.map(this.state.place, (place,id) => {
console.log('place',place.gallery);
_.map(place.gallery, (image,id) => {
return(
<img src={image.image} class="img-fluid" />
)
});
});
let noLocation = () => {
return(
<div className="noroom">There is no room</div>
);
console.log('nolocation');
};
return(
<div className = "container">
<div className="content text-align-center">
<div className="row text-xs-center">
<div className="middle-text" style={margin}>
<h1 className="welcome"><span>Common Rental Space</span></h1>
<p className="appSubtitle">facilitates your search for rental space all over Nepal</p>
<button ref="test" className="btn how-it-works" onClick={this.handleClick}>Search Space</button>
</div>
</div>
</div>
<div id="mySearch" className="overlay" onKeyDown={this.handleKeyDown}>
<button className="btn closebtn" onClick={this.handleClick}>x</button>
<div className="overlay-content">
<SearchInput ref="searchInput" className="search-input" onChange={this.searchUpdated} />
<div className="container searchList">
{ this.state.place > 1 ? {location} : {noLocation} }
</div>
</div>
</div>
</div>
);
}
}
}
What might be the error? The syntax is { condition ? true : false }
When I do {this.state.place >1 ? { location } : {noLocation} } I get an error
app.js:1030 Uncaught Invariant Violation: findComponentRoot(..., .0.1.1.1.0.0): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a> or using non-SVG elements in an <svg> parent. Try inspecting the child nodes of the element with React ID ``.
When I do this.state.place >1?{location}:{noLocation}i get this.state.place >1 ? result, and if place does not match the page shows this.state.place >1 ? :.
noLocation appears to be a method, but you aren't actually calling the method anywhere - so you are basically telling reaction to render the function itself, not the result of the method.
If it must be a method, try, noting the extra ():
{ this.state.place.length >=1 ? location : noLocation() }
Related
I have a lit element based javascript project, when I want to throw an html tag with .replace in a text, I encounter either the value with the tag or a structure in the form of object, object, I made a structure as follows, what am I doing wrong?
basicly my values
main-text = abc dcf [0] xyz
bold-text = 123
and my render here
render() { return html`
<section >
<div class="blablaclass" #click = ${() => this.clickfnc()} >
<div class="blablaclass1">
${html`<span> ${this.t('main-text').replace('[0]', this.renderCardText )} </span>`}
</div>
<div>
<img class="blablaclass2" src="./resources/right-arrow.svg"/>
</div>
</div>
</section>`;
}
get renderCardText(){
return html`<strong>this.t('bold-text')</strong>`;
}
and outputs
output: acv dcf [] xyz
without call html in function just return output: acv dcf <strong>123</strong> xyz
The html tag function returns a TemplateResult object so you can't use it as a replacement in String.prototype.replace().
There are a couple different options for what you want to do:
Split the string instead of replacing and combine them piece by piece.
render() {
const [before, after] = this.t('main-text').split('[0]');
return html`
<section >
<div class="blablaclass" #click = ${() => this.clickfnc()} >
<div class="blablaclass1">
${html`<span>${before}${html`<strong>${this.t('bold-text')}</strong>`}${after}</span>`}
</div>
<div>
<img class="blablaclass2" src="./resources/right-arrow.svg"/>
</div>
</div>
</section>`;
}
This can get tricky if you have more than 1 things to replace.
Replace as string and use the unsafeHTML directive.
render() {
return html`
<section >
<div class="blablaclass" #click = ${() => this.clickfnc()} >
<div class="blablaclass1">
${html`<span>${unsafeHTML(this.t('main-text').replace('[0]', `<strong>${this.t('bold-text')}</strong>`))}</span>`}
</div>
<div>
<img class="blablaclass2" src="./resources/right-arrow.svg"/>
</div>
</div>
</section>`;
}
Make sure you trust the string you put in there.
Not sure why I'm getting this error. I need to loop through the variations and find the id's containing the varid variables. To me this looks right but it's obviously not. I'm sure everyone here is much smarter than me though haha, I'm still very much a newbie at all this.
This function is supposed to allow me to filter down the state so that I have only the needed data and can display that within the page rather than the state containing all of my drupal products. Perhaps there's a more efficient way to do this also, I'm not sure.
Here's the code:
class ProductPage extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
dropdownOpen: false
};
}
toggle() {
this.setState(prevState => ({
dropdownOpen: !prevState.dropdownOpen
}));
}
render() {
let style = {
height: this.props.height - 56,
};
let product = this.props.products.items.find(o => o.path[0].alias === this.props.router.match.url);
console.log(product);
console.log(this.props.variations);
let variationList = [];
if (product && this.props.variations) {
for (let i = 0; i < product.variations.length; i++) {
let varid = product.variations[i].variation_id;
let variation = this.props.variations.find(o => o.path[0].alias === varid);
variationList.push(variation);
}
}
let body = product && product.body.length ? product.body[0].value : null;
return (
<div className="App" id="default">
<div className='MenuBar'>
<MenuBar/>
</div>
<div>
<div style={style} className="ProductPage row no-gutters">
<div className="col-xs-3 col-md-3">
<LeftMenuBar/>
</div>
<div className="outer col-xs-4 col-md-4">
<div>
<div id="ProductPlacement">
<img src={WomensWear} alt=""/>
<div id="alternate-pics">
<div id="alt-pic">
</div>
<div id="alt-pic">
</div>
<div id="alt-pic">
</div>
</div>
</div>
</div>
</div>
<div className="col-xs-5 col-md-5">
<div id="ImagePlacement">
<div className="ProductTitle">
<h1>First Product</h1>
</div>
<hr/>
<div className="ProductDescription">
<div dangerouslySetInnerHTML={{__html: body}} />
</div>
<div id="options">
<div id="color">
</div>
<div id="color2">
</div>
<div id="color3">
</div>
</div>
<div id="options">
<div>
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle caret id="size-dropdown">
Size
</DropdownToggle>
<DropdownMenu>
<DropdownItem>1</DropdownItem>
<DropdownItem>3</DropdownItem>
<DropdownItem>5</DropdownItem>
</DropdownMenu>
</Dropdown>
<div className="AddToCart">
<button className="AddToCart">Add To Cart</button>
<button className="Price">$34.99</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default ProductPage;
I also ran into this issue and through trial and error discovered it was because of copy+paste. Check your reducer(s) to make sure you aren't setting a default of an object {} or other type, instead of an array [].
In my case I had (this is ES6 syntax by the way):
const someReducer = (state = {}, action) => {
switch (action.type) {
case 'reducer type':
// get the data etc.
return [];
default:
return state;
}
};
When I should have had:
const someReducer = (state = [], action) => {
switch (action.type) {
case 'reducer type':
// get the data etc.
return [];
default:
return state;
}
};
Notice the first line where I'm setting the default. This is used while the api calls are pending, so if it just happens to reach the code where .find() is being used then you'll get the error.
This is extremely easy to miss because data is retrieved so fast that you can't easily see when the data is the wrong type. Just make sure your default, however you're setting it, is the correct type! Hope that helps someone!
I'm hoping you encounter the same issue of mine. I have react code that need a jquery event like (click, change). here is my code.
export default class SamplePreviewComponent extends React.Component<Props, any> {
constructor(props) {
super(props);
}
componentDidMount() {
this.renderChoiceButton();
}
renderChoiceButton() {
$("input.st").on("click", function() {
let value = $(this).val();
this.props.addDependentSample(value);
});
}
render() {
const { sampleTree } = this.props;
return (
<div className="row pl-1 pr-1 pt-0 mb-1">
<div className="columns bg-black20 pt-1 pb-1 border-radius-sm">
<div className="mb-1">
<p className="subheader">
<strong>
<small>SAMPLE #1</small>
</strong>
</p>
{sampleTree.root.label.trim().length > 0 && <h4>{sampleTree.root.label}</h4>}
{sampleTree.root.subLabel &&
sampleTree.root.subLabel.trim().length > 0 && (
<span className="subheader">
<small>
<strong>{sampleTree.root.subLabel}</strong>
</small>
</span>
)}
</div>
<div>
<div
dangerouslySetInnerHTML={{ __html: sampleTree.root.generatedHtml }}
className="red"
/>
</div>
</div>
</div>
);
}
}
if you check my return value of my component. there is dangerouslySetInnerHTML added. The output is like this
<div>
<div class="fancy-checkbox fancy-hover small mb-0">
<input type="checkbox" class="st" id="_0" name="17[]" value="1">
<label for="_0">1</label>
</div>
<div class="fancy-checkbox fancy-hover small mb-0">
<input type="checkbox" class="qt" id="_1" name="17[]" value="2">
<label for="_1">2</label>
</div>
</div>
When the user click the checkbox. I'm going to add and event using a jquery
renderChoiceButton() {
$("input.st").on("click", function() {
let value = $(this).val();
this.props.addDependentSample(value);
});
}
I get an error Cannot read property 'addDependentSample' of undefined. Maybe, because it comes from the react props and the jquery cannot read it. How can I add event using jquery that will connect the function to react?
There are a few ways you can resolve this error - a simple approach would be to store a reference to your component instance (ie componentInstance as shown below), and then access the component's props through that instance, like so:
renderChoiceButton() {
// Store reference to component for access in click handler
const componentInstance = this;
$('input.st').on('click', function() {
let value = $(this).val();
// Access props for the component via componentInstance
componentInstance.props.addDependentSample(value);
});
}
I have a quiz form here and would like to add input fields for questions when a user clicks the "Add a question" button.
I've been playing around with the code and have been able to populate the state object with some text. Obviously, the goal is to have this be an input component and then somehow rendering this to the screen.
What I'm struggling with is how to render an actual element to the page. I know it's done in the render method of the component just not exactly sure how.
I think I'm getting close. Any help would be appreciated. The code is below.
Thanks!
var QuizForm = React.createClass({
getInitialState : function() {
return { questions : [] }
},
createQuestion : function() {
this.state.questions.push("Test");
// Adds "Test" to state object.
this.setState({
questions : this.state.questions
});
},
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul>
{/* Would like question inputs to show up here */}
</ul>
<button onClick={this.createQuestion} className="add-question-btn btn btn-primary" style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Just map your this.state.questions array to the HTML element you want.
For instance, if you want to render <li> elements:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li>{state}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
See an example.
If you want to render <input> tags, you can use the same technique above, but be mindful of the fact that React treats it as a controlled component.
A React best practice would be to map your state.questions array to a dynamically generated HTML component such as:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li key={state.someId}>{state.question}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Please keep in mind that when mapping and rendering dynamic objects in React it's always good to insert a key for each mapped object. So make sure to create that when you're creating the content.
Best Regards,
If my api takes the query as http://localhost:8000/api/v1/rental/?place__startswith=kathmandu then how can i do generic search in reactjs. What i tried is i passed the default parameter as search(query=kathmandu) so that the result of place named kathmandu will be listed by default and when user types place name that they want to search then it should display those places instead of kathmndu. But i am getting an error saying Uncaught ReferenceError: kathmandu is not defined. How can i resolve this problem?
componentWillMount(){
this.search();
}
search(query=kathmandu){
let url = 'http://localhost:8000/api/v1/rental/?place__startswith=query';
Request.get(url).then((response) => {
console.log('response',response.body.objects);
this.setState({
place:response.body.objects
});
});
}
searchUpdated(term){
console.log('term is',term);
this.search(term);
}
render() {
var margin = { marginTop : '13em' };
let location = _.map(this.state.place, (place) => {
return(
<div className="searchResult">
<li>{place.place}</li>
<li>{place.city}</li>
</div>
)
});
return(
<div className = "container">
<div className="content text-align-center">
<div className="row text-xs-center">
<div className="middle-text" style={margin}>
<h1 className="welcome"><span>Welcome </span></h1>
<button ref="test" className="btn how-it-works" onClick={this.handleClick}>Search Space</button>
</div>
</div>
</div>
<div id="mySearch" className="overlay" onKeyDown={this.handleKeyDown}>
<button className="btn closebtn" onClick={this.handleClick}>x</button>
<div className="overlay-content">
<SearchInput ref="searchInput" className="search-input" onChange={this.searchUpdated} />
<ul>{location}</ul>
</div>
</div>
</div>
);
}
}
I think what you're looking for is encodeURIComponent.
search( query='kathmandu' ){
And:
let url = 'http://localhost:8000/api/v1/rental/?place__startswith=' + encodeURIComponent(query);
NB as your query string actually does only contains letter, you don't need encodeURIComponent for that example, but you might need it in other cases.