Using x-editable with reactjs, how to call editable function on items? - reactjs

I am new to ReactJS, I am trying to create a Reactjs component that is a list of editable fields using x-editable.
According to x-editable documentation I need to call .editable() for each field, normally this is done accessing the element with jQuery.
How can I do it with React ? It has to be done when the component is mounted and I can't find a way to know when the component is rendered...
I would like to know the best way to achieve this ; I had a look at React refs but I am not sure it can help. So I ended up giving it a specific class, then using a selector
to call editable() on the fields, but it works only when the rendering has been done
and I don't find it very elegant.
JS(X) code:
var EditableField = React.createClass({
render: function() {
return <p>{this.props.name}: {this.props.value}</p>
}
});
in script code:
$(document).ready(function() {
$.fn.editable.defaults.mode = 'inline';
$(".editable_field").editable();

You should do it in the componentDidMount function. This function is called when the component is mounted and the DOM is ready. Read more about the lifecycle here: http://facebook.github.io/react/docs/component-specs.html
Example (using refs instead of class selector):
var EditableField = React.createClass({
componentDidMount: function() {
$(this.refs.editable.getDOMNode()).editable()
},
render: function() {
return <p>{this.props.name}: {this.props.value}</p>
}
});
Note that many "jquery plugins" will do heavy DOM manipulations and that does not always play well with React.

You can use react-x-editable(react version of x-editable).Currently not all option supported.I will try to support most of options.

Related

ReactJS: best practice access input values when creating forms

I've been playing a bit with ReactJS and am really enjoying the framework.
I'm also trying to follow the rule of creating components that are stateless where possible.
I have a Settings component that includes a child SettingsForm and a SettingsWidget.
Settings holds all the states, and only pass it as props to the form and widget.
This works (and scales) well because when the state in Settings is updated, it propagates to all child components.
var Settings = React.createClass({
getInitialState: function() {
settings: {}
}
})
What I am not 100% sure on is the best practice when accessing input values on SettingsForm to pass it on to the parent component.
I know I can use refs and also two-way binding to accomplish this, but neither feel very "ReactJS-like".
Is there a better of way accomplishing this that I am unaware of? For the sake of completeness, I've included the relevant code in my SettingsForm component below
var SettingsForm = React.createClass({
getInitialState: function() {
return {
changed: false
}
},
handleChange: function(event) {
this.setState({changed: true})
this.props.handleChange(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
},
handleSubmit: function(event) {
event.preventDefault();
// Access and pass on input values to parent callback so state is updated
this.props.handleUpdate(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
this.setState(this.getInitialState());
},
...
}
For now there is a Mixin you can use to link the input values to the state, called LinkedStateMixin that is exactly what you are looking for...
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
Then all you have to do is modify your handler functions on the parent component to take your inputs as variables, and pass that function down to the child component as a prop. When you want to handle the form, call that function in the props and send the state (bound with from the Mixin) as the variables.
React Docs - React Link

Is there a way to hook ReactJS onto dynamic elements from backbone?

Is there away to make React.render() not get called until backbone view has been rendered. Because that generates the dynamic DOM element that React.render is going to hook on?
Is there any "beautiful" way to this?
Call React.render in the render method of your view, and call React.unmountComponentAtNode in its remove method.
var ReactView = Backbone.View.extend({
render: function() {
React.render(<MyComponent />, this.el);
return this;
},
remove: function() {
React.unmountComponentAtNode(this.el);
Backbone.View.prototype.remove.apply(this, arguments);
},
});
In your case, you would probably not directly render in this.el, but select an child element to render into via jQuery or DOM APIs.

Global React does not play nice with AMD React

I'm getting weird weird behaviour when rendering a component using an AMD-loaded React, when a global React already exists on the page. Click events on components are getting fired when they should not be.
A look at the DOM implies that this stems from multiple React instances (one global, one AMD in my case) not being aware of each other, but this poses a problem when loading an AMD module at runtime that depends on React, into a page that also includes React.
How can I resolve this clash?
Reproduction
I can make a component like this:
var ButtonComponent = React.createClass({
onButtonClick: function(){
alert(this.props.data + ' click event fired');
},
render: function() {
return React.DOM.button({onClick: this.onButtonClick}, this.props.data);
}
});
(function(){ // create vanilla
var ButtonList = React.createClass({
render: function() {
return React.DOM.div({}, React.createElement(ButtonComponent, {data: this.props.data}));
}
});
React.render(React.createElement(ButtonList, {data: 'button that was loaded by the page'}), document.getElementById('page-load-target'));
})();
jsbin
But as soon as I add another component using another instance of React then click the first button, then it calls the click event on the second loaded button:
// .... as above ....
(function(){ // create using amd
require.config({
paths: {
'react': '//fb.me/react-with-addons-0.12.2.min'
}
});
window.setTimeout(function(){
require(['react'], function(ReactFromAmd){
ReactFromAmd.render(ReactFromAmd.createElement(ButtonComponent, {data: 'button that was loaded by AMD'}), document.getElementById('amd-load-target'));
});
}, 1000)
})();
jsbin
If I use the existing, global version of React in this call (rather than ReactFromAmd, then it works as expected. jsbin
The ancestors (React instance) of ButtonComponent and the component created with ReactFromAmd.createElement are different, and yet they are in the same virtual DOM -- That's not allowed.
If you don't mind replacing AMD with browserify, I just figured out a way to let isolated/remotely-loaded React components co-exist nicely.
(To be continued if someone needs it)
This has been fixed in version 0.14.2: http://jsbin.com/tesodoxape/1/edit?html,js,output

Setting the initial state in React components for progressive enhancement & Flux architecture

I've read on http://scotch.io/tutorials/javascript/build-a-real-time-twitter-stream-with-node-and-react-js and it describes a technique of taking over server rendered React components seamlessly:
Server renders into {{{markup}}} in handlebars, and pass initial state.
<section id="react-app">{{{ markup }}}</div>
<script id="initial-state" type="application/json">{{{state}}}</script>
Then on the client side javascript
/** #jsx React.DOM */
var React = require('react');
var TweetsApp = require('./components/TweetsApp.react');
// Snag the initial state that was passed from the server side
var initialState = JSON.parse(document.getElementById('initial-state').innerHTML)
// Render the components, picking up where react left off on the server
React.renderComponent(
<TweetsApp tweets={initialState}/>,
document.getElementById('react-app')
);
But in a flux architecture, such as described in this article http://scotch.io/tutorials/javascript/creating-a-simple-shopping-cart-with-react-js-and-flux, state is initialized in the getInitialState lifecycle method:
// Method to retrieve state from Stores
function getCartState() {
return {
product: ProductStore.getProduct(),
selectedProduct: ProductStore.getSelected(),
cartItems: CartStore.getCartItems(),
cartCount: CartStore.getCartCount(),
cartTotal: CartStore.getCartTotal(),
cartVisible: CartStore.getCartVisible()
};
}
// Define main Controller View
var FluxCartApp = React.createClass({
// Get initial state from stores
getInitialState: function() {
return getCartState();
},
// Add change listeners to stores
componentDidMount: function() {
ProductStore.addChangeListener(this._onChange);
CartStore.addChangeListener(this._onChange);
},
// Remove change listers from stores
componentWillUnmount: function() {
ProductStore.removeChangeListener(this._onChange);
CartStore.removeChangeListener(this._onChange);
},
// Render our child components, passing state via props
render: function() {
return (
<div className="flux-cart-app">
<FluxCart products={this.state.cartItems} count={this.state.cartCount} total={this.state.cartTotal} visible={this.state.cartVisible} />
<FluxProduct product={this.state.product} cartitems={this.state.cartItems} selected={this.state.selectedProduct} />
</div>
);
},
// Method to setState based upon Store changes
_onChange: function() {
this.setState(getCartState());
}
});
module.exports = FluxCartApp;
Which one is the right approach to setting state from a progressive enhancement point of view?
Thinking about progressive enhancement I like how flux and react work together.
I am using ReactJS and Flux in my current project and everything is clean and easy. All you have to be aware of is showing some discipline of creating new stores when it really is needed. I dont really like the eventEmitter stuff though. I just trigger my own events which I define in a seperate eventConstants.js file this allows me to have several components listening for different changes on the same store.
This really scales well.
Answering your question:
It does depend about your usecase. Ignoring that rendering an initial page on the server is great for SEO it does only make sence to render on the server if users should all see pretty much the same content. I like to keep client stuff on the client.
I hope this helped you

AngularJS app inside ReactJS component?

Is it possible to create an Angular app inside a react component?
Something like:
React.createClass({
render: function() {
return <div ng-app>...</div>;
}
});
This is completely backwards, but will only have to be a temporary solution. I'm assuming I could do something like the code above, and add the angular bootstrapping to the componentDidMount lifecycle method.
Has anyone successfully done this?
Thanks.
It would look something like this:
componentDidMount: function(){
this._angularEl = document.createElement("div");
this._angularEl.innerHTML = angularTemplatHTMLString;
this._angularEl.setAttribute("ng-app", "");
this.getDOMNode().appendChild(this._angularEl);
// bind angular to this._angularEl
},
componentWillUnmount: function(){
// unbind angular from this._angularEl
this.getDOMNode().removeChild(this._angularEl);
delete this._angularEl;
},
render: function(){
return <div></div>
}
You could either use this for each component, or create a function which returns a mixin.
function makeAngularMixin(template){
return { /* above code except for render */ }
}
or have a component which allows passing an angular template via props.

Resources