[UPDATE July 23 2015]
I want to create a list of buttons, one for each marker
in ctrl.getMarkers()
. Let's assume a marker is something like
marker: {'title':' '}
.
Using the classic ng-repeat, I have the following
<div ng-repeat="marker in ctrl.getMarkers()" >
<button class="btn btn-default"
ng-click = "doSomething(marker)"
ng-style="ctrl.isRed() ? {color:red} : {color:black}">
<b> {{::marker.title}}</b>
</button>
</div>
I have about 100 buttons to show, but the update is not fast at all. So I want to try the ng-react library. Unfortunately I haven't well understood how to use it.
So far, I wrote this:
HTML
<poi-list list="ctrl.getMarkers()" />
JS
/** @jsx React.DOM */
.value( "PoiList", React.createClass( {
propTypes : {
list: React.PropTypes.object.isRequired
},
getDefaultProps: function() {
return { list: [] };
},
render: function()
{
var markers = this.props.list.map( function( marker, i )
{
return React.DOM.button({className:'btn btn-default'
/*ng-click? ng-class?*/
}, marker.title) ;
} );
return React.DOM.div(null, markers);
}
}))
.directive( 'poiList', function( reactDirective ) {
return reactDirective( 'PoiList' );
} );
How could I use ng-click
, ng-class
etc with the React DOM element?
Here's the JSFiddle
[UPDATE 2]
I found a solution and I've answered my own question below. However I've got still a problem slowing down react: "Deprecated attempt to access property 'nodeType' on a non-Node object". Please, look at my answer below for further info about the error. Thank you
I figured out how to (almost) solve my problem. I pass the controller as attribute of the react element, so I can invoke its functions. Like this:
HTML
<poi-list list="ctrl.getMarkers()" ctrl="ctrl"/>
JS
.value( "PoiList", React.createClass( {
propTypes : {
list: React.PropTypes.object.isRequired,
ctrl: React.PropTypes.object.isRequired
},
render: function()
{
var ctrl = this.props.ctrl; // directive's Controller
var markers = this.props.list.map( function( marker, i )
{
return React.DOM.button( {
className:'btn btn-default',
onClick: function(){ctrl.doSomething(marker);},
onMouseOver: function(){ctrl.doSomethingElse(marker);},
}, marker.title
) ;
} );
return React.DOM.div(null, markers);
}
}))
.directive( 'poiList', function( reactDirective ) {
return reactDirective( 'PoiList' );
} );
It works!! JSFiddle
[UPDATE 1]
Anyway.... in my real application it's terrible slow... much slower then ng-repeat. I don't know why. Looking at the console, I have a bunch of error "Deprecated attempt to access property 'nodeType' on a non-Node object"
from angular.js:328, and I guess this is the reason of the slow performance. I don't know what's the problem, and I don't have this error in the JSFiddle... any help?
This is the piece of Angular code that rises the error:
function forEach(obj, iterator, context) {
var key, length;
if (obj) {
if (isFunction(obj)) {
for (key in obj) {
// Need to check if hasOwnProperty exists,
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
iterator.call(context, obj[key], key, obj);
}
}
/*---->*/ } else if (isArray(obj) || isArrayLike(obj)) {// <---ERR
var isPrimitive = typeof obj !== 'object';
for (key = 0, length = obj.length; key < length; key++) {
if (isPrimitive || key in obj) {
iterator.call(context, obj[key], key, obj);
}
}
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context, obj);
} else {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
iterator.call(context, obj[key], key, obj);
}
}
}
}
return obj;
}
[UPDATE 2]
I figured out that the problem was the array of complex objects passed to the React Element. It's impossible for React making comparison between old and new object, resulting in slowness and errors. This is the explanation of this problem and the solution.