Is there a way to make reactjs render custom attributes on an HTML element?
I am developing this app with node webkit using react, and i need to add webkitdirectory and mozdirectory attributes to an file type input element to be able to select directories.
thanks
Custom HTML Attributes from JSX Gotchas.
If you pass properties to native HTML elements that do not exist in the HTML specification, React will not render them. If you want to use a custom attribute, you should prefix it with data-.
If it's essential that you use an attribute that isn't prefixed with data-, you'll have to add it yourself using the DOM API inside your component.
giveCustomAttributes: function(input) {
input.setAttribute('webkit-directory', '');
input.setAttribute('moz-directory', '');
},
render: function() {
return (
<input type='file' ref={giveCustomAttributes} />
);
}
If you want a more declarative approach you could move this behaviour into a mixin, in order to share it between components.
function CustomAttrsMixin(refName, attrs) {
return {
componentDidMount: function() {
var attrNames = Object.keys(attrs),
element = this.refs[refName];
attrNames.forEach(function(attrName) {
element.setAttribute(attrName, attrs[attrName]);
});
}
};
}
Then call the function with the appropriate values to create the mixin itself.
mixins: [CustomAttrsMixin('input', {
'webkit-directory': '',
'moz-directory': ''
})],
render: function() {
return (
<input type='file' ref='input' />
);
}
mixins is not supported in ES6 of ReactJS.
I use this code
componentDidMount(){
var input = ReactDOM.findDOMNode(this.refs.customAttributes)
input.setAttribute('webkitdirectory', '')
input.setAttribute('directory', '')
input.setAttribute('multiple', '')
}
and
<input type='file' ref='customAttributes'/>
to upload a whole folder
Related
I am new to React and I am using React v0.13.3 and JSXTransformer v0.13.3 to create a couple of simple components, each of which renders an input field along with a button inside a paragraph. When any button is clicked, I want to show the associated input value using an alert. I am trying to use refs to get the value, but for some reason it is not working, and shows undefined.
Here is my code:
var CommentBox = React.createClass({
show: function() {
alert(this.refs.test.value);
},
render: function() {
return(<p><input type="text" ref="test" /><button type="button" onClick={this.show}>Show</button></p>);
}
});
React.render(<div><CommentBox /><CommentBox /></div>, document.getElementById('commentbox'));
I would suggest to bind onChange of the input to set the value on the state, like so:
<input onChange={event => this.setState({value: event.target.value})} />
Now this.state.value always has the current value of the field. Then on the show function, just do:
show: function() {
alert(this.state.value);
}
Your code is working just fine! I put it in a jsfiddle.
However, that's not a good approach for your specific use-case. In general, you must try not to overuse refs. Here's a quote from the ReactJS related docs:
Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy.
So, here is a better approach:
For similar purposes, just like the one you need, using a controlled component is the preferred way. I suggest you to consider using your Component state.
Therefore, here's an example how you can achieve the same result, using the Component state. I am using your code snippet as a base:
var CommentBox = React.createClass({
getInitialState() {
return {
// That's the default input value
value: ''
};
},
show: function() {
alert(this.state.value);
},
handleChange: function(event) {
// Each time the input's value is changed, the state gets an update
this.setState({
value: event.target.value
});
},
render: function() {
return(
<p>
<input onChange={this.handleChange} type="text" />
<button type="button" onClick={this.show}>Show</button>
</p>
);
}
});
React.render(
<div><CommentBox /><CommentBox /></div>,
document.getElementById('commentbox')
);
I am having problems with select tag implementation in React.js.
Here is what I have:
var ProfessorsFilter = React.createClass({
getInitialState: function(){
return(
{
visibleDepartments: [],
selectedSchoolId: 1
}
)
},
selectSchool: function(event){
console.log("select school");
alert("select ");
this.setState({selectedSchoolId: event.target.value});
},
render: function () {
var schoolOptions = this.props.schools.map(function(school, index){
return (
<option key={index} value={school.id}>{school.name}</option>
);
});
return(
<select onChange={this.selectSchool} value={this.state.selectedSchoolId} className="select-2">
{schoolOptions}
</select>
)
}
});
So, I am doing controlled component. But onchange does not fire my method selectSchool.
EDIT:
jsfiddle: https://jsfiddle.net/wc02bvaj/
BTW. I am also using select2.
EDIT2: It turned out to be problem with select2.
If you're using jQuery along with React on the same DOM elements it will generally cause problems. Either leave that unmanaged by React, use a React equivalent and remove jQuery, or in this case, you have a few options.
The easiest options is to just use https://github.com/rkit/react-select2-wrapper.
Alternatively you could roll your own solution, e.g.,
Select2 has an change callback on its own. If you're using Redux (it doesn't look like you are) you could change the state by dispatching an action from the Select2 change handler. You might be able to listen to the jQuery Select2 change event by registering a handler in your ProfessorsFilter and setting the state there.
Is there any append, Prepend and toggle functions available in reactjs like functions available in jQuery. If not how to do that.
And also, Is there any tutorials or live online classes available for reactjs other than http://facebook.github.io/react/?
This is not a React way. Instead, you can render your components conditionally based on your state and props:
render: function(){
var conditionalComponent = this.state.needToDisplayAdditionalText ? <b>Appended text</b> : null;
return (
<p>
{conditionalComponent}
</p>
);
}
I am new to ReactJs. From the examples, I can see that one needs to call
React.render(elementToBeReadered, targetingElement). Is there a way to use the web components defined in React directly, like angularjs' directive? E.g.
<Hello />
var Hello = React.createClass({
render: function() {
return (
<div>
Hello World!
</div>
);
}
});
So that I don't need to add a target element like <div id='target-element'></div> and then render it with React.render(<Hello />, document.getElementById('target-element')). Why should I duplicate this everywhere?
You'll typically nest react components within each other. In angular, this would be similar to having many ng-app on many different elements.
If you want to have regular DOM, with react components only sparsely populated, then you'll have to render by element reference as you said. I would try to use react components to compose the entire app instead.
Is there a way to use the web components defined in React directly, like angularjs' directive?
Sure, you can build any system you like on top of React.render. You give it a react element and a dom node, and it does its thing. You could build an angular directive that renders the component you like, for example:
var reactComponents = {Foo: Foo};
module.directive('react', function($parse){
return {
link: function(scope, element, attrs){
var props = Object.keys(attrs).reduce(function(props, key){
if (key === "component") return props;
props[key] = $parse(attrs[key])(scope);
return props;
}, {});
var reactElement = React.createElement(reactComponents[attrs.component], props);
React.render(reactElement, element);
}
};
});
not tested
And in your template:
<react component="Foo" bar="1" baz="something.otherThing"></react>
If you add some watchers it'll respond to expressions changing, and you can do other things like error handling, resolving the component class with $injector rather than a static object hash, and handling '$destroy' (see React.unmountComponentAtNode).
I'd like to add a bit of functionality to some existing server-rendered HTML. Let's say I have a form:
<form>
<input type="checkbox" /> Show details
<div class='details'>
<input type="text" name="first_name" />
<input type="text" name="last_name" />
</div>
</form>
The HTML is already generated on the server. I'm wondering, can I use a React component to, say, add/remove a hide class to the .details div whenever the checkbox is checked and unchecked?
I don't want React to re-render the form, since the rest of the page is already handled by the server.
There is a solution but I don't know if it is efficient :
You can use the dangerouslySetInnerHTML to create a wrapper over your existing DOM elements.
Consider for example you want to add a swapper on two already existing div elements (https://jsfiddle.net/gdoumenc/a86g58qz/):
// a wrapper just rendering the previous DOM children
var Wrapper = React.createClass({
render: function() {
return <div dangerouslySetInnerHTML={{__html: this.props.html}}/>;
}
});
// a simple swapper
var Swapper = React.createClass({
getInitialState: function() {
return {swap: false};
},
onClick: function() {
this.setState({swap: !this.state.swap});
},
replace: function(id) {
if (!(id in this)) {
var node = document.getElementById(id);
var elt = document.createElement(node.tagName);
elt.appendChild(node.childNodes[0]);
this[id] = elt.innerHTML;
}
return this[id];
},
render: function() {
// replace here the elements par wrapped ones
box1 = <Wrapper html={this.replace('box1')}/>;
box2 = <Wrapper html={this.replace('box2')}/>;
if (this.state.swap) {
content = [box1, box2];
} else {
content = [box2, box1];
};
return <div>
{content}<button onClick={this.onClick}>Swap</button>
</div>;
}
});
`
Check server-rendering React example. You can see there that PHP script is getting React render result from node.js and returns it to client and then the same React component is attached to DOM for further modification.
If you want to have HTML rendered on server side and then handled by React that's the best approach. Otherwise you will need to write templates twice: in React and your server side template engine.