I`m using React + Babel 6, with webpack.
When I was using Babel 5, it was easy to pass in the initial data using a script type="text/babel" on the page, then babel-core/browser.js takes care of it.
But now, using Babel 6, I have to load all the initial data calling the REST API, as my component mounts.
This results in the browser client opening a connection on the server to render the frontend, and then the frontend opens a new connection to get the data.
Wouldn't this affect my server performance as, now I have 2 connections vs the older 1 connection oppened?
EDIT:
I wish I could keep using the folowing snippet on the page:
<script type="text/javascript" src="{{ asset('app/bundle.js') }}"></script>
<script type="text/babel">
var jsonVar = '{vars}';
ReactDOM.render(
<App vars={vars}/>,
document.getElementById('app-wrapper')
);
</script>
It's a normal pattern to load your server side content and, then, your components grab some data. One downside of this design, of course, is that this implies one initial render plus api request for data.
However, you can setup a server side render with react components, rendering initial data on the server. If your backend is nodejs, for instance, you can use ReactDOMServer.renderToString.
I've resolved this issue by:
Using an "application/json" script tag(passing an id) and put serialized data inside it.
<script type="application/json" id="app-data"> { "id" : 1 } </script>
Then in the app.js:
var appData = JSON.parse( document.getElementById(script-id).innerHTML )
Related
I'm trying to create a simple webpage which gets data from a microcontroller (MSP432) and plots it on a graph in real time.
I have researched and I'm currently using plotly.js and html to create the graph. I currently have a graph that updates itself with random data in realtime.
I have attached the code for the page below.
I now want to stream the data in, and I have looked at node.js and in particular the serialport library. I think I have installed the serialport npm.
The part where I'm confused is how does the node.js code fit in with my html/plotlyjs index file?
I have never used javascript before. It's my first time with nodejs especially, so I'm confused. Should I just put it inside the <script> tag right in the getX() getY() function?
Also does anyone know how I can go about starting the nodejs code? I'm kind of lost.
This is my index.html file:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="plotly.min.js"></script>
<meta charset="utf-8" />
<title>My Plot Page</title>
</head>
<body>
<p>Plotly plot:</p>
<div id="chart1"></div>
<script>
var counter = 0;
function getX() {
counter++;
return counter;
}
function getY() {
return Math.random();
}
Plotly.plot('chart1', [{
x: [getX()],
y: [getY()],
type: 'line'
}]);
setInterval(function () {
Plotly.extendTraces('chart1', { x: [[getX()]] , y: [[getY()]] }, [0])
}, 200);
</script>
</body>
</html>
Node.js is an open source server environment. It is used to host a webserver and can't be run inside the webbrowser. It can be used to read serial port data and send it to the connected clients.
An example setup would be as below:
---------------------------------------------------------------------------
| MSP432 node.js server web page in browser |
| M <==================> N <===========================> W |
| serial websockets |
---------------------------------------------------------------------------
The nodejs server (N) reads the data from the serial port and manages the MSP432 (M). The server (N) also hosts a webserver (using expressjs) and opens a websocket with the connected webpage (W) to transfer new data. An easy to use websocket library is socket.io.
A simple nodejs webserver can be created by doing:
express --view=pug <your application name>
please note that ejs can also be used instead of pug
ajax can also be used instead of websockets
From experience (I work with data visualization systems), I can tell you Plotly might not be the easiest way to plot real-time data. It can do it for sure, but what it does is re-render the whole plot for every new point, which considering the data structure is not the most efficient method and looks a bit unnatural when updating.
In your use case, I would recommend this plugin instead: http://smoothiecharts.org/ it's lightweight, free, and "smooth". Read the "10 minute tutorial" on their website and you're good to go.
Summarizing, to each smoothiecharts timeseries, you want to use the append() method to add each new data sample. You can call this using a setTimeInterval() JavaScript method to get the value from... a URL (making an AJAX GET request). You want to create a URL that will always return the latest reading from your sensor, and for this you'll need to create a local webserver.
This is where your NodeJS application fits in: Create a simple NodeJS server with a GET method that returns the latest reading from your device. Something like this is enough to return simple content like a number: https://www.tutorialspoint.com/nodejs/nodejs_first_application , you could print a random number first and work on it until it works before continuing.
The hardest part here though is to get your microcontroller's readings into the NodeJS application. I don't know the specifics of the MSP432 or how you're connecting to it, but usually you can write a C script that reads the latest value from it and prints it to the console.
If you manage to do this, you can use the following NodeJS code to execute your C program and read its console output:
var exec = require('child_process').execFile;
var path = 'c:\yourprogram.exe';
var fun = function() {
exec(path, function(err, data) {
console.log(err)
console.log(data.toString());
});
}
fun();
You can easily tweak that code into a function that updates the NodeJS variable that your server returns, and run it in a loop every X milliseconds.
And that would be your full visualization system.
I am wondering, what would be the best setup of data flow from PHP (database) to fronted Javascript rendering, lets say VueJS.
My first idea is, that will provide data attribute with JSON data to HTML element - div, which Vue instance will be mounted on.
I dont want to create REST API and load data via AJAX HTTP requests from Vue.
# PHP part
echo '<div id="myId" data-my-data="{h1:\"My heading\"}"></div>';
// Javascript part
import Vue from 'vue/dist/vue.js';
import App from './MyApp.vue';
const el = document.querySelector('#myId');
new Vue({
el,
render: h => h(App, {
props: {
myData: JSON.parse(el.dataset.myData),
},
}),
});
What do you think, is it ok or is there any other option except REST?
Update:
Main purpose is that my App will handle complex - multi-step Forms with some complex fields, which I would like to create as reusable components.
App will validate forms via AJAX (to prevent re-rendering page), on success redirect to success page.
My infrastructure would be, that PHP will prepare data, render main layout with assets (JS + CSS) and DIV with data atributes for Vue App.
in Angularjs in a html page I need to load an external javascript file:
<script src="https://www.my-url.com/js/my.js?Key=xxxxxxxx"></script>
But based on different env (test, beta, prod), I will have different Key.
How can I implement this like what we usually do using web.config in .net?
Edit:
I saw some answers, but seems not exactly what I need. so I elaborate my environment: I have a client side which is pure html and Angularjs, my server side is an Asp.net Web API web service. When I talk about web.config in the original post, I don't mean put the key in web.config, but something conceptually similar. I want this "config file" on the client side, not on my Web API.
You can use gulp-replace and automate it on your build time.
There are two issues to solve:
Getting web.config values into the angular app
Making use of the config to download a script
1. Getting web.config to the app:
I've detailed in a blog post the method I use. Essentially, use a custom angular provider in the applications .cshtml file. This will load all web.config items with the prefix of client:...
Used by the MVC controller:
public static class ApplicationConfiguration
{
private const string ClientAppSettingPrefix = "client:";
public static object GetClientConfiguration()
{
var clientConfiguration = new ExpandoObject() as IDictionary<string, Object>;
// Find all appSetting entries prefixed with "client:"
foreach (var key in ConfigurationManager.AppSettings.AllKeys.Where(key => key.StartsWith(ClientAppSettingPrefix)))
{
// Remove the "client:" prefix before adding to clientConfiguration
clientConfiguration.Add(key.Replace(ClientAppSettingPrefix, String.Empty), ConfigurationManager.AppSettings[key]);
}
return clientConfiguration;
}
}
Script added into the app's .cshtml file:
<!-- Inject the configuration -->
<script type="text/javascript">
(function() {
angular.module('client.config', [])
.provider('applicationConfiguration', function() {
var config = #Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings {ContractResolver = new CamelCasePropertyNamesContractResolver()}));
return {
config: config,
$get: function() {
return config;
}
};
});
})();
</script>
So now you can use it in you add as a normal dependency:
angular.module('app', [
// Add as a dependent module
'client.config'
])
.config([
'applicationConfigurationProvider', 'dataServiceProvider', function(applicationConfigurationProvider, dataServiceProvider) {
// Set the api root server configuration
dataServiceProvider.setApiRootUrl(applicationConfigurationProvider.config.apiRoot);
}
]);
2. Making use of config to download script
As suggested in other answers, use JQuery's getScript() function.
Other SO answers also suggest using a simple injection into the head if you don't want to depend on Jquery. Take a look at Single page application - load js file dynamically based on partial view for ideas
You have couple of options here.
Option 1:
Use Angular's http service to get script files dynamically as String and then use eval() function to execute resulting String.
References: eval Angular $http service
Option 2:
Use JQuery's getScript method
Example:
var keys={ 'prod':'prodKey',
'staging:='stagingKey',
'dev':'devKey'
}
//Assuming you have an variable storing modes like prod, staging or dev
var url='https://www.my-url.com/js/my.js?Key='+keys[ENVT.MODE];
$.getScript( url, function( data, textStatus, jqxhr ) {
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Script loaded successfully" );
});
Reference: getScript
I know that the Jinja2 library allows me to pass datastore models from my python code to html and access this data from inside the html code as shown in this example . However Jinja2 isn't compatible with javascript and I want to access the data inside my Javascript code . What is the simplest templating library which allows to iterate over my datastore entities in Javascript ? I've heard about things like Mustache and Jquery , I think they look a bit too complicated. Is there anything simpler?
You should create a python controller which serves JSON formatted data, which any Javascript library (especially jQuery) can consume from. Then, setup the Jinja2 template to contain some Javascript which calls, loads and displays said data.
One more approach to consider: If the Python object is not dynamic, you may want to use json.dumps() to store it as a TextProperty, and simply JSON.parse(unescape(model_text)) on the JS side. Reduces the overhead, and memory hit which can be important when trying to stay within an F1 limit. For example, I run an instance that very easily runs inside an F1. There is one large dictionary object that we deliver. Were this object to exist as a Python dictionary inside the instance we would kill the instance due to the soft memory limit. Using the TextProperty approach we can pass this large dict to the client without any issues. (Note: we did have to momentarily boost our instance up to an F4 when initially creating this object -- something incredibly easy inside the Admin web page.) With more dynamic objects, answers above apply.
Jinja2 and Javascript play fine together. You need to arrange to have template expansion emit your Python data structures into a JS-friendly form.
https://sites.google.com/a/khanacademy.org/forge/technical/autoescape-in-jinja2-templates covers it fairly well. (Note the use of the escapejs filter.)
It works. I had to serialize(convert) my datastore entities to json format, which Javascript understands well. I created a function which converts every instance of my datastore into a dictionnary then encapsulates all these instances into a list which is then converted to Json using json.dumps. When I pass this result to the Java script , I can then easily access my values as seen below.
import json
import webapp2
from google.appengine.ext import db
import jinja2
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
# serialize datastore model to JSON format
def serialize(model):
allInstances = model.all() # fetching every instance of model
itemsList = [] #initial empty list
for p in allInstances:
d = db.to_dict(p)
itemsList.append(d)
return json.dumps(itemsList)
class myModel(db.Model):
v = db.FloatProperty()
c = db.FloatProperty()
tdate = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp2.RequestHandler):
def get(self):
myModel(v=4.5, c=3.0).put()
#creating template variables
template_values = {
'json_data': serialize(myModel)
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
Inside my 'index.html' file, I have:
{% autoescape true %}
<!DOCTYPE html>
<html>
<head>
<title> webpage </title>
<script type="text/javascript">
// I retrieve my data here
var results = "{{ json_data }}";
for(var i = 0; i < db_results.length; i++) {
document.write("myModel instance:" + i + results[i] + "<br>");
}
</script>
</head>
<body>
</body>
</html>
{% endautoescape %}
It has nothing to do with compatibility. Jinja is server side templating. You can use javascript for client side coding.
Using Jinja you can create HTML, which can be accessed by javascript like normal HTML.
To send datastore entities to your client you can use Jinja to pass a Python list or use a json webservice.
I'm trying to find the best way to deal with dynamic routing generated through an AJAX call with Symfony2.
When a new call is made, I need the current path to be available , along with some dynamic variables that get passed into the path.
Essentially this .
A few answers have suggested putting the route into a variable within each templete , such as
<script type="text/javascript">
var productPath = {{ path("acme_myBundle_default_product" , {"magazine" : "bobscheese" , "product" : "chedderfornoobs"}) }};
</script>
The issue here is, the path rely s on variables, that won't exist at runtime (namely $magazine and $product).
A perfect solution would be FOSJsRoutingBundle it seems , but the installation doesn't seem to be up to date with the latest Symfony2 .
Installation runs fine with git submodule add git://github.com/FriendsOfSymfony/FOSJsRoutingBundle.git vendor/bundles/FOS/JsRoutingBundle
but then I think the rest of the ReadMe is out of date, following it gives me a blank screen, with no errors in the log.
So my question is , either , how to install FOSJsRoutingBundle in Symfony2.1.3 , or how best to handle client side generated URLS within Symfony2.
FOSJsRoutingBundle can be normally used in my environment(2.1.3).
Does routing go wrong?
Has it set up?
acme_myBundle_default_product:
pattern: // ...
defaults: // ...
options:
expose: true
I just went down the
<script type="text/javascript">
var basePath = 'http://www.mybaseurl.com';
</script>
Route. Not as fulfilling, but worked for me in this case.