Google Maps from JSON File - ajax

I'm trying to create a heatmap map with 2 layers using google maps API and heatmaps.js. I'm able to create my map by hard-coding my lat/lon variables, but ultimately I'd like to have my layers fed from JSON files that can easily be refreshed.
Here is my current HTML, which works great.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href='css/bootstrap.css' rel='stylesheet' type='text/css'></link>
<link href='css/bootstrap-responsive.css' rel='stylesheet' type='text/css'></link>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.3.js'></script>
<script type='text/javascript' src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=visualization&.js"></script>
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
}
#media (max-width: 980px) {
/* Enable use of floated navbar text */
.navbar-text.pull-right {
float: none;
padding-left: 5px;
padding-right: 5px;
}
}
</style>
<script>
var map, pointarray, heatmap;
var layer1 = [
{location: new google.maps.LatLng(42.071523,-72.624257), weight:13.747727085},
{location: new google.maps.LatLng(42.37686,-72.46914), weight:6.6332495807},
{location: new google.maps.LatLng(42.40524,-72.528427), weight:5.1961524227},
{location: new google.maps.LatLng(42.383945,-72.511834), weight:1.7320508076},
{location: new google.maps.LatLng(42.433317,-72.114488), weight:5.6568542495}
];
var layer2 = [
{location: new google.maps.LatLng(41.513113,-74.37616), weight:2.4494897428},
{location: new google.maps.LatLng(41.147711,-73.941171), weight:10},
{location: new google.maps.LatLng(41.329376,-74.347207), weight:4.8989794856},
{location: new google.maps.LatLng(41.338977,-73.987248), weight:1.7320508076}
];
function initialize() {
var mapOptions = {
zoom: 4,
center: new google.maps.LatLng(38.82, -99.408660),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
pointArray1 = new google.maps.MVCArray(layer1);
pointArray2 = new google.maps.MVCArray(layer2);
heatmap1 = new google.maps.visualization.HeatmapLayer({
data: pointArray1
});
heatmap2 = new google.maps.visualization.HeatmapLayer({
data: pointArray2
});
heatmap1.setMap(map);
heatmap2.setMap(map);
}
//FUNCTION TO CHANGE LAYERS
function changeMap(layerNum) {
if (layerNum == 1) {
updateMap(heatmap1);
}
if (layerNum == 2) {
updateMap(heatmap2);
}
}
//FUNCTION TO UPDATE LAYERS
function updateMap(layer) {
var layerMap = layer.getMap();
if (layerMap) {
layer.setMap(null);
} else {
layer.setMap(map);
}
}
</script>
<link href='css/DT_bootstrap.css' rel='stylesheet' type='text/css'></link>
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="../assets/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="#">Test Page</a>
<div class="nav-collapse collapse">
<p class="navbar-text pull-right">
Logged in as ...
</p>
<ul class="nav">
<li class="active">Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<body class="container-fluid">
<div class="row">
<div class="span12" style="float: none; margin: 0 auto;">
<body onload="initialize()">
<h3>Test Layers</h3>
<input type='checkbox' name='system_type17' value='1' onclick="changeMap(this.value);" checked="checked" />
<span style="width:100px;display:inline-block;">Layer 1</span>
<input type="checkbox" name="system_type3" value="2" onclick="changeMap(this.value);" checked="checked" />
<span style="width:100px;display:inline-block;">Layer 2</span>
<br><br/>
<div id="map-canvas" style="height: 575px; width: 1000px;"></div>
</body>
</div>
</div>
</body>
</body>
</html>
What I would like to do is replace var layer1 and layer2 with a single JSON file that I would be able to just query, I'm just unsure how to execute something like this. For example, a JSON file that would look something like this:
{
"datapoints": [
{
"lat": "38.1513366000",
"lon": "-97.4341659000",
"weight": "0",
"layer":"1"
},
{
"lat": "38.1513748000",
"lon": "-97.4341125000",
"weight": "0",
"layer":"1"
},
{
"lat": "38.1513938000",
"lon": "-97.4341125000",
"weight": "0",
"layer":"1"
},
{
"lat": "38.1493263000",
"lon": "-97.4339447000",
"weight": "0",
"layer":"1"
},
{
"lat": "38.1493339000",
"lon": "-97.4339447000",
"weight": "0",
"layer":"2"
},
{
"lat": "38.1493377000",
"lon": "-97.4339447000",
"weight": "0",
"layer":"2"
},
{
"lat": "38.1483650000",
"lon": "-97.4358291000",
"weight": "0",
"layer":"2"
},
{
"lat": "38.1484031000",
"lon": "-97.4358062000",
"weight": "0",
"layer":"2"
}
]
}
Updated code per Yehia's suggestions:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href='css/bootstrap.css' rel='stylesheet' type='text/css'></link>
<link href='css/bootstrap-responsive.css' rel='stylesheet' type='text/css'></link>
<script type='text/javascript' src='js/jquery-1.8.3.js'></script>
<script type='text/javascript' src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=visualization&.js"></script>
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
}
#media (max-width: 980px) {
/* Enable use of floated navbar text */
.navbar-text.pull-right {
float: none;
padding-left: 5px;
padding-right: 5px;
}
}
</style>
<script>
var map, pointarray, heatmap;
/*var layer1 = [
{location: new google.maps.LatLng(42.071523,-72.624257), weight:13.747727085},
{location: new google.maps.LatLng(42.37686,-72.46914), weight:6.6332495807},
{location: new google.maps.LatLng(42.40524,-72.528427), weight:5.1961524227},
{location: new google.maps.LatLng(42.383945,-72.511834), weight:1.7320508076},
{location: new google.maps.LatLng(42.433317,-72.114488), weight:5.6568542495}
];
var layer2 = [
{location: new google.maps.LatLng(41.513113,-74.37616), weight:2.4494897428},
{location: new google.maps.LatLng(41.147711,-73.941171), weight:10},
{location: new google.maps.LatLng(41.329376,-74.347207), weight:4.8989794856},
{location: new google.maps.LatLng(41.338977,-73.987248), weight:1.7320508076}
];*/
function initialize() {
var mapOptions = {
zoom: 4,
center: new google.maps.LatLng(38.82, -99.408660),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
}
//FUNCTION TO CHANGE LAYERS
function changeMap(layerNum) {
if (layerNum == 1) {
updateMap(heatmap1);
}
if (layerNum == 2) {
updateMap(heatmap2);
}
}
//FUNCTION TO UPDATE LAYERS
function updateMap(layer) {
var layerMap = layer.getMap();
if (layerMap) {
layer.setMap(null);
} else {
layer.setMap(map);
}
}
</script>
<link href='css/DT_bootstrap.css' rel='stylesheet' type='text/css'></link>
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="../assets/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="#">Test Page</a>
<div class="nav-collapse collapse">
<p class="navbar-text pull-right">
Logged in as ...
</p>
<ul class="nav">
<li class="active">Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<body class="container-fluid">
<div class="row">
<div class="span12" style="float: none; margin: 0 auto;">
<body onload="initialize()">
<h3>Test Layers</h3>
<input type='checkbox' name='system_type17' value='1' onclick="changeMap(this.value);" checked="checked" />
<span style="width:100px;display:inline-block;">Layer 1</span>
<input type="checkbox" name="system_type3" value="2" onclick="changeMap(this.value);" checked="checked" />
<span style="width:100px;display:inline-block;">Layer 2</span>
<br><br/>
<div id="map-canvas" style="height: 575px; width: 1000px;"></div>
</body>
</div>
</div>
<script type="text/javascript">
$.getJSON("testdata.json").then(function(data) {
$.each(data, function(i,datapoints) {
$.each(datapoints, function(j,datapoint) {
layers.push({
location: new google.maps.LatLng(datapoint.lat, datapoint.lng),
weight: datapoint.weight,
layerID: datapoint.layer
});
});
});
});
<script>
</body>
</body>
</html>
Alright, almost there I think. Thanks so much for your help so far, I know this is painful. Here is my initialize function, I'm still getting Uncaught ReferenceError: layers is not defined
<script type='text/javascript'>
var map, pointarray, heatmap;
function initialize() {
function loadData() {
var layers = [ ];
$.ajax({
url: 'testdata.json',
async: false,
dataType: 'json',
success: function (data) {
for (var i=0; i<data.datapoints.length; i++) {
var datapoint = data.datapoints[i];
if (layers[datapoint.layer]===undefined) {
layers[datapoint.layer] = [];
}
layers[datapoint.layer].push({
location: new google.maps.LatLng(datapoint.lat, datapoint.lon),
weight: datapoint.weight,
layerID: datapoint.layer
});
}
}
});
return layers;
}
var mapOptions = {
zoom: 4,
center: new google.maps.LatLng(38.82, -99.408660),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
pointArray1 = new google.maps.MVCArray(layers[1]);
pointArray2 = new google.maps.MVCArray(layers[2]);
heatmap1 = new google.maps.visualization.HeatmapLayer({
data: pointArray1
});
heatmap2 = new google.maps.visualization.HeatmapLayer({
data: pointArray2
});
heatmap1.setMap(map);
heatmap2.setMap(map);
}
//FUNCTION TO CHANGE LAYERS
function changeMap(layerNum) {
if (layerNum == 1) {
updateMap(heatmap1);
}
if (layerNum == 2) {
updateMap(heatmap2);
}
}
//FUNCTION TO UPDATE LAYERS
function updateMap(layer) {
var layerMap = layer.getMap();
if (layerMap) {
layer.setMap(null);
} else {
layer.setMap(map);
}
}
</script>

You'll need a way of reading that JSON and parsing it into the variable(s) you need. Since you're using jQuery, here's a method that would work with the JSON structure you have.
$.getJSON("layers.json").then(function(data) {
$.each(data, function(i,datapoints) {
$.each(datapoints, function(j,datapoint) {
layers.push({
location: new google.maps.LatLng(datapoint.lat, datapoint.lng),
weight: datapoint.weight,
layerID: datapoint.layer
});
});
});
});
Adapt as necessary.
In response to davids12's update, here's a function that returns an array of arrays where each composite array has the datapoints from a certain layer. So, running over your example, layers would have 2 arrays in it (layers[1] and layers[2]) which are basically layer1 and layer2 that you describe in your code (with an additional layerID variable; you could remove it if you wish). This allows you to load much more layers and points just by putting them in the JSON using the format you have now.
function loadData() {
var layers = [ ];
$.ajax({
url: 'j.json',
async: false,
dataType: 'json',
success: function (data) {
for (var i=0; i<data.datapoints.length; i++) {
var datapoint = data.datapoints[i];
if (layers[datapoint.layer]===undefined) {
layers[datapoint.layer] = [];
}
layers[datapoint.layer].push({
location: new google.maps.LatLng(datapoint.lat, datapoint.lng),
weight: datapoint.weight,
layerID: datapoint.layer
});
}
}
});
return layers;
}

Related

Chart.js 4.0.1 Uncaught ReferenceError: Chart is not defined

I wrote an AJAX Javascript code for my ESP32 datalogger which worked so far using old versions of Chart.js. The website hosted by the ESP32 is not working anylonger if I use a more recent of Chart.js.
The error message I caught is:
Uncaught ReferenceError: Chart is not defined at datalogin.html
The line in the code involved is this one
const myChart = new Chart(ctx, config);
Something in the interpretation seems to occur at a very early stage. But I could not identify what. See code below.
I already tried different Chart.js repository in order to have it working. It had absolutly no influence. I actively looked using different browser regarding this specific problematic and I could not find any way of solving this problem.
Thanks a lot for your support
<!DOCTYPE html>
<html lang="en">
<head>
<title>EFM Meter loggin interface</title>
<link rel="icon" type="image/x-icon" href="lightning.ico">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script type="module" src="https://github.com/cdnjs/cdnjs/blob/master/ajax/libs/Chart.js/4.0.1/chart.js" ></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns#2.0.1/dist/chartjs-adapter-date-fns.bundle.js"></script>
<style>
.jumbotron {
background-color: #000;
color: #fff;
}
</style>
</head>
<body>
<div class="jumbotron text-center">
<h1>Elektrofeldmeter Data Logging Page</h1>
</div>
<div class="container">
<div class="border border-2 m-2">
<div class="row">
<div class="col-sm-12 ">
<div class="container-sm">
<canvas id="myChart" style="" height="152"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<div class="border border-2 m-2">
<div class="col-sm-12">
<h3> Parameters setup</h3>
</div>
</div>
<div class="border border-2 m-2">
<div class="row">
<div class="col-sm-12">
<label for="customRange1" class="form-label" id="labelPWM">PWM of motor: 190</label>
<input type="range" class="form-range" min="0" max="190" step="1" value="190" onchange="rangeValue(this)" id="customRange1">
</div>
<div class="col-sm-6">
<label for="customRange2" class="form-label" id="labelYmin">Y min: -5000</label>
<input type="range" class="form-range" min="-5000" max="5000" step="1" value="-5000" onchange="rangeY()" id="Ymin">
</div>
<div class="col-sm-6">
<label for="customRange2" class="form-label" id="labelYmax">Y max: +5000 0</label>
<input type="range" class="form-range" min="-5000" max="5000" step="1" value="5000" onchange="rangeY()" id="Ymax">
</div>
<div class="col-sm-12">
<button type="button" class="btn btn-primary" onclick="saveAs()">*.CSV</button>
</div>
</div>
</div>
</div>
</div>
<script>
function rangeValue(element) {
console.log(element.value);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/pwm?value="+element.value, true);
xhr.send();
document.getElementById("labelPWM").innerHTML = "PWM of motor: " + element.value;
};
function rangeY() {
myChart.options.scales.y.max = document.getElementById('Ymax').value;
myChart.options.scales.y.min = document.getElementById('Ymin').value;
myChart.update();
};
function clkOrientation(element) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/clk?value="+element.checked, true);
xhr.send();
}
const animation = { };
const config = {
type: 'line',
data: {
datasets: [{
borderColor: '#fc9905',
borderWidth: 2,
radius: 0,
data: 0
}
]
},
options: {
animation,
interaction: {
intersect: false
},
plugins: {
legend: false
},
scales: {
x: {
type: 'time',
title: {
display: true,
text: 'time',
color: '#000000',
font: {
size: 20
}
},
ticks :
{
color: '#000000',
font: {
size: 12
}
}
},
y: {
type: 'linear',
title: {
display: true,
text: 'Electrical field [V/m] # PWM=190',
color: '#000000',
font: {
size: 20
}
},
ticks :
{
color: '#000000',
font: {
size: 12
}
}
}
},
plugins: {
title: {
display: true,
text: 'Electrical field value [V/m]'
}
}
}
};
Chart.defaults.font.size = 20;
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, config);
function addData(chart, data) {
for (var i = 0 ; i < data.length; i++){
chart.data.datasets[0].data.push({"x":data[i].x,"y":(data[i].y-32.671)/0.48025});
};
chart.update();
};
function getData() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var txt = this.responseText;
var array = JSON.parse(txt); //Ref: https://www.w3schools.com/js/js_json_parse.asp
addData(myChart,array);
}
};
xhttp.open("GET", "readEFM", true); //Handle readADC server on ESP32
xhttp.send();
};
setInterval(function() {
getData();
}, 5000);
txt = '[{"x":1662921606250,"y":35.71},{"x":1662921606450,"y":35.61},{"x":1662921606650,"y":35.70},{"x":1662921606850,"y":35.74},{"x":1662921607050,"y":35.78},{"x":1662921607250,"y":35.45},{"x":1662921607450,"y":35.65},{"x":1662921607650,"y":35.66},{"x":1662921607850,"y":35.78},{"x":1662921608050,"y":35.76}]';
const myArr = JSON.parse(txt);
addData(myChart,myArr);
myChart.update();
function saveAs(){
let csvContent = "data:text/csv;charset=utf-8,";
for (var i = 0 ; i < myChart.data.datasets[0].data.length; i++){
csvContent+=myChart.data.datasets[0].data[i].x + "," + myChart.data.datasets[0].data[i].y + "\n";
}
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "EFM_log.csv");
document.body.appendChild(link);
link.click();
};
</script>
</body>
</html>

return isTrusted false

I'm writing my first web component with Stencil.
It's a pills component published here : https://github.com/reservoir-dogs/rp-pills
The component code's :
import { Component, Prop, Watch, Event, EventEmitter } from '#stencil/core';
#Component({
tag: 'rp-pills',
styleUrl: 'rp-pills.scss',
shadow: false
})
export class RpPills {
#Prop() items: any[] = [];
#Prop() displayProperty: string;
#Prop({ mutable: true }) value: any;
#Prop() class: string;
#Prop() theme: string = 'default';
#Prop() emptyMessage: string = 'No item';
classes: string;
#Event() valueChange: EventEmitter;
onClick(item: any) {
this.value = item;
this.valueChange.emit(this.value);
}
#Watch('class')
#Watch('theme')
watchHandler() {
this.classes = `nav nav-pills ${this.theme} ${this.class}`;
}
render() {
if (this.items.length > 0)
return (
<ul class={this.classes}>
{this.items.map((item) =>
<li onClick={() => this.onClick(item)} class={this.value === item ? 'active' : ''} >
<a>{item[this.displayProperty]}</a>
</li>)}
</ul>
);
else
return (
<ul class={this.classes}>
<li class="empty">
<a>{this.emptyMessage}</a>
</li>
</ul>
);
}
}
This test work fine :
it('should work with a list of items and selected item', async () => {
const cmp = new RpPills();
cmp.valueChange = {
emit: () => { }
};
const spy = jest.spyOn(cmp.valueChange, 'emit');
cmp.onClick({name:'Coucou'});
expect(spy).toHaveBeenCalledWith({ name: 'Coucou' });
});
But my HTML sample and an integration in Ionic App does not work and return the following message : {"isTrusted":false}
HTML sample :
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
<title>Stencil Component Starter</title>
<script src="/build/rppills.js"></script>
</head>
<style>
.orange .active a {
background-color: #ff0000;
}
.orange a {
background-color: #ff6a00;
}
div {
float: left;
clear: both;
}
</style>
<body>
<div>
<rp-pills display-property="name" class="nav-pills-bordered" theme="orange">
</rp-pills>
<span></span>
</div>
<div>
<rp-pills display-property="name" class="nav-justified">
</rp-pills>
<span></span>
</div>
<div>
<rp-pills display-property="name" class="nav-pills-bordered nav-justified">
</rp-pills>
<span></span>
</div>
<div>
<rp-pills class="nav-pills-bordered">
</rp-pills>
<span></span>
</div>
<div>
<rp-pills empty-message="Aucun message" class="nav-pills-bordered">
</rp-pills>
<span></span>
</div>
<div>
<rp-pills>
</rp-pills>
<span></span>
</div>
<script>
var cmps = document.querySelectorAll('rp-pills');
for (var i = 0; i < cmps.length; i++) {
var cmp = cmps[i];
if (cmp.attributes.length > 0 && cmp.attributes[0].name == 'display-property') {
cmp.value = { 'name': 'Coucou' };
cmp.items = [cmp.value, { 'name': 'Comment ca va ?' }, { 'name': 'Au revoir' }];
cmp.addEventListener('valueChange', (event) => { alert(JSON.stringify(event)); });
}
}
setInterval(() => {
var cmps = document.querySelectorAll('rp-pills');
var spans = document.querySelectorAll('span');
for (var i = 0; i < cmps.length; i++) {
if (cmps[i].value != undefined)
spans[i].innerText = cmps[i].value.name;
}
}, 1000);
</script>
</body>
</html>
2 errors
I tried to do that :
<rp-pills [items]="jeux" [(value)]="partie.jeu"></rp-pills>
The event of my Stencil component's :
is not compliant with angular two-way binding
contain a property 'detail' where there is my value
Use in Ionic App
HTML code
<rp-pills [items]="jeux" [value]="partie.jeu" (valueChange)="jeuChange($event.detail)"></rp-pills>
TypeScript code
jeuChange(jeu: Jeu) {
this.partie.jeu = jeu;
}

RTL picker with dependent values

The reequirement is to make an RTL picker with multiple levels.
I copied the example from the documentation into a page equiped with the official frameworks' CSS for RTL users.
I have modified "textAlign" properties of each column as well.
For some reason the picker isn't acting as expected. open the snippet in full page mode.
var app = new Framework7({
root: '#app',
rtl: true,
theme: 'md'
});
app.views.create('#mainView', {
});
var carVendors = {
Japanese: ['Honda', 'Lexus', 'Mazda', 'Nissan', 'Toyota'],
German: ['Audi', 'BMW', 'Mercedes', 'Volkswagen', 'Volvo'],
American: ['Cadillac', 'Chrysler', 'Dodge', 'Ford']
};
var pickerDependent = app.picker.create({
inputEl: '#demo-picker-dependent',
rotateEffect: true,
formatValue: function(values) {
return values[1];
},
cols: [{
textAlign: 'right',
values: ['Japanese', 'German', 'American'],
onChange: function(picker, country) {
if (picker.cols[1].replaceValues) {
picker.cols[1].replaceValues(carVendors[country]);
}
}
},
{
textAlign: 'right',
values: carVendors.Japanese,
width: 160,
},
],
routableModals:false
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/framework7/2.3.0/css/framework7.rtl.md.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/framework7/2.3.0/js/framework7.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block-title">
Dependent values</div>
<div id="app">
<div id="mainView">
<div class="list no-hairlines-md">
<ul>
<li>
<div class="item-content item-input">
<div class="item-inner">
<div class="item-input-wrap">
<input type="text" placeholder="Your car" readonly="readonly" id="demo-picker-dependent" />
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
That seems like a bug in Framework7.
CSS 'right' and 'left' properties for first and last '.picker-column' don't fit RTL layout (flipped). The attached repair solved it.
var app = new Framework7({
root: '#app',
rtl: true,
theme: 'md'
});
app.views.create('#mainView', {
});
var carVendors = {
Japanese: ['Honda', 'Lexus', 'Mazda', 'Nissan', 'Toyota'],
German: ['Audi', 'BMW', 'Mercedes', 'Volkswagen', 'Volvo'],
American: ['Cadillac', 'Chrysler', 'Dodge', 'Ford']
};
var pickerDependent = app.picker.create({
inputEl: '#demo-picker-dependent',
rotateEffect: true,
formatValue: function(values) {
return values[1];
},
cols: [{
textAlign: 'right',
values: ['Japanese', 'German', 'American'],
onChange: function(picker, country) {
if (picker.cols[1].replaceValues) {
picker.cols[1].replaceValues(carVendors[country]);
}
}
},
{
textAlign: 'right',
values: carVendors.Japanese,
width: 160,
},
],
routableModals:false
});
.picker-column.picker-column-first:after{
left:100% !important;
right:0 !important;
}
.picker-column.picker-column-last:after{
left:0 !important;
right:100% !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/framework7/2.3.0/css/framework7.rtl.md.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/framework7/2.3.0/js/framework7.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block-title">
Dependent values</div>
<div id="app">
<div id="mainView">
<div class="list no-hairlines-md">
<ul>
<li>
<div class="item-content item-input">
<div class="item-inner">
<div class="item-input-wrap">
<input type="text" placeholder="Your car" readonly="readonly" id="demo-picker-dependent" />
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
EDIT:
github issue

Using a Query to retrieve data from a googlesheet and push it into a dashboard

I am trying to withdraw data from a google spreadsheet, convert it into a DataTable and push the values into a Dashboard LineChart according to Google Apps documentation. I have managed to do this with an array I manually populated but I have not managed to figure out how to do this properly with a spreadsheet. It currently states that one or more participants failed to draw and I have an invalide column label. Any ideas what I am doing wrong.
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart', 'controls']});
google.charts.setOnLoadCallback(drawStuff);
function initialize() {
var opts = {sendMethod: 'auto'};
// Replace the data source URL on next line with your data source URL.
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1bqRWtvB6kxBfeIuVzCwVXZ5_mCn1b542CaIwE116jK8/edit#gid=0', opts);
query.setQuery("Select *");
// Send the query with a callback function.
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
if (response.isError()){
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
else {
var data = response.getDataTable();
return data;
}
}
function drawStuff() {
var data = initialize;
var dashboard = new google.visualization.Dashboard(
document.getElementById('programmatic_dashboard_div'));
// We omit "var" so that programmaticSlider is visible to changeRange.
programmaticSlider = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'programmatic_control_div',
'options': {
'filterColumnLabel': 'Query',
'ui': {'labelStacking': 'vertical'}
}
});
programmaticChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'programmatic_chart_div',
'options': {
'width': 750,
'height': 300,
'legend': {position: 'top', textStyle: {color: 'blue', fontSize: 16}},
'chartArea': {'left': 15, 'top': 15, 'right': 0, 'bottom': 0},
'chart': {
title: 'Popular Queries',
subtitle: 'by number of clicks'
},
}
});
dashboard.bind(programmaticSlider, programmaticChart);
dashboard.draw(data);
}
</script>
</head>
<body>
<div id="programmatic_dashboard_div" style="border: 1px solid #ccc">
<table class="columns">
<tr>
<td>
<div id="programmatic_control_div" style="padding-left: 2em; min-width: 250px"></div>
<div>
<button style="margin: 1em 1em 1em 2em" onclick="changeRange();">
Select range [2, 5]
</button><br />
</div>
<script type="text/javascript">
function changeRange() {
programmaticSlider.setState({'lowValue': 2, 'highValue': 5});
programmaticSlider.draw();
}
</script>
</td>
<td>
<div id="programmatic_chart_div"></div>
<div id="chart_div"></div>
</td>
</tr>
</table>
</div>
</body>
</html>

Angular ajax $http cannot post and get in same time

I'm trying to use MEAN stack store and update a simple angular to do list, I've write a restful api for server.the post record function app.addTask = function(task) working fine if I remove $http.get from html, but once put it back, it stop record the new task.
Can't figure it out why, need your guys help.
Here is the server.js
var express = require('express'),
restful = require('node-restful'),
bodyParser = require('body-Parser'),
methodOverride = require('method-override'),
mongoose = restful.mongoose;
var app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
mongoose.connect('mongodb://localhost/transTaskDB');
//create new collection
var TaskSchema = mongoose.Schema({
contents: String,
target: String,
color: String,
status: Boolean
});
var Tasks = restful.model('tasks', TaskSchema);
// Tasks.methods(['get', 'post', 'put', 'delete']);
// Tasks.register(app, '/api/tasks');
// ROUTES FOR OUR API
//===============================================
var router = express.Router(); //get an instance of express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Shown when each request made.');
next(); // make sure we go to the next routes and don't stop here
});
//custom filter find the last entry record
//record new task
router.route('/newtask')
.post(function(req, res){
//create a new instance of the task model
var task = new Tasks();
task.contents = req.body.taskContent;
task.target = req.body.taskUser;
task.color = req.body.taskColor;
// task.contents = "have a tea";
// task.target = "tony";
// task.color = "#e74c3c";
task.status = false; //** fasle means the task still open not done
//task.save();
//throw error exception in console
task.save(function(err, tasks) {
if (err)
res.send(err);
res.json(tasks);
});
})
.get(function(req, res){
Tasks.find(function(err, tasks) {
if (err)
res.send(err);
res.json(tasks);
});
});
//REGISTER OUT ROUTES --------
//all of our route will be prefixed with /api
app.use('/api/tasks', router);
app.listen(3000);
console.log('Server is running at port 3000');
html
<!doctype html>
<html lang='en' ng-app='TaskAPP'>
<head>
<meta charset='UTF-8'>
<title>Trans Task</title>
<link rel='stylesheet' href='bower_components/bootstrap-sass/dist/css/bootstrap.min.css' type='text/css'>
<link rel='stylesheet' href='bower_components/bootstrap-sass/dist/css/bootstrap-theme.min.css' type='text/css'>
<style>
body {
background-image: url('images/swirl_pattern.png');
background-repeat: repeat-y repeat-x;
}
.done {text-decoration: line-through; color: #ccc;}
.task-list {list-style: none;}
.published-list {
padding: 10px 40px;
}
.published-list >div {
padding: 20px;
border-radius: 10px;
font-size:20px;
color: white;
}
</style>
</head>
<body>
<div class="container">
<nav class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="#">
<span class="glyphicon glyphicon-tower"></span> Trans Task
</a>
</div>
</nav>
<div ng-controller='taskCtrl as app'>
<form role="form" name='frm2' ng-submit="app.addTask(app.task)">
<div class="form-group">
<label>Task Contains</label>
<input type='text' name='taskInput' class='form-control' ng-model="app.task.taskContent" placeholder="Enter task" required/>
</div>
<div class="form-group">
<!--need find a way to load the registed users from mongodb-->
<!--apply socket.io on each individual user to get realtime task update and update manager the roger response-->
<label>Target assign to</label>
<input type='text' name='taskInput' class='form-control' ng-model="app.task.taskUser" placeholder="Enter name" required/>
</div>
<div class="form-group">
<label>with color</label>
<select ng-model="app.task.taskColor">
<option ng-repeat="col in colors" value="{{col.color}}" >{{col.title}}</option>
</select>
</div>
<button class="btn btn-primary" ng-disabled='frm2.$invalid'>Publish</button>
</form>
<ul class='task-list'>
<li class="published-list" ng-repeat="tsk in app.task">
<div ng-style={'background-color':tsk.color}>
<input type='checkbox' ng-model='tsk.status'>
<span ng-class='{"done":tsk.status}'>{{tsk.contents}}</span>
</div>
</li>
</ul>
<!-- <button class="btn btn-danger" ng-click='clearCompleted()'>Clear Completed</button> -->
</div>
</div>
<script src='bower_components/jquery/dist/jquery.min.js'></script>
<script src='bower_components/angular/angular.min.js'></script>
<script src='bower_components/bootstrap-sass/dist/js/bootstrap.min.js'></script>
<script>
//angular parts
var app = angular.module('TaskAPP',[]);
//ajax sample
app.controller("taskCtrl", function($scope, $http) {
$scope.colors = [
{'title': 'red', 'color': '#e74c3c', 'status':true}, {'title': 'green', 'color': '#2ecc71', 'status':true}, {'title': 'amber', 'color': '#f39c12', 'status':true}
];
//you are the problem
var app = this;
$http.get("http://localhost:3000/api/tasks/newtask")
.success(function(data) {
//the return is the tasks json file
app.task = data;
})
app.addTask = function(task) {
$http.post("http://localhost:3000/api/tasks/newtask", task)
.success(function(data) {
//the return is the tasks json file
app.task = data;
})
}
})
</script>
</body>
</html>

Resources