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

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.

Related

Is there a way to re-render child view on any custom JQuery event in Backbone/Marionette?

I want to re-render my child view that is being rendered in a composite view on $(window).resize() event which I have subscribed in onShow() of my composite view. Can we do do that? if yes, is there a preferred way? I want to something like this:
define([
"app",
"views/list-item",
], function(App, ListItem) {
var List= App.CompositeView.extend({
template: "list",
childViewContainer: ".list-items",
childView: ListItem,
onShow: function() {
$(window).on('resize', function() {
//re-render child View(ListItem)
});
}
});
return List;
});
According to this PR CompositeView has a renderChildren method, depending n your version of marionette. If it is old it might be private _renderChildren.
Side note: having global selectors and events inside a view is bad practice. I'd put that logic in a separate script outside of the view.
You can implement 'modelEvents' in parent view. On change of 'modelEvents' call render method which will re-render the view. For example:
"modelEvents" :{
"change:updateView": "render"
}
And toggle the 'updateView' model to call this event.

Backbone View overriding the render function loses childviews

I'm trying to run some code to resize a div after my header is done rendering. I have looked at answers here and the Backbone documentation. this is what I wrote:
Backbone.View.extend({
template: header_tpl,
render: function() {
this.$el.html(this.template({});
setTimeout(function() {
$(window).on("resize",function(){
$(".somediv").height($(".someotherdiv").height())
})
.resize()
}, 0);
return this;
},
childViews: {
// Some childViews in here
}
});
This works, but the childViews in this view won't render. I think it has to do with the empty object being passed on the this.template(). The backbone docs say to pass on this.model.attributes, but this view doesn't have a model. Its a simple header with no data being passed on to it.
As pointed out by #CoryDanielson 's comment, Backbone has no default handling of "childViews". If your job is to make a Backbone View render it's child Views, there are lots of reasonably simple ways to do that.
But I think what you are really trying to do is to keep some sort of pre-built render functionality that is built into Backbone.View somewhere else in your codebase. Since the only extension you seem to need is attaching a resize event to window, maybe the best option is to not do this in the render method, then you can continue to use whatever is pre-built elsewhere in your codebase.
Backbone.View.extend({
template: header_tpl,
// no override of render
initialize: function() {
setTimeout(function() {
$(window).on("resize",function(){
$(".somediv").height($(".someotherdiv").height())
})
.resize()
}, 0);
},
childViews: {
// Some childViews in here
}
});
This code should attach the event when the view is instanced, not at each render.
Of course, if your Codebase may also be altering the default initialize method, we really can't know. In that case, there might be some options to override the default methods (initialize, render, ...) just by extending, but still calling the old methods under the hood.

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

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.

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.

backbone boilerplate render view issue

I am using the backbone-boilerplate/backbone-layoutmanager, and I am having issues re-rendering the view after calling place.fetch(). It seems to work fine the first time, but when I do fetch the second time, the "render" method is not getting called anymore.
Any hints would be helpful
thanks
pete
ROUTER
test: function() {
var place = new Place.Model({
place_id: place_id,
});
place.fetch().complete(function(){
app.useLayout("main").setViews({
".place-detail": new Place.Views.Show({
model: place
})
}).render();
});
}
VIEW
initialize: function() {
_.bindAll(this, "render");
this.model.on("change", this.render, this);
}
render: function(manage) {
return manage(this).render();
}
fetch is an async function which accepts an object with a success or error handler which will be called on completion. AFAIK fetch does not support the jQuery method of chaining with a complete handler, so you need to pass it an object with the proper success method set up if you want it called on completion.

Resources