I am using react with my meteor app and I need to integrate this with a list of items.
There is a ItemList.jsx and a ItemRow.jsx since the item itself has text, links, images, ect.
ItemRow.jsx
ItemRow = ReactMeteor.createClass({
templateName: "ItemRow",
propTypes: {
item: React.PropTypes.object.isRequired,
showPoolTitle: React.PropTypes.bool,
},
getInitialState: function() {
return {
editing: false,
drop: this.props.item,
pool: {},
}
},
startMeteorSubscriptions: function() {
Meteor.subscribe("ItemRow", this.props.item._id);
},
getMeteorState: function() {
return {
item: Items.findOne(this.props.item._id),
pool: Pools.findOne(this.props.drop.poolId),
};
},
toggleEditing: function() {
this.setState({ editing: !this.state.editing });
},
render: function() {
var content;
if (this.state.editing) {
content = <ItemRowEdit drop={this.state.item} done={this.toggleEditing}/>
} else {
content = <ItemRowShow pool={this.state.pool} item={this.state.item} edit={this.toggleEditing} showPoolTitle={this.props.showPoolTitle}/>
}
return (
<div key={this.props.item._id} className="item">
{content}
</div>
)
},
});
and ItemList.jsx
ItemList = ReactMeteor.createClass({
templateName: "ItemList",
propTypes: {
items: React.PropTypes.object.isRequired
},
getInitialState: function() {
return {
items: this.props.items.fetch()
}
},
render: function() {
var items = this.state.items;
return (
<div className="ui very relaxed huge list">
{items.map(function(item) {
return ( <ItemRow item={item}/> );
})}
</div>
);
}
});
I am not using Meteor react for ItemList just yet but I want to be able to drag and drop reorder first so any help to get me on the right track is much appreciated!
Related
My components looks like:
App.jsx
import MyInput from './MyInput';
const onChangeHandler = (val) => {
console.log(val);
};
export default {
render() {
return (
<MyInput onChange={onChangeHandler} />
);
},
};
and MyInput.jsx
export default {
props: {
onChange: {
type: Function,
},
},
render() {
// as Sphinx suggested it should be this.$props.onChange
return (
<input onChange={this.$props.onChange} />
);
},
};
But this.onChange is undefined:
How to properly use this.onChange prop in MyInput component?
CodePen
Here you can find CodePen with implementation of my problem:
https://codepan.net/gist/13621e2b36ca077f9be7dd899e66c056
Don't start your prop name with on. The 'on' prefix in reserved.
Credits to:
nickmessing - see his answer
Check Vue API: instance property=$props, you should use
_this.$props like below demo:
Vue.config.productionTip = false
Vue.component('child', {
props: {
onChange: {
type: Function,
default: function () {console.log('default')}
},
},
render: function (h) {
let self = this
return h('input', {
on: {
change: function (e) {
var test;
(test = self.$props).onChange(e)
}
}
})
}
})
Vue.component('container1', {
render: function (h) {
return h('child', {
props: {
onChange: this.printSome
}
})
},
methods: {
printSome: function () {
console.log('container 1 custom')
}
}
})
Vue.component('container2', {
render: function (h) {
return h('child', {
props: {
onChange: this.printSome
}
})
},
methods: {
printSome: function () {
console.log('container 2 custom')
}
}
})
new Vue({
el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<h3>Container 1</h3>
<container1></container1>
<h3>Container 2</h3>
<container2></container2>
</div>
I have a page with photoalbums, and I need edit each album by click on the edit button in album component. I can't understand how to communicate between components if I have no common store(redux for example)
How to track state of parent component from child component - Modal?
var AlbumsPage = React.createClass({
render: function ()
{
return(
<div>
<AlbumList url="Album/List"/>
</div>
);
}
});
var AlbumList = React.createClass({
componentDidMount: function ()
{
$.ajax({
url: this.props.url,
dataType: 'json',
method: "POST",
cache: false,
success: function (data) {
this.setState({ data: data.Albums });
}.bind(this),
error: function (xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function()
{
return this.getAlbumListState();
},
getAlbumListState: function()
{
return {
data: [],
currentAlbum: null,
showModal: false
}
},
setCurrentAlbum: function(album){
this.state.currentAlbum = album;
},
setShowModal : function(val){
this.state.showModal = val;
},
getShowModal: function(){
return this.state.showModal;
},
render: function () {
var albums = this.state.data.map(function(album) {
return (
<Album key={ album.Id } title={ album.Title } getShowModal={ this.getShowModal } setCurrentAlbum={ this.setCurrentAlbum } setShowModal={ this.setShowModal }></Album>
);
}, this);
return (
<div>
<div>
{ albums }
</div>
<AlbumModal showModal={ this.state.showModal } currentAlbum={ this.state.currentAlbum }/>
</div>
);
}
});
var Album = React.createClass({
open : function()
{
console.log("open fired");
console.log(this.props.getShowModal());
if (this.props.getShowModal()) {
this.props.setShowModal(false);
this.props.setCurrentAlbum(null);
} else {
this.props.setShowModal(true);
this.props.setCurrentAlbum(this.props.album);
}
},
render: function () {
return (
<div className="col-sm-3 col-md-3">
<div className="thumbnail">
<div className="caption">
<h3>{ this.props.title }</h3>
<p>
<a onClick={ this.open }><span className="glyphicon glyphicon-pencil"></span></a>
<a><span className="glyphicon glyphicon-trash"></span></a>
</p>
</div>
</div>
</div>
);
}
});
var AlbumModal = React.createClass({
getInitialState: function() {
return {
showModal: this.props.showModal,
currentAlbum: this.props.currentAlbum
};
},
close: function() {
this.setState({ showModal: false });
},
open: function() {
this.setState({ showModal: true });
},
render: function() {
return (
<div>
<ReactBootstrap.Modal show={this.state.showModal} onHide={this.close}>
<ReactBootstrap.Modal.Header closeButton>
<ReactBootstrap.Modal.Title>Modal heading</ReactBootstrap.Modal.Title>
</ReactBootstrap.Modal.Header>
<ReactBootstrap.Modal.Body>
<h4>Text in a modal</h4>
</ReactBootstrap.Modal.Body>
<ReactBootstrap.Modal.Footer>
<ReactBootstrap.Button onClick={this.close}>Close</ReactBootstrap.Button>
</ReactBootstrap.Modal.Footer>
</ReactBootstrap.Modal>
</div>
)
}
});
ReactDOM.render(
<AlbumsPage />,
document.getElementById('albums')
);
You'd have to pass the parent as a prop to the child component.
So in your AlbumList::render, you'd have to do
return (
<Album
key={ album.Id }
title={ album.Title }
getShowModal={ this.getShowModal }
setCurrentAlbum={ this.setCurrentAlbum }
setShowModal={ this.setShowModal }
parent={this}
>
</Album>
);
But this will create a huge overhead once you start passing states to many different components.
A good plugin to solve this would be to use Redux
I'm starting to learn react. There's an excellent example in the official docs about loading data initially via AJAX:
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);
The code above gets the latest gist of a specific user from GitHub.
What is the best way in React to go about outputting a list of the last 10 gists of the specific user?
How would you modify the code sample above?
var UserGist = React.createClass({
getInitialState: function() {
return {
gists: []
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
this.setState({
gists: result
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return <div>
{this.state.gists.map(function(gist){
return <div key={gist.id}>{gist.owner.login}</div>
})}
<div>;
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);
I have just started to work on React and have been trying to come up with a To-Do App using raw React, without JSX. I have been trying to implement 'Delete' functionality for each of the To-Do item, but it doesn't work. Can someone please help me to understand and implement this 'delete button'
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<script src="https://cdn.rawgit.com/zloirock/core-js/master/client/shim.min.js"></script>
<meta charset="utf-8">
<title>To-Do app</title>
</head>
<body>
<div id="ToDo-app"></div>
<script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react.js"></script>
<script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react-dom.js"></script>
<script>
var ItemForm = React.createClass({
PropTypes: {
value: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired,
},
onItemInput : function(e) {
this.props.onChange(Object.assign({},this.props.value, {item: e.target.value}));
},
onSubmit: function(e) {
e.preventDefault();
this.props.onSubmit();
},
render: function() {
var errors = this.props.value.errors || {};
return (
React.createElement('form', {onSubmit: this.onSubmit, className: 'ItemForm', noValidate: true},
React.createElement('input', {
type: 'text',
className: errors.item && 'ItemForm-error',
placeholder: 'To-Do item',
onInput: this.onItemInput,
value: this.props.value.item,
}),
React.createElement('button', {type: 'submit'}, "Add Item")
)
);
},
});
var ToDoItem = React.createClass({
PropTypes: {
item: React.PropTypes.string.isRequired,
id: React.PropTypes.string.isRequired,
onSubmit: React.PropTypes.func.isRequired,
},
onSubmit: function(e) {
e.preventDefault();
this.props.onSubmit(this.props.id);
},
render: function() {
return (
React.createElement('li', {className: 'ToDoItem'},
React.createElement('h2', {className: 'ToDoItem-item', onSubmit: this.onSubmit}, this.props.item),
React.createElement('button', {type: 'submit'}, "Delete")
)
);
},
});
var ItemsView = React.createClass({
PropTypes: {
id: React.PropTypes.string.isRequired,
items: React.PropTypes.array.isRequired,
newItem: React.PropTypes.object.isRequired,
onNewItemChange: React.PropTypes.func.isRequired,
onNewItemSubmit: React.PropTypes.func.isRequired,
onDSubmit: React.PropTypes.func.isRequired,
},
render: function() {
var ItemElements = this.props.items
.map(function(item) {
return React.createElement(ToDoItem, item);
});
//alert(ItemElements);
return(
React.createElement('div', {className: 'ItemView'},
React.createElement('h1', {className: 'ItemView-title'}, "To-Do Items"),
React.createElement('ul', {className: 'ItemView-list', onSubmit: this.props.onDSubmit}, ItemElements),
React.createElement(ItemForm, {value: this.props.newItem, onChange: this.props.onNewItemChange,
onSubmit: this.props.onNewItemSubmit,
})
)
);
},
});
var ITEM_TEMPLATE = {item: "", errors: null};
function updateNewItem(item) {
setState({ newItem: item});
};
function submitNewItem() {
var item = Object.assign({}, state.newItem, {key: state.items.length + 1, errors: {}});
if (!item.item) {
item.errors.item = ["Please enter your To-Do item"];
}
setState(
Object.keys(item.errors).length === 0
? {
newItem: Object.assign({}, ITEM_TEMPLATE),
items: state.items.slice(0).concat(item),
}
: { newItem: item }
);
};
function deleteItem(e,item) {
alert("Inside delete func");
var index = state.item.id;
var elements = state.items.splice(index, 1);
setState({items: elements});
};
function navigated() {
setState({
location: window.location.hash});
}
var state = {
items: [
{key: 1, item: "Pay the internet bill"},
{key: 2, item: "Call the team for conference"},
],
newItem: Object.assign({}, ITEM_TEMPLATE),
location: window.location.hash
};
function setState(changes) {
var component;
Object.assign(state, changes);
switch (state.location) {
case '#/items':
//alert("Inside items")
component = React.createElement(ItemsView, Object.assign({}, state, {
onDSubmit: deleteItem,
onNewItemChange: updateNewItem,
onNewItemSubmit: submitNewItem,
}));
break;
default:
component = React.createElement('div', {},
React.createElement('h1', {}, "Let's get this Done!"),
React.createElement('a', {href: '#/items'}, "To Do Items")
);
}
ReactDOM.render(component, document.getElementById('ToDo-app'));
};
// Handle browser navigation events
window.addEventListener('hashchange', navigated, false);
// Start the app
navigated();
</script>
</body>
</html>
Use frontend-boilerplate. It is a fully To-Do app using React, Redux, Webpack and other commonly tools.
Using ReactJs and react-dnd
I want a user to be able to sort the form fields (a.k.a. properties)
I set up the code almost identical to the source code for the Cards in the simple sort demo. There are no console warnings or errors, and I can't figure out why this won't work. I can neither drag nor drop anything.
What it looks like:
Code:
App.js
import EditForm from './Forms/EditForm.js';
var id = $('#form').data('id');
var source = `/api/forms/${id}?include=type,properties.type`;
React.render(
<EditForm source={source} />,
document.getElementById('form')
);
EditForm.js
import React from 'react/addons';
import update from 'react/lib/update';
import Property from './Property.js';
var EditForm = React.createClass({
mixins: [ React.addons.LinkedStateMixin ],
getInitialState: function() {
return {
id: null,
name: null,
slug: null,
properties: []
}
},
componentDidMount: function() {
this.getFormFromServer();
},
getFormFromServer: function () {
$.get(this.props.source, (result) => {
if (this.isMounted()) {
this.setState({
id: result.id,
name: result.name,
slug: result.slug,
properties: result.properties.data
});
}
});
},
moveProperty: function(id, afterId) {
const { properties } = this.state;
const property = properties.filter(p => p.id === id)[0];
const afterProperty = properties.filter(p => p.id === afterId)[0];
const propertyIndex = properties.indexOf(property);
const afterIndex = properties.indexOf(afterProperty);
this.setState(update(this.state, {
properties: {
$splice: [
[propertyIndex, 1],
[afterIndex, 0, property]
]
}
}));
},
render: function() {
const { properties } = this.state;
var propertiesList = properties.map((property, i) => {
return (
<Property
key={property.id}
id={property.id}
type={property.type.name}
name={property.name}
moveProperty={this.moveProperty} />
);
});
return (
<div>
<h1>Form</h1>
<form>
<div className="form-group">
<label>Name:</label>
<input type="text" name="name" valueLink={this.linkState('name')} className="form-control" />
</div>
<div className="form-group">
<label>Properties:</label>
<div className="list-group properties-list">
{propertiesList}
</div>
</div>
</form>
</div>
);
}
});
export default EditForm;
Property.js
import React, { PropTypes } from 'react/addons';
import { DragDropMixin } from 'react-dnd';
import ItemTypes from './ItemTypes';
const dragSource = {
beginDrag(component) {
return {
item: {
id: component.props.id
}
};
}
};
const dropTarget = {
over(component, item) {
component.props.moveProperty(item.id, component.props.id);
}
};
var Property = React.createClass({
mixins: [ React.addons.LinkedStateMixin, DragDropMixin ],
propTypes: {
id: PropTypes.any.isRequired,
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
moveProperty: PropTypes.func.isRequired
},
statics: {
configureDragDrop(register) {
register(ItemTypes.PROPERTY, {
dragSource,
dropTarget
});
}
},
render: function () {
const { type } = this.props;
const { name } = this.props;
const { isDragging } = this.getDragState(ItemTypes.PROPERTY);
const opacity = isDragging ? 0 : 1;
return (
<a className="list-group-item"
{...this.dragSourceFor(ItemTypes.PROPERTY)}
{...this.dropTargetFor(ItemTypes.PROPERTY)}>
{type}: {name}
</a>
);
}
});
export default Property;
ItemTypes.js
module.exports = {
PROPERTY: 'property'
};
If anybody could help I would greatly appreciate it. It's kind of sad how much time I've actually spent trying to figure this out.
Reference links:
My code on github
Demo example
Demo source on github
After spending over a day trying to get the drag and drop working I fixed it with one single line of code.
import React from 'react/addons';
How it compiled and rendered at all without that, I don't even know.