I'm a little weak in javascript.
I'm inspiring myself from this answer to pass a function from parent to child in REACT and I'm having a little difficulty.
Could someone help me correct my code?
Thanks!
var List = React.createClass({
deleting: function(test){
console.log(test);
},
render: function() {
var all = this.props.activities;
var test = List.deleting;
var list = all.map(function(a){
return (<ListItem act={a} del={test}>);
});
return (
<ul> {list}
</ul>
);
}
});
var ListItem = React.createClass({
deleting: function(e){
this.props.del(e.target.parentNode.firstChild.innerHTML);
},
render: function(){
return (
<li key={this.props.act}>{this.props.act}
<div onClick={this.deleting}>X</div>
</li>
);
}
});
The error I get:
You need pass reference to method .deleting that is part of List Object, now you are trying pass var test = List.deleting; that is undefined. In order to this in .map, refers to List, you should set this for .map by yourself - to do that just pass (in our case it should be this because this in render method refers to List) second argument to .map, and pass to del= attribute reference to method this.deleting.
Also set key attribute for ListItem, and in React all tags must be closed - so add /> ( now you are getting error because you have not closed tag ListItem) in the end of ListItem tag
var List = React.createClass({
deleting: function(test) {
console.log(test);
},
render: function() {
var all = this.props.activities;
var list = all.map(function(a) {
return (<ListItem key={a} act={a} del={this.deleting} />);
}, this);
return <ul> {list} </ul>
}
});
Example
Related
I used this article as an example (React way), but it is not working for me. Please point me to my mistake, as I can't understand what's wrong.
This is the error I see:
Uncaught TypeError: this.props.onClick is not a function
Here is my code:
// PARENT
var SendDocModal = React.createClass({
getInitialState: function() {
return {tagList: []};
},
render: function() {
return (
<div>
{
this.state.tagList.map(function(item) {
return (
<TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/>
)
})
}
</div>
)
},
HandleRemove: function(c) {
console.log('On REMOVE = ', c);
}
});
// CHILD
var TagItem = React.createClass({
render: function() {
return (
<span className="react-tagsinput-tag">
<span>{this.props.nameProp}</span>
<a className='react-tagsinput-remove' onClick={this.HandleRemove}></a>
</span>
)
},
HandleRemove: function() {
this.props.onClick(this);
}
});
Thanks in advance!
The issue is that this inside the map callback does not refer to the React component, hence this.HandleRemove is undefined.
You can set the this value explicitly by passing a second argument to map:
this.state.tagList.map(function() {...}, this);
Now this inside the callback refers to the same value as this outside the callback, namely the SendDocModal instance.
This has nothing to do with React, it's just how JavaScript works. See How to access the correct `this` context inside a callback? for more info and other solutions.
Try the following:
var SendDocModal = React.createClass({
getInitialState: function() {
var item = {};
item.Name = 'First';
item.Id = 123;
var item2 = {};
item2.Name = 'Second';
item2.Id = 123456;
return {tagList: [item,item2]};
},
HandleRemove: function(c){
console.log('On REMOVE = ', c);
},
render: function() {
return (<div>
{this.state.tagList.map(function(item){
return(
<TagItem nameProp={item.Name} idProp={item.Id} key={item.Id} click={this.HandleRemove}/>
)}, this)}
</div>
)
}
});
// CHILD
var TagItem = React.createClass({
handleClick: function(nameProp)
{
this.props.click(nameProp);
},
render: function(){
return(
<span className="react-tagsinput-tag" ><span onClick={this.handleClick.bind(this, this.props.nameProp)}>{this.props.nameProp}</span><a className='react-tagsinput-remove' ></a></span>
)
}
});
Few changes:
Added 'this' after the tagList mapping. To be honest I am not entirely sure why - perhaps a more experienced programmer can tell us.
Added a key to each TagItem. This is recommended and an the console will inform you that you should do this so that if the state changes, React can track each item accordingly.
The click is passed through the props. See React js - having problems creating a todo list
I am trying to get a DOM node ref from a dynamic object but I am getting the following error in the Chrome console:
Uncaught TypeError: Cannot read property 'getDOMNode' of undefined.
https://jsfiddle.net/ux4rL8sf/6/
var Hello = React.createClass({
getInitialState: function () {
return {
currentItems : [{"id":"1"} , {"id":"2"} , {"id":"3"}]
};
},
onRowClick: function (i) {
var x;
if (i == 'abs') {
x = this.refs[i].getDOMNode().scrollHeight;
} else {
x = this.refs['row' + i].getDOMNode().scrollHeight;
}
alert(x);
},
render: function() {
var Items = this.state.currentItems.map(function(tv) {
return (<div refs={"row" + tv.id} onClick={this.onRowClick.bind(this, tv.id)} > {tv.id}</div>);
}.bind(this)
);
return (<div> {Items} <div ref="abs" onClick={this.onRowClick.bind(this, 'abs')}>Test </div> </div>) ;
}
}
);
React.render(<Hello />, document.getElementById('container'));
In the callback you provide to map when creating the Items variable in your render method, you have
return (<div refs={...
I think you want
return (<div ref={...
instead.
On line 22 of your fiddle, you use refs instead of ref. I think that should fix your problem.
I want to remove an object from an ko.observableArray
I have two observableArrays
self.arrayA = ko.observableArray();
self.arrayB = ko.observableArray();
then in a function I want to remove an item.
self.myRemoval = function(item){
var arrayToRemoveFrom;
if ( somelogic ) {
arrayToRemoveFrom = self.arrayA();
}
else {
arrayToRemoveFrom = self.arrayB();
}
arrayToRemoveFrom.remove(item);
}
The line "arrayToRemoveFrom.remove(item)" causes an exception, saying remove is not a function. What would be the best way to remove "item"?
remove is a special function of the ko.onservableArray .
However when you write self.arrayA(); with the () at the end you are returning the underlaying JavaScript array which does not have a remove function and you get the exception.
To fix your code you just need to remove the ():
self.myRemoval = function(item){
var arrayToRemoveFrom;
if ( somelogic ) {
arrayToRemoveFrom = self.arrayA;
}
else {
arrayToRemoveFrom = self.arrayB;
}
arrayToRemoveFrom.remove(item);
}
How to write this without using JSX?
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});
This comes from the react.js tutorial: http://facebook.github.io/react/docs/tutorial.html
I know I can do the following:
return (
React.createElement('div', { className: "commentBox" },
React.createElement('h1', {}, "Comments")
)
But this only adds one element. How can I add more next to one another.
You can use the online Babel REPL (https://babeljs.io/repl/) as a quick way to convert little chunks of JSX to the equivalent JavaScript.
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement("div", {className: "commentBox"},
React.createElement("h1", null, "Comments"),
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
)
);
}
});
It's also handy for checking what the transpiler outputs for the ES6 transforms it supports.
insin's answer is the direct translation, however you may prefer to use factories.
var div = React.createFactory('div'), h1 = React.createFactory('h1');
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
div({className: "commentBox"},
h1(null, "Comments"),
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
)
);
}
});
createFactory essentially partially applies createElement. So the following are equivalent:
React.createElement(c, props, child1, child2);
React.createFactory(c)(props, child1, child2);
If you're just using es6 but aren't fond of JSX you can make it less verbose with destructuring assignment. See this jsbin for an interactive example using 6to5 instead of jsx.
var [div, h1, commentForm, commentList] = [
'div', 'h1', CommentForm, CommentList
].map(React.createFactory);
if you have a variable number of children then you can use that:
Using apply function which take an array of parameters.
React.createElement.apply(this, ['tbody', {your setting}].concat(this.renderLineList()))
where renderLineList is for instance:
renderLineList: function() {
var data=this.props.data;
var lineList=[];
data.map(function(line) {
lineList.push(React.createElement('tr', {your setting}));
});
return lineList;
}
You just add them one after another as children to your parent component,
return React.createElement("div", null,
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
);
I had this problem, it took a while to solve by stepping through the interpreter source code:
var arrayOfData = [];
var buildArray = (function () {
var id;
var name;
return{
buildProc(index, oneName){
id = index;
name = oneName;
arrayOfData[index] = (React.createElement('Option', {id},name));
}
}
})();
// then
this.state.items = result;
var response = parseJson.parseStart(this.state.items);
var serverDims = response.split(":");
for (var i = 1; i < serverDims.length; i++) {
buildArray.buildProc(i, serverDims[i] )
}
// then
render(){
const data = this.props.arrayOfData;
return (
React.createElement("select", {},
data
)
// {data} Failed with "object not a valid React child, data with no curly's worked
)
}
I'm trying to get to know Angular a bit. In particular, I want to create a hierarchical data structure, that can be manipulated using a hierarchical view:
Root:
- addChild
- child 1: { remove, addChild, child1, child2, ...}
- child 2: { remove, addChild, child1, child2, ...}
....
(real code at http://jsfiddle.net/xtofl/n3jqM/12)
At the moment I try to stop at 2 levels, i.e. the Root has children and grandchildren.
The grandchildren's 'remove' button does trigger the child.remove(grandchild) function. However, the removal of the element does not result in rows being removed :(
I don't manage to understand why. On top of that, the example at the fiddle seems to add 4 grandchildren at once.
The relevant code:
function Controller($scope) {
$scope.nextChildIndex = 1;
$scope.addChild = function () {
$scope.children.push(makeChild($scope.nextChildIndex++));
};
$scope.removeChild = function (child) {
$scope.children.remove(child);
};
$scope.children = [];
}
var makeChild = function (i) {
var nextIndex = 1;
var ret = {
index: i,
children: []
};
ret.addChild = function () {
ret.children = makeChild(nextIndex++);
};
ret.removeChild = function (child) {
ret.children.remove(child);
};
return ret;
};
The relevant html:
<ul ng-repeat="grandchild in child.children">
<li class="grandchild">
<button ng-click="child.removeChild(grandchild)">-grandchild</button>
<span>child {{grandchild.index}}</span>
</li>
</ul>
Question: what is so wrong about this makeChild function that an ng-click="addChild()" call adds 4 li elements at once, and that the ng-click="child.removeChild(grandchild)" does not result in grandchildren to be removed?
you problem is not in AngularJS
it was mistake with Array.prototype.remove
it should be
Array.prototype.remove = function (element) {
var index = this.indexOf(element);
this.splice(index,1 );
};
updated fdl - http://jsfiddle.net/STEVER/n3jqM/13/
UPD:
and instead of
ret.children = makeChild(nextIndex++);
you should do
ret.children.push(makeChild(nextIndex++));
http://jsfiddle.net/STEVER/n3jqM/14/
enjoy ;)