React DnD in a Meteor app - javascript

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

Vue, how to pass function in props in JSX render?

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>

How to track state of parent component from child component in ReactJs?

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

React - Load Initial List via AJAX

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

React- button functionality

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.

Trouble with drag-and-drop sortable list using ReactJs and react-dnd

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.

Categories