How to Append and Prepend element in react js like jquery - reactjs

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>
);
}

Related

React select onchange doesn't work

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.

ReactJS component rendering and how to append elements to the div the component is mounted on

I'm having this use case where there is a 'load more' button on the page to fetch more items from an API endpoint, and so I want these items to get appended to the DOM when they arrive. The thing is that the HTML page that is served by the web server comes with some extra list items (as seen below) within the same item-list div container I mount my React component, with empty data/props, on page load.
<div class="item-list">
<div class="item-list__child-item"></div>
<div class="item-list__child-item"></div>
...
<div class="item-list__child-item"></div>
</div>
My assumption is that if I handle this in the ReactJS way, as soon as I fetch more items from the server (REST) and append those items to an 'itemList' state array, react will somehow replace all of the content that holds that 'item-list' div where the component was mounted on.
A quick workaround that I'm thinking would work and that it doesn't rely on the isomorphic stuff and pre-rendering the react component on the server, is to create a separate sibling div having the same div class name 'item-list' and adding an id attribute to mount the component on, so the resulting HTML would go like:
<div class="item-list">
<div class="item-list__child-item"></div>
<div class="item-list__child-item"></div>
...
<div class="item-list__child-item"></div>
</div>
<div class="item-list" id="react-component-name"></div>
Maybe there is a cleaner way to do it without getting into the isomorphic stuff, or maybe I'm not understanding the React concept and how it works. Anyways will appreciate any directions you may have on this.
OK, your question wasn't clear on this, but the data that is represented by what was generated in the HTML will be entirely different from the data that you will be getting via AJAX.
There's a simple solution to this. Instead of creating an entirely new DOM element that will be adjacent to your original DOM layout, what you will do is grab the data that was already there, store it into an array, and append the new data that you will grab via AJAX into that Array. This way, you will reap the benefit of React's DOM diffing. Why is it useful? Maybe you want to let the user sort the data, or interact with the data directly, while it will remain in full control of a parent React component.
So anyways, take a look at this fiddle: https://jsfiddle.net/x4jjry04/3/. It's based on Paul Booblic's fiddle.
var Page = React.createClass({
getDefaultProps: function () {
return {
items: []
}
},
getInitialState : function(){
return{
items : this.props.items
}
},
componentDidMount: function () {
// Mimics an AJAX call, but replace this with an actial AJAX call.
setTimeout(function () {
var dataFromAjax = ['one', 'two', 'three'];
this.setState({
items: this.state.items.concat(dataFromAjax)
});
}.bind(this));
},
addClick : function(){
this.state.items.push("more");
this.forceUpdate();
},
render : function(){
return <div>{this.state.items.map(function(item){return <div className="bla-bla-class">{item}</div>})}<br/><div onClick={this.addClick}>ADD</div></div>;
}
});
var elements = document.querySelectorAll('.item-list__child-item');
var initialvalues = Array.prototype.slice
.call(elements)
.map(function (div) {
return div.innerHTML;
});
React.render(<Page items={initialvalues} />, document.body);
Check this simple fiddle demo:
https://jsfiddle.net/x4jjry04
var Page = React.createClass({
getInitialState : function(){
return{
items : ["one","two","three"]
}
},
addClick : function(){
this.state.items.push("more");
this.forceUpdate();
},
render : function(){
return <div>{this.state.items.map(function(item){return <div className="bla-bla-class">{item}</div>})}<br/><div onClick={this.addClick}>ADD</div></div>;
}
});
React.render(<Page />, document.body);
I assume you are using react serverside to render the list?
On page load you fetch the original list from the server and have the component "re-render" the elements. re-render is in quotes, because React wont actually update the list unless the list changes. Now you are setup with a component that works as expected, and you can add elements to the list as you want.
The general Idea with isomorphic/universal React is that you treat your app as a normal Single Page App, and let React handle the magic of dirty checking.
This also means that you can use the same component when rendering on the server, since your component doesn't contain any client specific code.

Is there another way to render in ReactJs

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).

react.js component: can't get keyDown events if component inside another one

JS Bin Available here
I have a component called ComponentB for which I want to get key down events:
var ComponentB = React.createClass({
render: function() {
return (
<div
contentEditable
onKeyDown={this.handleKeyDown}>{this.props.data}</div>
);
},
handleKeyDown: function(e) {
console.log("B: " + e.type +"-" + e.which);
}
});
I can get those events if this ComponentB is directly under the main/App component.
If I try to embed this component inside another component (componentA) I don't receive those events anymore (this.props.lines is an array of 3 strings) :
var ComponentA = React.createClass({
render: function(){
return (
<div
contentEditable>
{
this.props.lines.map(function(line,i) {
return <ComponentB key={i} data={line} />
})
}
</div>
);
}
});
The associated JS BIN shows this behavior : if you try to edit the lines in the component A section. no event will be emitted but they will if you edit the sinbgle instance of componentB below...
Looks to me like a bug in react.js but wanted to check here first.
As #ssorallen said in a comment, you can't have nested contentEditable elements, with or without react.
It seems to be a problem with nested contentEditable elements. Remove contentEditable from ComponentA, and it works as you expect.
One of the reasons this doesn't work, is because React doesn't really support contentEditable. Basically it sets the attribute, but it can't sensibly render into the contentEditable because when it tries to update it... the DOM has changed without its knowledge (which throws an error).
Rather you should treat contentEditable elements like an input element, which doesn't have children. Instead you update the innerHTML (see renderComponentToString and dangerouslySetInnerHTML) and listen to onInput events to get changes. See Stack Overflow: onChange event for contentEditable for details on how this works.
A proper handling of contentEditable has been discussed briefly, but no solution was arrived at. Feel free to suggest good ways to handle it.

Rendering templates based on session variable

I am using Meteor, Handlebars, and Backbone to create a multipage application. I have a Router set up using backbone which sets a session variable, currentPage. How can I render a different template depending on the value of currentPage?
I was told that I could create a Template helper function that would do this, but I'm not sure how to approach this.
if currentPage is global and pages are stored as strings, then I would expect this to work:
Handlebars.registerHelper('currentPageIs',function(page){
return currentPage == page;
});
// and in the html:
{{#if currentPageIs '/posts'}}
{{> posts}}
{{else}}
{{> homepage}}
{{/if}}
A really simple solution is here: https://gist.github.com/3221138
But I would strongly recommend installing meteor-router. This will require you to first install meteorite.
Also, know that an official routing solution is on the roadmap.
The best choice would to use Iron-Router, but it you don't want that here is a nice pattern to change the template:
//HTML
<body>
{{>mainTemplate}}
</body>
//JS Client Initially
var current = Template.initialTemplate;
var currentDep = new Deps.Dependency;
Template.mainTemplate = function()
{
currentDep.depend();
return current;
};
function setTemplate( newTemplate )
{
current = newTemplate;
currentDep.changed();
};
//Later
setTemplate( Template.someOtherTemplate );
I don't know how to check for the route but if you can, then you can just use the proposed setTemplate function to change the template conditionally.

Resources