ReactJS + Flux: How to pass data attribute from HTML? - laravel

I'm using ReactJS(Flux) and Laravel framework. I need to pass a variable from blade template to React components. I'm trying to use data-x attribute.
My question are..
How can I get the data in React(or Flux architecture)?
Do you have the best practice to store the data in Flux. Is app.js the best place to do it?
Thanks,
index.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ReactJS</title>
</head>
<body>
<section id="react" data-domain="{{env("DOMAIN")}}"></section>
<script src="{{ elixir('js/bundle.js') }}"></script>
</body>
</html>
/app.js
var React = require('react');
var SampleApp = require('./components/SampleApp.react');
React.render(
<SampleApp />,
document.getElementById('react')
);
/components/SampleApp.react
var React = require('react');
var SampleApp = React.createClass({
render: function() {
return (
<div>
Hello
</div>
);
}
});
module.exports = SampleApp;
===================================================
Edit 1
I could pass data by using {this.props.domain}. Next step is how to store the data as Flux way.
/app.js
var React = require('react');
var SampleApp = require('./components/SampleApp.react');
var react = document.getElementById('react');
React.render(
<SampleApp domain={react.dataset.domain}/>,
react
);
/components/SampleApp.react
var React = require('react');
var SampleApp = React.createClass({
render: function() {
return (
<div>
Hello {this.props.domain}
</div>
);
}
});
module.exports = SampleApp;
===================================================
Edit 2
Fixed
/index.blade.php
/app.js
/components/SampleApp.react.js
/actions/SampleActionCreators.js
/constans/SampleConstants.js
/dispatcher/SampleAppDispatcher.js
/stores/SampleStore.js
index.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ReactJS</title>
</head>
<body>
<section id="react" data-domain="test.example.com"></section>
<script src="{{ elixir('js/bundle.js') }}"></script>
</body>
</html>
/app.js
var React = require('react');
var SampleApp = require('./components/SampleApp.react');
React.render(
<SampleApp />,
document.getElementById('react')
);
/components/SampleApp.react.js
var React = require('react');
var SampleActionCreators = require('../actions/SampleActionCreators');
var SampleStore = require('../stores/SampleStore');
function getSampleState() {
return {
domain: SampleStore.getDomain()
};
}
var SampleApp = React.createClass({
getInitialState: function() {
return getSampleState();
},
componentDidMount: function() {
SampleStore.addChangeListener(this._onChange);
var domain = document.querySelector('#react').dataset.domain;
SampleActionCreators.initData(domain);
},
componentWillUnmount: function() {
SampleStore.removeChangeListener(this._onChange);
},
render: function() {
return (
<div>
Hello {this.state.domain}
</div>
);
},
_onChange: function() {
this.setState(getSampleState());
}
});
module.exports = SampleApp;
/actions/SampleActionCreators.js
var SampleAppDispatcher = require('../dispatcher/SampleAppDispatcher');
var SampleConstants = require('../constants/SampleConstants');
var ActionTypes = SampleConstants.ActionTypes;
module.exports = {
initData: function(domain) {
SampleAppDispatcher.dispatch({
type: ActionTypes.SAMPLE_INIT_DATA,
domain: domain
});
},
};
/constans/SampleConstants.js
var keyMirror = require('keymirror');
module.exports = keyMirror({
ActionTypes: keyMirror({
SAMPLE_INIT_DATA: null
})
});
/dispatcher/SampleAppDispatcher.js
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
/stores/SampleStore.js
var SampleAppDispatcher = require('../dispatcher/SampleAppDispatcher');
var SampleConstants = require('../constants/SampleConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var CHANGE_EVENT = "change";
var _domain = "";
var SampleStore = assign({}, EventEmitter.prototype, {
getDomain: function() {
return _domain;
},
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
});
SampleAppDispatcher.register(function(action) {
switch (action.actionType) {
case SampleConstants.SAMPLE_INIT_DATA:
_domain = action.domain;
SampleStore.emitChange();
break;
default:
// no op
}
});
module.exports = SampleStore;

Your second edit is "correct" Flux way, same one I used on several large scale projects.
More simpler, alternative approach would be to get domain in app.js and pass it to your SampleApp as prop. This requires for DOM from your blade template to be loaded before JS executes. Since you are already putting your JS on bottom you should be good but I added window.onload event just to make it sure.
var React = require('react');
var SampleApp = require('./components/SampleApp.react');
function getDomain() {
return document.getElementById('react').dataset.domain;
}
function initReact() {
var params = {
domain: getDomain()
};
React.render(
<SampleApp {...params} />,
document.getElementById('react')
);
}
window.onload = function() {
initReact();
};
Now you can use {this.props.domain} to access your domain value in SampleApp.reatc.js

Related

function won`t run in if statement (eventlistener && eventlistener) javascript

I'm trying to get an if statement going to get api results.
First I put eventlisteners(click) on my images and when they are BOTH clicked, the get-api-results function should run.
I know I asked something similar before but I got that one screwed up, with this I`m a little closer I think.
Here`s the code
import axios from 'axios';
const container = document.getElementById('container')
let img = document.createElement("img");
img.src = "https://picsum.photos/200/301";
let img2 = document.createElement("img2");
img2.src = "https://picsum.photos/200/300";
const imgCheck = img.addEventListener("click", function(e) {
console.log("check")
})
const img2Check = img2.addEventListener("click", function(e) {
console.log("ok")
})
img.onclick = function () {location.href = "http://localhost:1234/pageTwo.html";};
document.body.appendChild(img);
document.body.appendChild(img2);
if (imgCheck && img2Check){
async function fetchRecipeOne() {
try {
const result = await axios.get('https://api.spoonacular.com/recipes/complexSearch?query=pasta&maxFat=25&number=2&apiKey=0b4d29adff5f4b41908e8ef51329fc48', {
headers: {
"Content-Type": "application/json"
}
})
console.log(result);
} catch (e) {
console.error(e);
}}
fetchRecipeOne();
} else {
console.log('no results');
}
And the html pages
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css">
<title>Title</title>
</head>
<body>
<img ><img/>
<script type="module" src="app.js"></script>
</body>
</html>
And page 2:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css">
<title>Title</title>
</head>
<body>
<img id="img2"><img/>
<script type="module" src="app.js"></script>
</body>
</html>
Again, I`m pretty new to this stuff so if can give me enough details to sort this out you would do me a big favour.
Thanks!
Tom
addEventListener() does not return anything.
Maybe you can create a variable and change it in the eventlistener, like so:
let imgCheck = false;
img.addEventListener("click", function(e) {
imgCheck = true;
});
let img2Check = false;
img2.addEventListener("click", function(e) {
img2Check = true;
});
Also you redirect the user when he click on img, reset the click so to say. Maybe delete that
And the where you define img2 you try to create an element with the name 'img2' which isn't a valid element.
So change:
let img2 = document.createElement("img2");
To:
let img2 = document.createElement("img");
Lastly you check is the user has clicked on both the images when the script runs, what you can do is set the if statement in the async function, and call the function when the user clicks on a img.
So it could look something like:
import axios from 'axios';
const container = document.getElementById('container')
let img = document.createElement("img");
img.src = "https://picsum.photos/200/301";
let img2 = document.createElement("img");
img2.src = "https://picsum.photos/200/300";
let imgCheck = false;
img.addEventListener("click", function(e) {
imgCheck = true;
fetchRecipeOne();
});
let img2Check = false;
img2.addEventListener("click", function(e) {
img2Check = true;
fetchRecipeOne();
});
document.body.appendChild(img);
document.body.appendChild(img2);
async function fetchRecipeOne() {
if (imgCheck && img2Check) {
try {
const result = await axios.get('https://api.spoonacular.com/recipes/complexSearch? query=pasta&maxFat=25&number=2&apiKey=0b4d29adff5f4b41908e8ef51329fc48', {
headers: {
"Content-Type": "application/json"
}
})
console.log(result);
} catch (e) {
console.error(e);
}
} else {
console.log('no results');
}
}

Browser does not render appended child node

I'm experimenting with web service to transmit new elements to document DOM.
So I'm preparing a XML on server side with necessary informations to do that job. My server side XML is as followed:
<Root>
<Command>Add
<Data><button id="PB" style="width:600px; height:100px;"/></Data>
</Command>
</Root>
This XML will be caught by following page.
You will see XML has a command id "Add", which should add the nodes below data to the page.
When code is running, the button will be created and shown properly in document DOM (see code function onMessage), but it will not be rendered.
The browser debugger tells me, the width and height of the button seems to be Null. When I edit the attributes in browser debugger, the button will be rendered after change. I get this behaviour on Chrome and IE.
I need a hint, what has to be changed to let it run.
<!DOCTYPE html>
<meta charset="utf-8" />
<script language="javascript" type="text/javascript">
var wsUri = "ws://localhost:8002/chat";
var output;
var websocket;
"use strict";
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.binaryType = "arraybuffer";
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt) {
writeToScreen("CONNECTED");
}
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
var parser, xmlDoc, NodeCommand, but;
parser = new DOMParser();
xmlDoc = parser.parseFromString(evt.data, "text/xml");
NodeCommand = xmlDoc.getElementsByTagName("Command");
switch (NodeCommand[0].textContent) {
case "Add":
output.appendChild(NodeCommand[0].childNodes[1].childNodes[0]);
break;
}
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function doSend(message) {
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<html>
<head>
<title>WebSocket Test</title>
</head>
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html>
Solved!
This can't be done in this (intuitive) way. Elements have to be created over document.

Marionette events are not triggered on Route

Why Marionette events are not triggered when I access a URL?
When I access the URL it suppose to call the function API.goHome()
but it doesn't! I don't understand why?
Here is my Code:
App.js
var PatientPortal = new Marionette.Application();
PatientPortal.addRegions({
'headerRegion': '#header',
'bodyRegion': '#body',
'footerRegion': '#footer'
});
PatientPortal.on("before:start", function () {
console.log("Started");
});
PatientPortal.navigate = function (route, options) {
options || (options = {});
Backbone.history.navigate(route, options);
};
PatientPortal.getCurrentRoute = function () {
return Backbone.history.fragment
};
PatientPortal.on("start", function(){
if (Backbone.history) {
Backbone.history.start();
}
if(PatientPortal.getCurrentRoute() == ""){
PatientPortal.navigate('home');
}
});
PatientPortal.start();
and Router Code:
PatientPortal.module("Portal", function (Portal, PatientPortal, Backbone, Marionette, $, _) {
Portal.Router = Backbone.Marionette.AppRouter.extend({
controller: "API",
appRoutes: {
"": "goHome",
"home": "goHome"
}
});
var API = {
goHome: function () {
console.log("go home");
}
};
PatientPortal.on("home:route", function () {
console.log("OKOKOK")
API.goHome();
});
PatientPortal.addInitializer(function () {
new Portal.Router({
controller: API
});
});
});
and here a home page code:
<!DOCTYPE html>
<html>
<head>
<title>INSAH - Login Page</title>
</head>
<body>
<div id="header"></div>
<script src="./js/assets/provider/jquery/jquery-2.1.1.min.js"></script>
<script src="./js/assets/provider/underscore/underscore-min.js"></script>
<script src="./js/assets/provider/backbone/backbone-min.js"></script>
<script src="./js/assets/provider/backbone/backbone.babysitter.min.js"></script>
<script src="./js/assets/provider/backbone/backbone.wreqr.min.js"></script>
<script src="./js/assets/provider/marionette/backbone.marionette.min.js"></script>
<script src="./js/app.js"></script>
<script src="./js/routes/route.js"></script>
</body>
</html>
Thanks.
I figured out the problem, it was because of starting the backbone history, the AddInitializer functuion shoudl be as following:
PatientPortal.addInitializer(function () {
new Portal.Router({
controller: API
});
Backbone.history.start();
});
and we should remove this line from app.js:
Backbone.history.start();

Create addListener click event for more than one shape on the Google map

Look at this code:
This creates four circles on the map in a same position and it creates addListener click event for each one too but I just can click on the last one. I want to fix it in a way that I can click on all of them to make setEditable(true) for each one.
<!DOCTYPE html>
<html>
<head>
<script
src="http://maps.googleapis.com/maps/api/js?key=AIzaSyDY0kkJiTPVd2U7aTOAwhc9ySH6oHxOIYM&sensor=false">
</script>
<script>
var selectedShape;
function clearSelection()
{
if(selectedShape)
{
selectedShape.setEditable(false);
selectedShape = null;
}
}
function setSelection(shape)
{
clearSelection();
selectedShape = shape;
shape.setEditable(true);
}
</script>
<script>
var amsterdam=new google.maps.LatLng(52.395715,4.888916);
function initialize()
{
var mapProp = {center:amsterdam, zoom:7, mapTypeId:google.maps.MapTypeId.ROADMAP};
var map = new google.maps.Map(document.getElementById("googleMap"),mapProp);
var myArray = [];
var myCity;
for(var i = 0; i < 4; i++)
{
myCity = new google.maps.Circle({
center:amsterdam,
radius:20000,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#0000FF",
fillOpacity:0.4
});
myArray.push(myCity);
google.maps.event.addListener(myCity, 'click', function() {setSelection(myCity)});
myArray[i].setMap(map);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="googleMap" style="width:500px;height:380px;"></div>
</body>
</html>
Use this instead of myCity :
google.maps.event.addListener(myCity, 'click', function() {
setSelection(this)
});
Using setSelection(myCity) will refer to the last myCity created.

window onload and window onfocus

window.onload = function() {
window.onfocus = alert('example');
}
I've met this problem, anyone can help?
I'm new at javascript and made this expecting to work properly, but it does not :)
I want to alert the word "example" when the page is fully loaded and active, but don't want to alert the word "example" if the page is fully loaded but not active (onblur).
And when user comes back (onfocus) then alert "example".
Your code calls the alert function immediately and assigns its return value to onfocus.
You need to set onfocus to an anonymous function that calls alert:
window.onload = function() {
window.onfocus = function() { alert('example'); };
};
Try this:
var hasFocus=false;
var loaded = false;
window.onload = function() {
if (hasFocus) alert('example');
loaded = true;
};
window.onfocus = function() {
if (loaded) alert('example');
hasFocus = true;
};
window.onblur = function() { hasFocus = false; };
window.onload = function() {
window.onfocus = function() {
alert('example');
}
}
Here is the javascript that you need.
<html>
<head>
<script type="text/javascript">
window.onload = init;
function init() { window.onfocus = whenInFocus; window.onblur = function() {window.onfocus = whenInFocus;};};
function whenInFocus() {alert('example'); window.onfocus = null;};
</script>
</head>
<body>
hello
</body>
</html>

Resources