Render new element onClick in react.js - javascript

I'm new to react and am trying to render a new element onClick:
var LoginButton = React.createClass({
..............
..............
clickHandle : function() {
this.rememberMe = {
active: localforage.getItem('rememberMe', function (err, key) {
return key;
})
};
if (this.rememberMe.active == true || this.rememberMe.active == 'checked')
{
document.getElementById('loginForm').submit();
}
else {
React.render(<wantToRemember />, document.getElementById('loginbuttonhere'));
}
return this.rememberMe.active;
},
This is the element that should appear:
var wantToRemember = React.createClass({
getInitialState : function () {
return {
position: 'absolute',
display: 'block',
top: '20px',
width: '100px',
height: '100px'
}
},
render : function () {
return (
<div className="rememberPopup" style={this.state}>
<div className="row">
<div className="staylogin">
<div className="col-md-4">
<label for="checkbox">Angemeldet bleiben</label>
</div>
<div className="col-md-1">
<input type="checkbox" id="checkbox" name="remember" />
</div>
</div>
</div>
</div>
);
}
});
but it doesn't appear, instead react renders this html:
<wanttoremember data-reactid=".1"></wanttoremember>
I'm pretty sure I'm doing some pretty basic stuff wrong, but can't figure out what. Isn't it possible to call different elements like this?

Your react.js component name begins with a lower-case letter, it should start with an upper-case leter: var WantToRemember = React.createClass(...) and React.render(<WantToRemember />,....
The JSX compiler requires for component names to begin with an upper-case letter (see jsx docs on this):
To render a React Component, just create a local variable that starts with an upper-case letter:
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.getElementById('example'));

You should pass a React element to React.render instead of the tag itself, something like this:
React.render(
React.createElement(wantToRemember)
);

Related

React: Adding props only to React component and not html tag (React.Children.map recursively)

I have a Form's React component that manage several Field's component and attach to them some props.
Until now, I created only simple form, like this
<Form>
<FieldText/>
<FieldDropdown />
</Form>
but now, I need a form with more complex structure, like this
<Form>
<div>
<a data-tab="first">First Tab</a>
<a data-tab="second">Second Tab</a>
</div>
<div data-tab="first">
<FieldText />
</div>
<div data-tab="second">
<FieldText />
</div>
</Form>
With simple form I added props to Fieldin this way
var Form = React.createClass({
render: function(){
<form onSubmit={this.submit} acceptCharset="UTF-8" ref={cForm.id}>
{
React.Children.map(this.props.children, child => {
// if type is funtion the is a react component
if( typeof child.type === "function"){
return React.cloneElement(child, {
attachToForm: this.attachToForm,
disabled: this.props.disabled
});
} else {
return child;
}
})
}
</form>
}
});
How can I modify Form to add some props only to Field's component and not
html tag?
Each child component should have a type field, for normal html elements, this would be a string such as "span", "div", etc.
You can simply switch (or your conditional of choice) against that field.
Simple abstracted version would be like:
const Foo = (props) => (
<div style={props.style}>FOO</div>
);
class App extends React.Component {
render () {
return (
<div>
{ React.Children.map(this.props.children, child => {
if(typeof child.type === 'string') {
switch(child.type) {
case 'span':
return React.cloneElement(child, { style: { background: 'pink' }});
case 'div':
return React.cloneElement(child, { style: { background: 'red' }});
}
} else {
switch(child.type.name) {
case 'Foo':
return React.cloneElement(child, { style: { background: 'blue' }});
}
}
return child;
})}
</div>
);
}
}
ReactDOM.render(
<App>
<span>span</span>
<p>p</p>
<Foo />
<div>div</div>
</App>,
document.getElementById('root')
);
With codepen:
http://codepen.io/cjke/pen/qRQvmY?editors=0010
EDIT
Based on the comments, the question is more about recursively walking the DOM tree - in which, its simple a duplicate of this question: React.Children.map recursively?

How to get DOM element within React component?

I'm rendering multiple of the same component, each with their own tooltip. Can I write code that will only look within the HTML of each component, so I'm not affecting all the other tooltips with the same class name? I'm using stateless components. Here is the code:
OptionsComponent.js:
import React from 'react';
const OptionsComponent = () => {
const toggleTooltip = event => {
document.getElementsByClassName('listings-table-options-tooltip').classList.toggle('tooltip-hide');
event.stopPropagation();
};
return (
<div className="inline-block">
<span onClick={toggleTooltip} className="icon icon-options listings-table-options-icon"> </span>
<div className="tooltip listings-table-options-tooltip">
Tooltip content
</div>
</div>
);
};
Backbone.js has something like this, allowing you to scope your document query to begin within the view element (analogous to a React component).
With React, you don't want to modify the DOM. You just re-render your component with new state whenever something happens. In your case, since you want the OptionsComponent to track its own tooltip state, it really isn't even stateless. It is stateful, so make it a component.
It would look something like this:
class OptionsComponent extends React.Component {
state = {
hide: false
};
toggleTooltip = (ev) => this.setState({ hide: !this.state.hide });
render() {
const ttShowHide = this.state.hide ? "tooltip-hide" : "";
const ttClass = `tooltip listings-table-options-tooltip ${ttShowHide}`;
return (
<div className="inline-block">
<span onClick={this.toggleTooltip} className="icon icon-options listings-table-options-icon"> </span>
<div className={ttClass}>
Tooltip content
</div>
</div>
);
// Alternatively, instead of toggling the tooltip show/hide, just don't render it!
return (
<div className="inline-block">
<span onClick={this.toggleTooltip} className="icon icon-options listings-table-options-icon"> </span>
{/* do not render the tooltip if hide is true */}
{!this.state.hide &&
<div className="tooltip listings-table-options-tooltip">
Tooltip content
</div>
}
</div>
);
}
}
You should use refs.
Slightly modified from React docs:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
var underlyingDOMNode = this.textInput; // This is your DOM element
underlyingDOMNode.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in this.textInput.
return (
<div>
<input
type="text"
ref={(input) => this.textInput = input} />
<input
type="button"
value="Focus the text input"
onClick={this.focus}
/>
</div>
);
}
}
A comfortable approach would be modifying your toggleTooltip method this way:
...
const toggleTooltip = event => {
event.target.parentNode.querySelector('.tooltip').classList.toggle('tooltip-hide');
};
...
I would however recommend having a state to represent the tooltip displaying or not.
With https://github.com/fckt/react-layer-stack you can do alike:
import React, { Component } from 'react';
import { Layer, LayerContext } from 'react-layer-stack';
import FixedLayer from './demo/components/FixedLayer';
class Demo extends Component {
render() {
return (
<div>
<Layer id="lightbox2">{ (_, content) =>
<FixedLayer style={ { marginRight: '15px', marginBottom: '15px' } }>
{ content }
</FixedLayer>
}</Layer>
<LayerContext id="lightbox2">{({ showMe, hideMe }) => (
<button onMouseLeave={ hideMe } onMouseMove={ ({ pageX, pageY }) => {
showMe(
<div style={{
left: pageX, top: pageY + 20, position: "absolute",
padding: '10px',
background: 'rgba(0,0,0,0.7)', color: '#fff', borderRadius: '5px',
boxShadow: '0px 0px 50px 0px rgba(0,0,0,0.60)'}}>
“There has to be message triage. If you say three things, you don’t say anything.”
</div>)
}}>Yet another button. Move your pointer to it.</button> )}
</LayerContext>
</div>
)
}
}

Render JSX element based on condition

So I have a simple component within a web app I have been working on and I was wondering if there is a way I could render an element within this component based on the value of this.props.item.
here is my JSX:
var React = require("react"); var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
deleteSchool: function(e){
e.preventDefault();
actions.deleteSchool(this.props.info);
},
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
<div className="panel-body">{this.props.info.tagline}</div>
</div>
)
} })
I wanted to be able to do something like this:
render:function(){
return(
code blah blah...
if (this.props.info = "nothing"){
<div className="panel-body">{this.props.info.tagline}</div>
}
...code blah blah
But I cannot write javascript withing the render function itself. Does anyone know how I could do this? Any help or advice is appreciated, thank you in advance.
You can use conditionally render using if and return the appropriate jsx
render(){
if(something){
return(<MyJsx1/>)
}else{
return(<MyJsx2/>)
}
}
You can chaage your component to:
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
{this.props.info = "nothing"?
(<div className="panel-body">{this.props.info.tagline}</div>)
:null}
</div>
)
} })
https://facebook.github.io/react/docs/conditional-rendering.html
Single line example
{(this.state.hello) ? <div>Hello</div> : <div>Goodbye</div>}
or
{(this.state.hello) ? <div>Hello</div> : false}
I often create an explicit function to to this, to avoid clutter in the main render:
var ChildComponent = React.createClass({
render: function () {
return (<p>I am the child component</p>)
}
});
var RootComponent = React.createClass({
renderChild: function () {
if (this.props.showChild === 'true') {
return (<ChildComponent />);
}
return null;
},
render: function () {
return(
<div>
{ this.renderChild() }
<p>Hello World!</p>
</div>
)
}
});
http://reactkungfu.com/2016/11/dynamic-jsx-tags/
For many React developers using JSX it is not clear how to make a
dynamic JSX tag. Meaning that instead of hardcoding whether it is
input or textarea or div or span (or anything else) we would like to
keep it in a variable.

React inline styles, applying styles from state

Using npm-inline-css module, I'm trying to change certain page elements colors, when storing the styles in a state. I set the state here:
setHeaderStyle: function(data){
var headerStyles = this.state.defaultStyles;
if(data) {
headerStyles.backgroundColor = data.first_colour;
headerStyles.color = data.theme;
}
this.setState({
branding: data,
headerStyles: headerStyles
});
},
Then I'm trying to apply the styles to the component:
render: function (){
return (
<div className="our-schools-app">
<InlineCss stylesheet="
& .button {
color: {{this.state.color}};
}
" />
<RouteHandler />
</div>
);
}
But they output like below. How can I set the inline styles? Or a better way I can do this?
<style scoped="" data-reactid=".0.0.1">#InlineCss-0 .button { color: {{this.state.color
}
}
;
}
</style>
From React Docs:
In React, inline styles are not specified as a string. Instead they are specified with an object whose key is the camelCased version of the style name, and whose value is the style's value, usually a string.
It looks like you're most likely trying to set styles for a button that exists in components that are rendered in RouteHandler.
If that's the case, it would make the most sense for you to create a wrapper that wraps the other components and accepts the styles you're trying to set.
For example:
var PageWrapper = React.createClass({
setHeaderStyle: function(data){
var headerStyles = this.state.defaultStyles;
if(data) {
headerStyles.backgroundColor = data.first_colour;
headerStyles.color = data.theme;
}
this.setState({
branding: data,
headerStyles: headerStyles
});
},
render: function () {
var buttonStyle = {
color: this.state.color
}
return (
<RouteHandler buttonStyle={buttonStyle} />
);
}
});
var Index = React.createClass({
render: function () {
return (
<div>
<RouteHandler />
</div>
);
}
});
var Signup = React.createClass({
render: function() {
return (
<div>
<p> Click below to signup now! </p>
<button style={this.props.buttonStyle}>Click Me!</button>
</div>
);
}
});
var Contact = React.createClass({
render: function() {
return (
<div>
<p> Click the button below to contact us </p>
<button style={this.props.buttonStyle}>Email Us!</button>
</div>
);
}
});
var routes = (
<Route path="/" handler={Index}>
<Route path="page" handler={PageWrapper}>
<Route path="signup" handler={Signup} />
<Route path="contact" handler={Contact} />
</Route>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
Edit: Per your request, as an example to show how nested routes would work, I added a Signup and Contact component. If you look at the routes variable you can see how I nested these components under PageWrapper.
Now the nested routes /#/page/signup and /#/page/contact will both get access to the props that are added to the <RouteHandler /> of PageWrapper. Hope this helps!!!!!

ReactJS: onClick change element

I've just started learning React and have a question.
I want to do the following:
If a user clicks on a paragraph I want to change the element to an input field that has the contents of the paragraph prefilled.
(The end goal is direct editing if the user has certain privileges)
I'm come this far but am totally at a loss.
var AppHeader = React.createClass({
editSlogan : function(){
return (
<input type="text" value={this.props.slogan} onChange={this.saveEdit}/>
)
},
saveEdit : function(){
// ajax to server
},
render: function(){
return (
<header>
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<h1>{this.props.name}</h1>
<p onClick={this.editSlogan}>{this.props.slogan}</p>
</div>
</div>
</div>
</header>
);
}
});
How can I override the render from the editSlogan function?
If I understand your questions correctly, you want to render a different element in case of an "onClick" event.
This is a great use case for react states.
Take the following example
React.createClass({
getInitialState : function() {
return { showMe : false };
},
onClick : function() {
this.setState({ showMe : true} );
},
render : function() {
if(this.state.showMe) {
return (<div> one div </div>);
} else {
return (<a onClick={this.onClick}> press me </a>);
}
}
})
This will change the components state, and makes React render the div instead of the a-tag. When a components state is altered(using the setState method), React calculates if it needs to rerender itself, and in that case, which parts of the component it needs to rerender.
More about states
https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
You can solve it a little bit more clear way:
class EditableLabel extends React.Component {
constructor(props) {
super(props);
this.state = {
text: props.value,
editing: false
};
this.initEditor();
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
initEditor() {
this.editor = <input type="text" defaultValue={this.state.text} onKeyPress={(event) => {
const key = event.which || event.keyCode;
if (key === 13) { //enter key
this.save(event.target.value)
}
}} autoFocus={true}/>;
}
edit() {
this.setState({
text: this.state.text,
editing: true
})
};
save(value) {
this.setState({
text: value,
editing: false
})
};
componentDidUpdate() {
this.initEditor();
}
render() {
return this.state.editing ?
this.editor
: <p onClick={this.edit}>{this.state.text}</p>
}
}
//and use it like <EditableLabel value={"any external value"}/>;

Categories

Resources