ReactJS - access to props child in render for props transfer - reactjs

When I try to access {this.props} in render, it crashes my page. Am I doing something wrong here?
var React = require('react');
var DefaultLayout = React.createFactory(require('../layouts/Default'));
var ReactGridLayout = React.createFactory(require('react-grid-layout'));
var DesktopStore = require("../stores/DesktopStore");
var _ = require('lodash');
// var classNames = require('classnames');
var HomePage = React.createClass({
displayName: 'Index.jsx',
getInitialState: function(){
return {
zoomed: DesktopStore.get('zoom'),
layout: this.generateLayout()
};
},
getDefaultProps: function() {
return {
layout: DefaultLayout,
grid: {
items: 20,
cols: 80,
rowHeight: 30,
verticalCompact: false,
autoSize: false,
isResizable: false,
margin: [5,5]
}
};
},
generateGridDOM: function(){
return _.map(_.range(this.props.grid.items), function(i) {
return (<div key={i}><span className="text">{i}</span></div>);
});
},
generateLayout: function(){
var p = this.props;
var layout = _.map(new Array(p.grid.items), function(item, i) {
return {x: 0, y: 1, w: 1, h: 1, i: i};
});
return layout;
},
render: function() {
var parentClassString = "desktop";
if(this.state.zoomed){
parentClassString += " zoomed";
}
return (
var grid = this.props.grid; // this crashes the page
<div className={parentClassString}>
<ReactGridLayout className="gridLayout"
layout={this.state.layout} {...this.props.grid} > // this crashes the page
{this.generateGridDOM()}
</ReactGridLayout>
</div>
);
}
});
module.exports = HomePage;

You can't define that var grid = this.props.grid; within the return, put it before the return. The render method is just supposed to return a single root DOM node or React component.
If you look in the webpack build output it should point out the var is an unexpected token:
ERROR in ./file.js
Module build failed:
SyntaxError: Unexpected token (56:12)
54 |
55 | return (
56 | var grid = this.props.grid; // this crashes the page
| ^

Related

embed code twitter on Tinymce 4

I am adding a plugin which insert twitter embed code. the problem is that I can see the tweet on the editor but not in the source code and preview. And I can't save it. I saw in forum that I have to add 'http:' to '//platform.twitter.com/widgets.js' and put it before , unfortunately, it's not working. This is the code I put:
tinymce.PluginManager.add('twitter', function(editor, url) {
editor.on('init', function (args) {
editor_id = args.target.id;
});
editor.addButton('twitter', {
text: 'Twitter',
icon: false,
onclick: function () {
editor.windowManager.open({
title: 'Twitter Embed',
body: [
{ type: 'textbox',
size: 40,
height: '100px',
name: 'twitter',
label: 'twitter'
}
],
onsubmit: function(e) {
var embedCode = e.data.twitter;
var script = embedCode.match(/<script.*<\/script>/)[0];
var scriptSrc = script.match(/".*\.js/)[0].split("\"")[1];
console.log(script);
var sc = document.createElement("script");
sc.setAttribute("src", "https:"+scriptSrc);
sc.setAttribute("type", "text/javascript");
var iframe = document.getElementById(editor_id + "_ifr");
var iframeHead = iframe.contentWindow.document.getElementsByTagName('head')[0];
var iframeBody = iframe.contentWindow.document.getElementsByTagName('body')[0];
embedCode1 = embedCode.replace('//platform.twitter.com/widgets.js','https://platform.twitter.com/widgets.js');
iframeBody.appendChild(sc);
editor.insertContent(embedCode1);
iframeHead.appendChild(sc);
// setTimeout(function() {
// iframe.contentWindow.twttr.widgets.load();
// }, 1000)
}
});
}
});
});

reactjs - changing state doesn't re-render component

I'm using a map function to create a game board from an array of objects and calling setState on click to make the game happen. I can successfuly update the state but the view won't update until I perform a different action. I'm guessing the problem is in how the map function passes props to the child element (Cell), but I can't figure out what I'm doing wrong.
var board = [];
var width = 50;
var height = 30;
var size = width * height;
for (var i=1; i<=size; i++) {
board[i] = {id: i, status: 'dead'};
}
var Cell = React.createClass({
turn: function() {
this.props.turn(this.props.id);
},
render: function() {
return <div id={this.props.id} className={this.props.status} onClick={this.turn}></div>
}
});
var GameBoard = React.createClass({
getInitialState: function() {
return {
board: board
};
},
handleClick: function(id) {
var newBoard = this.state.board;
newBoard[id] = {id: id, status: 'alive'};
this.setState({board: newBoard});
},
move: function() {
var board = this.state.board;
var newBoard = board;
for (var j=1;j<=board.length;j++) {
if (board[j].status == 'alive') {
newBoard[j-1] = {id: j-1, status: 'alive'};
newBoard[j] = {id: j, status: 'dead'};
}
}
this.setState({board: newBoard});
},
render: function() {
var squares = this.state.board.map(function(item){
return <Cell id={item.id} status={item.status} turn={this.handleClick}/>
}.bind(this));
return (
<div>
<h1>Game of Life</h1>
<button className="btn btn-default" onClick={this.move}>Run</button>
<div className='boardContainer'>{squares}</div>
</div>
);
}
});
ReactDOM.render(<GameBoard/>,document.getElementById('app'));
http://codepen.io/Theeeus/pen/YpQzPO?editors=0010
The loop in your move function is off-by-one, so it throws an error before reaching the line with setState. The first two lines of the method simply assign a reference to this.state.board in the variable newBoard. Therefore, you're "updating" your state, but not correctly with setState. That's why the board updates on your next click, which calls setState in handleClick.
1) You should modify a deep copy of the state instead of the state itself
2) Fix the off-by-one-error in the for loop
var board = this.state.board;
var newBoard = board; // Note, this is a reference to this.state.board. That's bad!
for (var j=1; j<=board.length - 1; j++) { // note, -1
...
}
You're mutating this.state. The React docs specify that this is a no-no. Inside the GameBoard component, I'd rewrite your handleClick() and move() functions to look more like this:
handleClick: function(id) {
this.setState({
...this.state,
board: [
...this.state.board.slice(0, id),
{
id,
status: 'alive'
},
...this.state.board.slice(id + 1)
]
});
},
move: function() {
this.setState({
...this.state,
board: this.state.board.map((place, id, board) => {
const nextPlace = board[id + 1];
if (nextPlace.status === 'alive') {
return {
...place,
status: 'alive'
};
} else if (place.status === 'alive') {
return {
...place,
status: 'dead'
};
}
return place;
})
});
},
Note: these functions use some new Javascript features like the spread operator (...place) and arrow functions. It's possible that these features might result in syntax errors when you try to run this code.
please use
if(var i = 0;i < arr.length;i++)
,instead of
if(var i = 1;i<=arr.length;i++){}
In your question,when your j in your move function equals to board.length, it will make an error.
Change your two if cycle in your code .
I hope that I can help.
var board = [];
var width = 2;
var height = 3;
var size = width * height;
for (var i=0; i < size; i++) {
board[i] = {id: i, status: 'dead'};
}
var Cell = React.createClass({
turn: function() {
this.props.turn(this.props.id);
},
render: function() {
return <div id={this.props.id} className={this.props.status} onClick={this.turn}></div>
}
});
var GameBoard = React.createClass({
getInitialState: function() {
return {
board: board
};
},
handleClick: function(id) {
var newBoard = this.state.board;
newBoard[id] = {id: id, status: 'alive'};
this.setState({board: newBoard});
},
move: function() {
var board = this.state.board;
var newBoard = board;
for (var j=0;j < board.length;j++) {
if (board[j].status == 'alive') {
newBoard[j-1] = {id: j-1, status: 'alive'};
newBoard[j] = {id: j, status: 'dead'};
}
}
this.setState({board: newBoard});
},
render: function() {
var squares = this.state.board.map(function(item){
return <Cell key = {item.id} fuck={item.id} id={item.id} status={item.status} turn={this.handleClick}/>
}.bind(this));
return (
<div>
<h1>Game of Life</h1>
<button className="btn btn-default" onClick={this.move}>Run</button>
<div className='boardContainer'>{squares}</div>
</div>
);
}
});
ReactDOM.render(<GameBoard/>,document.getElementById('app'));
.dead{
width:10px;height:10px;border:1px solid red;margin:3px;
}
.alive{
border:1px solid green;margin:3px;width:10px;height:10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Dynamically change zoom

I need to change zoom of Google Maps. Code:
function _initMap(vm) {
vm.windowOptions = {
show: false
};
var latSum = 0;
var longSum = 0;
for (var i = 0, length = vm.markers.length; i < length; i++) {
//calculate center of map (1st part)
latSum += vm.markers[i].coords.latitude;
longSum += vm.markers[i].coords.longitude;
//assign an icon
vm.markers[i].iconUrl = getIconUrl(vm.markers[i].deviceType);
}
var centeredLatitude = latSum / vm.markers.length;
var centeredLongitude = longSum / vm.markers.length;
vm.control = {};
vm.map = {
center: setCenterMap(),
options: getMapOptions(),
zoom: setMapZoom(),
events: {
click: function (mapModel, eventName, originalEventArgs) {
var e = originalEventArgs[0];
$log.log('gz', e.latLng.lat() + ' ' + e.latLng.lng());
console.log('xxx', mapModel);
}
},
show: true,
refresh: function (a, b, c, d) {
vm.map.control.refresh();
}
};
vm.clusterOptions = {
minimumClusterSize: 2,
zoomOnClick: true,
styles: [{
url: 'assets/images/markers/m1.png',
width: 53,
height: 53,
textColor: 'white',
textSize: 17,
fontFamily: 'Open Sans'
}],
averageCenter: true,
clusterClass: 'cluster-icon'
};
vm.window = {
location: undefined,
templateUrl: 'app/components/maps/maps.info.template.html',
show: false,
options: getMapWindowOptions()
};
vm.clickMarker = function (marker, event, object) {
vm.window.show = false;
vm.window.details = object.details;
vm.window.location = object.coords;
vm.window.show = true;
vm.sendChoosenDeviceToController(object);
angular.element('#right-menu').focus();
};
vm.closeClick = function () {
vm.window.show = false;
}
}
but the code:
center: setCenterMap()
zoom: setMapZoom()
when I call the methods center and zoom does not change center and zoom. How to update center and zoom dynamically ? The methods are properly exectued during initiation of map but after initialization does not want to change.
The solution was just simply:
scope.map.center = {
'latitude': scope.markers[i].coords.latitude,
'longitude': scope.markers[i].coords.longitude
};
GoogleMaps knows about that change and works nice.

Include JointJS diagram in React/Flux projects

I'm trying to include a JointJS diagram in my React+Flux project.
I started from an existing demo available there.
My idea is to embed the diagram in an higher level component that will be reused inside my project.
The structure that I came up with is the following:
index.html
...
<body>
<section id="mySec"></section>
...
app.js
...
ReactDOM.render(
<JointJSDiagram id="1"/>,
document.getElementById('mySec')
);
JointJSDiagram.react.js
...
var JointJSDiagramStore = require('../stores/JointJSDiagramStore');
class JointJSDiagram extends React.Component {
...
componentDidMount() {
var el = this.refs[this.props.placeHolder];
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
}
...
render() {
return (<div ref={this.props.placeHolder}/>);
}
...
}
module.exports = JointJSDiagram;
JointJSDiagramStore.js
...
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var _graph = new joint.dia.Graph();
var _paper = new joint.dia.Paper({
width: 600,
height: 200,
model: _graph,
gridSize: 1
});
var JointJSDiagramStore = assign({}, EventEmitter.prototype, {
...
buildDiagram: function(el) {
_paper.el = el;
// In here I used the code from: http://www.jointjs.com/demos/fsa
function state(x, y, label) {
var cell = new joint.shapes.fsa.State({
position: { x: x, y: y },
size: { width: 60, height: 60 },
attrs: {
...
...
...
link(star, block, 'other', [{x: 650, y: 290}]);
link(star, code, '/', [{x: 490, y: 310}]);
link(line, line, 'other', [{x: 115,y: 100}, {x: 250, y: 50}]);
link(block, block, 'other', [{x: 485,y: 140}, {x: 620, y: 90}]);
link(code, code, 'other', [{x: 180,y: 500}, {x: 305, y: 450}]);
},
...
});
...
module.exports = JointJSDiagramStore;
The problem is that nothing is visualized except for some (7) warnings stating:
Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node;
instead, use the node directly. This DOM node was rendered by
JointJSDiagram.
UPDATE
If I explicitly use the id instead of refs like this:
JointJSDiagramStore.js
...
componentDidMount() {
var el = document.getElementById(this.props.placeHolder);
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
JointJSDiagramStore.addChangeListener(this._onChange);
}
...
render() {
return (<div id={this.props.placeHolder}/>);
}
...
I don't receive Warnings anymore, but nothing is still displayed on the placeholder div.
This quick test worked for me. I'm using react 0.14.3
class Graph extends React.Component {
constructor(props) {
super(props);
this.graph = new joint.dia.Graph();
}
componentDidMount() {
this.paper = new joint.dia.Paper({
el: ReactDOM.findDOMNode(this.refs.placeholder),
width: 600,
height: 200,
model: this.graph,
gridSize: 1
});
const rect = new joint.shapes.basic.Rect({
position: { x: 100, y: 30 },
size: { width: 100, height: 30 },
attrs: {
rect: { fill: 'blue' },
text: { text: 'my box', fill: 'white' }
}
});
const rect2 = rect.clone();
rect2.translate(300);
const link = new joint.dia.Link({
source: { id: rect.id },
target: { id: rect2.id }
});
this.graph.addCells([rect, rect2, link]);
}
render() {
return <div ref="placeholder" ></div>;
}
}

Marker Clusterer in DevExtreme Mobile

I'm developing an application in DevExtreme Mobile. In application, I use DXMap in this application. How can I use the marker clusterer structure in DevExtreme Mobile App?
You can use Google Maps Marker Clusterer API to create and manage per-zoom-level clusters for a large number of DevExtreme dxMap markers. Here is an example:
 dxMap Marker Clusterer
This example is based on the approach described in the Google Too Many Markers! article
Here is sample code:
$("#dxMap").dxMap({
zoom: 3,
width: "100%",
height: 800,
onReady: function (s) {
var map = s.originalMap;
var markers = [];
for (var i = 0; i < 100; i++) {
var dataPhoto = data.photos[i];
var latLng = new google.maps.LatLng(dataPhoto.latitude, dataPhoto.longitude);
var marker = new google.maps.Marker({
position: latLng
});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
}
});
The kry is to use the google maps api. I did it for my app, here how.
This the html, very simple:
<div data-options="dxView : { name: 'map', title: 'Punti vendita', pane: 'master', secure:true } ">
<div data-bind="dxCommand: { id: 'back', behavior: 'back', type: 'back', visible: false }"></div>
<div data-options="dxContent : { targetPlaceholder: 'content' } ">
<div style="width: 100%; height: 100%;">
<div data-bind="dxMap:options"></div> <!--this for the map-->
<div id="large-indicator" data-bind="dxLoadIndicator: {height: 60,width: 60}" style="display:inline;z-index:99;" />
<div data-bind="dxPopover: {
width: 200,
height: 'auto',
visible: visible,
}">
</div>
</div>
</div>
</div>
When the page loads, the app read the gps coordinates:
function handleViewShown() {
navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
jQuery("#large-indicator").css("display", "none"); //this is just a gif to indicate the user to wait the end of the operation
}
If the gps location is correctly read, I save the coordinates (the center of the map):
function onSuccess(position) {
var lat1 = position.coords.latitude;
var lon1 = position.coords.longitude;
center([lat1, lon1]);
}
And these are the options I set to my dxMap:
options: {
showControls: true,
key: { google: "myGoogleApiKey" },
center: center,
width: "100%",
height: "100%",
zoom: zoom,
provider: "google",
mapType: "satellite",
autoAdjust: false,
onReady: function (s) {
LoadPoints();
var map = s.originalMap;
var markers = [];
for (var i = 0; i < MyPoints().length; i++) {
var data = MyPoints()[i];
var latLng = new google.maps.LatLng(data.location[0], data.location[1]);
var marker = createMarker(latLng, data.title, map, data.idimp);
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers, { imagePath: 'images/m' });
}
},
Where MyPoints is populated calling LoadPoints:
function LoadPoints() {
$.ajax({
type: "POST",
async:false,
contentType: "application/json",
dataType: "json",
url: myApiUrl,
success: function (Response) {
var tempArray = [];
for (var point in Response) {
var location = [Response[p]["latitudine"], Response[p]["longitudine"]];
var title = Response[p]["name"] + " - " + Response[p]["city"];
var temp = { title: title, location: location, tooltip: title, onClick: GoToNavigator, idpoint: Response[p]["id"] };
tempArray.push(temp);
}
MyPoints(tempArray);
},
error: function (Response) {
jQuery("#large-indicator").css("display", "none");
var mex = Response["responseText"];
DevExpress.ui.notify(mex, "error");
}
});
}
Note that in the folder Myproject.Mobile/images I included the images m1.png, m2.png, m3.png, m4.png and m5.png.
You can found them here.

Resources