AngularJS how to get data from <textarea> prefilled by Google Maps script - html

I have a script that accesses the Goggle Maps API and fills in a <textarea> with results. How do I pass that prefilled data into an AngularJS controller?
$scope.Add=function(msg){
$log.log(msg)
}
<div ng-app="">
<div ng-controller="MapController">
<div style="display:block">
<div id="map" style="float:left"></div>
<div style="float:left;">
<textarea class="user" ng-model="user" id="points_textarea"></textarea>
<input type="button" value="submit" ng-click="Add(user)" />
</div>
</div>
i am new to angularjs,
how to pass the data from textarea which is already prefilled from one of the javascript function in html, to the controller in angularjs
Any help please

Bring the Google Maps functions into the AngularJS framework:
angular.module("gMap", [])
.service("gMap", function($q) {
var directionsService = new google.maps.DirectionsService();
var map;
var origin = null;
var destination = null;
var waypoints = [];
var markers = [];
this.initialize = initialize;
this.calcRoute = calcRoute;
this.reset = reset;
//functions here
});
Modify the calcRoute function to return a promise:
function calcRoute() {
var mode = google.maps.DirectionsTravelMode.DRIVING;
var request = {
origin: origin,
destination: destination,
waypoints: waypoints,
travelMode: mode,
optimizeWaypoints: true,
avoidHighways: false
};
var pointsDefer = $q.defer();
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
//Code snipped
̶v̶a̶r̶ ̶p̶o̶i̶n̶t̶s̶_̶t̶e̶x̶t̶a̶r̶e̶a̶=̶d̶o̶c̶u̶m̶e̶n̶t̶.̶g̶e̶t̶E̶l̶e̶m̶e̶n̶t̶B̶y̶I̶d̶(̶"̶p̶o̶i̶n̶t̶s̶_̶t̶e̶x̶t̶a̶r̶e̶a̶"̶)̶;̶
̶p̶o̶i̶n̶t̶s̶_̶t̶e̶x̶t̶a̶r̶e̶a̶.̶v̶a̶l̶u̶e̶ ̶=̶ ̶p̶o̶i̶n̶t̶s̶_̶t̶e̶x̶t̶;̶
var pointsObj = {};
pointsObj.routeCenter = response.routes[0].bounds.getCenter();
pointsObj.routeSpan = response.routes[0].bounds.toSpan();
pointsObj.routePoints =
response.routes[0].overview_path
.map( _ => ({
lat: _.lat(),
lng: _.lng()
}));
pointsDefer.resolve(pointsObj);
clearMarkers();
directionsDisplay.setDirections(response);
} else { pointsDefer.reject(status); };
});
return pointsDefer.promise;
}
Notice that the above function removes the code that fills in the <textarea> with the data. Instead the code returns an AngularJS promise that resolves with the data.
Replace the <textarea> in the HTML
<body ng-app="app" ng-controller="ctrl as vm">
<h2>Google Map route point generator</h2>
Click on the map to select the route points (up to 8).
<br/><br/>
<input type="button" value="Get Points" ng-click="vm.calcRoute()" />
<input type="button" value="Reset" ng-click="vm.reset()" />
<br/><br/>
<div id="map_canvas"></div>
<br/>
̶<̶t̶e̶x̶t̶a̶r̶e̶a̶ ̶r̶e̶a̶d̶o̶n̶l̶y̶ ̶i̶d̶=̶"̶p̶o̶i̶n̶t̶s̶_̶t̶e̶x̶t̶a̶r̶e̶a̶"̶ ̶o̶n̶C̶l̶i̶c̶k̶=̶"̶s̶e̶l̶e̶c̶t̶_̶a̶l̶l̶(̶)̶;̶"̶>̶
̶<̶/̶t̶e̶x̶t̶a̶r̶e̶a̶>̶
<br/>
{{vm.points | json}}
</body>
The App
angular.module("app",['gMap'])
.run(function(gMap){
gMap.initialize();
})
.controller("ctrl", function(gMap) {
this.calcRoute = function() {
var promise = gMap.calcRoute();
promise.then( data => {
this.points = data;
})
};
this.reset = function() {
gMap.reset();
this.points = {};
};
})
The DEMO on PLNKR

You can use ng-model and ng-bind for these.
Check this in angular 4 - https://coursetro.com/posts/code/58/Angular-4-Property-Binding-Tutorial
And in Angular 1 - https://docs.angularjs.org/api/ng/directive/ngBind

HTML :
<textarea rows="4">{{user.content}}</textarea>
JS:
var app = angular.module('myApp', []);
app.controller('userCtrl', function($scope) {
$scope.user = {
'content': 'Theming support in an application can be pretty useful.'
};
});

I have made you simple plnkr example
It will show prefilled data and on change of textarea it will show alert
Main thing to understand is ng-model, it is binding your input type="textarea" with variable textArea by using ng-model="textArea"
https://plnkr.co/edit/rml2JC8YZgLDTyLgq7x3?p=preview

You can define your Textarea like this:
<textarea ng-model='test_textarea'></textarea>
Then you should initialize your textarea in controller like this:
$scope.test_textarea = "content";
Your angular app initializes when the documents DOM is ready - thus, overrides the value with your $scope.test_textarea value.

Related

Why I'm getting this error "Cannot draw chart: no data specified."?

I'm trying to load my google spreadsheet into my very basic webapp but I keep getting this error "Cannot draw chart: no data specified." what I'm doing wrong ?
Here is my HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
const loaded = new Promise((res, rej) => {
google.charts.load('current');
google.charts.setOnLoadCallback(res);
});
let wrapper = null;
async function drawTable(arr) {
await loaded; //wait if charts is not loaded
wrapper = new google.visualization.ChartWrapper({
chartType: 'Table',
dataTable: arr,
containerId: 'table_div',
});
wrapper.draw();
}
function getData(form) {
google.script.run
.withSuccessHandler(drawTable)
.getDataFromServer(form);//change server function name
}
</script>
</head>
<body>
<form>
<input type="text" name="searchtext" />
<input type="button" value="ok" onclick="getData(this.parentNode)" />
</form>
<div id="table_div"></div>
</body>
</html>
and here is my CODE.GS
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function getDataFromServer(e) {
var id ="1GRi3NAdannp3uNDi202HC5hKNMNIVMNw_WPDYIes5Hs";
var data = SpreadsheetApp.openById(id)
.getSheetByName("Daily report")
.getDataRange()
.getValues();
var ar = data.splice(0,1); //add headers
data.forEach(function(f) {
if (~f.indexOf(e.searchtext)) ar.push(f);
});
return ar;
}
And this is the link of my google spreadsheet .
https://docs.google.com/spreadsheets/d/1GRi3NAdannp3uNDi202HC5hKNMNIVMNw_WPDYIes5Hs/edit?usp=sharing
Thanks,
Here's a simple example of how I load data into a chart. First column date string and the other four columns are numbers.
function drawMealsChartOld(){
$('#btnC').css('background-color','#ffff00');
google.script.run
.withSuccessHandler(function(mObj){
var dt=mObj.dA;
var hA=dt[0];
dt.splice(0,1);
var dA=dt.slice();
var data = new google.visualization.DataTable();
for(var i=0;i<hA.length;i++){
if(i===0){
data.addColumn('string',hA[i]);
}else{
data.addColumn('number',hA[i]);
}
}
data.addRows(dA);
var options={
title:'Meals Grams (Starts: ' + mObj.start + ' - Ends: ' + mObj.end + ')',
fontSize: 14,
fontName: 'Roman',
width:640,
height:350,
pointSize:3,
hAxis:{slantedText:true,slantedTextAngle:90,textStyle:{color:'#333300',fontName:'Verdana',fontSize:8,bold:true}},
legend:{position:'top'},
chartArea:{left:75,top:75,width:'75%',height:'50%'},
series:{0: {targetAxisIndex: 0}, 1:{targetAxisIndex: 0}},
vAxes:[{title:'GRAMS',titleTextStyle:{color:'#0000CC',fontName:'Verdana',fontSize:12,bold:true,italic:false},textStyle:{color:'#0000CC',fontName:'Verdana',fontSize:10,bold:true,italic:false}}]
};
var chart=new google.visualization.LineChart(document.getElementById('mcht'));
//Not interested in emailing this chart I just want to be able to see how the average is doing.
//google.visualization.events.addListener(chart,'click',function(){emailVitalsDialog()});
//google.visualization.events.addListener(chart,'ready',function(){
//gImgObj['base64Data']=chart.getImageURI().split(',')[1];
//gImgObj.ready=true;
//});
chart.draw(data,options);
$('#btnC').css('background-color','#ffffff');
})
.getMealsData();
}

Google Maps API: how to check if an address or location is valid?

Here's my problem: I have a web page where I'm trying to use autocomplete, like that, very very basic:
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<script type="text/javascript">
$(document).ready(function () {
new google.maps.places.Autocomplete(
document.getElementById('testtest'), {}
);
</script>
When the user posts the form, on the server side, I will get a text value like
"Pentagone, North Rotary Road, Arlington, Virginie, États-Unis"
and so. So, on the server side, is there a way to validate that this address is good ie ask google?
I don't know why it has to be on the server side. You should be doing that with Google as soon as they enter it. Don't make them submit the form and have to do it all over again because you want to do validation on the server side.
HTML
<input type="text" id="address" onchange="doGeocode()" />
<!-- require Google Maps API -->
<script src="//maps.googleapis.com/maps/api/js"></script>
JS
function doGeocode() {
var addr = document.getElementById("address");
// Get geocoder instance
var geocoder = new google.maps.Geocoder();
// Geocode the address
geocoder.geocode({
'address': addr.value
}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK && results.length > 0) {
// set it to the correct, formatted address if it's valid
addr.value = results[0].formatted_address;;
} else {
// show an error if it's not
alert("Invalid address");
}
});
};
However, if you want to use PHP you can try this...
function geocode($address) {
$return = array();
$address = urlencode($address);
$key = "put your key here,,,";
$url = "https://maps.google.com/maps/api/geocode/json?key=$key&address={$address}";
$resp_json = file_get_contents($url);
$resp = json_decode($resp_json, true);
if ($resp['status']!=='OK') return false;
foreach($resp['results'] as $res) {
$loc = array(
"zipcode"=>null,
"formatted"=>null
);
foreach ($res['address_components'] as $comp) {
if (in_array("postal_code", $comp['types']))
$loc['zipcode'] = $comp['short_name'];
}
$loc['formatted'] = $res['formatted_address'];
$loc['lng'] = $res['geometry']['location']['lng'];
$loc['lat'] = $res['geometry']['location']['lat'];
$return[] = $loc;
}
return $return;
}
Angular 12
I still haven't found a valid solution to this from Google. This is what I did:
I have a field variable within my component:
validRegion: boolean = false;
Whenever the event handler from Google Maps Places Autocomplete fires (only fires if a valid location is found), I toggle the field variable to true.
private getPlaceAutocomplete() {
const autocomplete = new google.maps.places.Autocomplete(this.addresstext.nativeElement,
{
componentRestrictions: { country: 'AUS' },
types: [this.adressType] // 'establishment' / 'address' / 'geocode'
});
google.maps.event.addListener(autocomplete, 'place_changed', () => {
const place = autocomplete.getPlace();
console.log(place.geometry.location.lat());
console.log(place.geometry.location.lng());
this.validRegion = true; # TOGGLE HERE
console.log(this.validRegion);
});
}
To ensure that the user can not change the location to an invalid location after a valid one has been found - I set a keystroke event (keydown) on the input to set the validRegion variable back to false. This will only become true once the event handler fires again
<input
matInput
required
class="input"
type="text"
[(ngModel)]="autocompleteInput"
#addresstext
(keyup)="validationRegion()"
>
validationRegion(){
this.validRegion = false;
}

How to put REST response back in angular JS tag to draw D3 js pie chart

I started learning Angular Js and D3 Js this week. The code below may be pathetic but please bear with me.
Problem: I am trying to consume a REST service which returns json {"chatjson":"[10,20,30]"}.
I want to draw a pie chart using [10,20,30] received from REST.
Code OverView: I am consuming three REST service in ng-controller 'validateCtrl'. two services are running fine and showing desired data in angular but the from third REST (see function '$scope.getChartData' ) which returns {"chatjson":"[10,20,30]"} , which is JSON , which should show a pie chart based on the response at
donut-chart tag in angular code, which I am not getting.
The D3 Js code is written at the bottom section. D3 code works fine with hardcoded data.
Actual code
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
<html>
<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<h2>Angular Example</h2>
<form ng-app="myApp" ng-controller="validateCtrl"
name="myForm" novalidate>
<p>Username:<br>
<input type="text" name="user" ng-model="user" required>
<span style="color:red" ng-show="myForm.user.$dirty && myForm.user.$invalid">
<span ng-show="myForm.user.$error.required">Username is required.</span>
</span>
</p>
<p>country:<br>
<input type="text" name="country" ng-model="country" required>
<span style="color:red" ng-show="myForm.country.$dirty && myForm.country.$invalid">
<span ng-show="myForm.country.$error.required">country is required.</span>
</span>
</p>
<p>
<input type="submit" value="save" ng-click="send()"
ng-disabled="myForm.user.$dirty && myForm.user.$invalid ||
myForm.country.$dirty && myForm.country.$invalid">
</p>
<ul>
<li ng-repeat="y in detail">
{{ y.name + ', ' + y.country }}
</li>
</ul>
<input type="submit" value="Get Country List" ng-click="getData()">
<input type="submit" value="Get Pie Chart" ng-click="getChartData()">
<ul>
<li ng-repeat="x in names">
{{ x.name + ', ' + x.country }}
</li>
</ul>
<div>
<donut-chart data="chartData"></donut-chart>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('validateCtrl', function($scope,$http) {
$scope.chartData=[12,13,60]; // Hard coded for testing purpose
$scope.user = 'Anukul';
$scope.country = 'India';
//=============== REST for fetching data from DB for Table details ==============
$scope.getData = function(){
var getApi="http://localhost:9080/nextapp/person/getList";
$http.get(getApi).success(function(response){$scope.names=response.records;
});
};
//=============== REST for fetching data for drawing chart ==============
$scope.getChartData = function(){
var getchartApi="http://localhost:9080/nextapp/person/getChart";
$http.get(getchartApi).success(function(response){$scope.chartData=response;
});
};
//=============== REST for inserting data in DB ==============
$scope.send = function(){
var name = $scope.user;
var country = $scope.country;
var api="http://localhost:9080/nextapp/person/"+name+"/"+country;
$http.get(api)
.success(function(response) {$scope.detail = response.result;});
};
//========== End of REST ==============================
});
//===================== new add for D3 Pie chart ============
app.directive('donutChart',function(){
function link(scope,el){
//---- D3 code goes here
var data = scope.data;
var color = d3.scale.category10()
var el = el[0]
var width = 500
var height = 500
var min = Math.min(width,height)
var pie = d3.layout.pie().sort(null)
var arc = d3.svg.arc()
.outerRadius(125)
.innerRadius(75)
var group = d3.select(el).append('svg')
.attr({width:width,height:height})
.append('g')
.attr('transform','translate('+width/2+','+height/2+')')
var arcs = group.selectAll(".arc")
.data(pie(data))
.enter()
.append('g')
.attr("class","arc")
arcs.append("path")
.attr("d",arc)
.attr("fill",function(d){return color(d.data);});
arcs.append("text")
.attr("transform",function(d){return "translate (" + arc.centroid(d)+")";})
.text(function(d){return d.data;});
//d3.select(el[0]).append('svg')
}
return{
link: link,
restrict:'E',
scope:{data:'='}
}
}
)
</script>
</body>
</html>
I think the main issue is that directives only run their link function once. The code posted in your question does all the drawing in the link function, which will only ever have access to the initial hard-coded data.
The solution, then, is to separate the drawing code from the link function in a form that you can call from a watcher:
app.directive('donutChart',function(){
function link(scope,element){
scope.el = element[0]; // Cache a reference to the element
draw(scope.data, scope.el); // Initial draw
}
function draw(data, el) {
var color = d3.scale.category10(),
width = 500,
height = 500,
min = Math.min(width,height),
pie = d3.layout.pie().sort(null),
arc = d3.svg.arc()
.outerRadius(125)
.innerRadius(75);
d3.select("svg").remove(); // Clear old pie chart
var group = d3.select(el).append('svg')
.attr({width:width,height:height})
.append('g')
.attr('transform','translate('+width/2+','+height/2+')'),
arcs = group.selectAll(".arc")
.data(pie(data))
.enter()
.append('g')
.attr("class","arc");
arcs.append("path")
.attr("d",arc)
.attr("fill",function(d){return color(d.data);});
arcs.append("text")
.attr("transform",function(d){return "translate (" + arc.centroid(d)+")";})
.text(function(d){return d.data;});
}
return{
link: link,
restrict:'E',
scope:{data:'='},
// Add a controller here to $watch for data changes
controller: function($scope) {
$scope.$watch('data', function(newData) {
draw(newData, $scope.el); // Re-draw the chart
});
}
};
});
Another thing I noticed might not be an actual issue because it depends on the actual server response. When setting the chart data, you do this:
$scope.chartData = response;
However, according to the text of your question, the expected response is like:
{ "chartjson": [10, 20, 30] }
If that's the case, and your test chart data is just an array, as seen here:
$scope.chartData = [12, 13, 60];
Then I would expect to get the array from the response like this:
$scope.chartData = response.chartjson;
You can see in this plunker that I mocked out $httpBackend to return the example object from your question, and this appears to work.

Text input is using original typed text instead of selected google place autocomplete text

I'm using the Google Maps JavaScript API v3 to autocomplete a text input in my angular/node app.
The problem I'm running into is that for some reason, my angular function is using the original typed text instead of the selected google place autocomplete text that gets filled into the text input.
Here is what happens (in pictures!):
1) Type in the beginning of the place I'm looking for
2) click on the autocomplete place, which fills the text input
3) The string used in my get calls to Google Places API is the original "siz" from step one instead of the place info from autocomplete, which returns the wrong place
Here is the code that I think is relevant to this problem:
From main.html:
<form class="form-horizontal" role="form">
<div class="input-group">
<input ng-model="businessName" googleplace class="form-control input-lg">
<span class="input-group-btn">
<button ng-click="findGPlace2()" class="btn btn-default" type="button">Find!</button>
</span>
</div><!-- /input-group -->
From Google.js controller (the console.log($scope.businessName); is printing out siz in this example):
$scope.findGPlace2 = function() {
console.log($scope.businessName);
GoogleService.findPlace2($scope.businessName).then(function(data) {
$scope.gPlace2 = data;
// for(var i = 0; i < data.results.length; i++) {
// console.log(data.results[i]);
// }
showGData(data.results[0].place_id);
});
};
From App.js (custom autocomplete directive):
analyticsApp.directive('googleplace', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, model) {
var options = {
types: [],
componentRestrictions: {}
};
scope.gAuto = new google.maps.places.Autocomplete(element[0], options);
google.maps.event.addListener(scope.gPlace, 'place_changed', function() {
scope.$apply(function() {
model.$setViewValue(element.val());
});
});
}
};
});
There must be something wrong with your googleplace directive.
Check this fiddile. It might help you
scope.gAuto = new google.maps.places.Autocomplete(element[0], options);
This should be
scope.gPlace = new google.maps.places.Autocomplete(element[0], options);
I think that should do it.

sending konckoutjs ViewModel as data throught ajax

for populating search form with data i'm using following ViewModel:
function AppViewModel() {
var self = this;
self.Countries =[{"id": "1","name": "Russia"},{"id": "2","name": "Qatar"}];
self.selectedCountryId =ko.observable();
}
I need Countries list for populate dropdwonlist.
When user fills the form and clicks "send", i need to submit the data, but i do not need to send the Countries list!
(only SelectedCountryId)
var vm=new AppViewModel();
ko.applyBindings(vm);
$('button').click(function(){
console.log(ko.mapping.toJSON(vm));
});
Is there the way to get rid of countries list without build new ViewModel for sending?
Observables are just like normal functions, so you just need to call it from outside.
function AppViewModel() {
var self = this;
self.Countries =[{"id": "1","name": "Russia"},{"id": "2","name": "Qatar"}];
self.selectedCountryId = ko.observable('1');
}
$(function() {
var vm = new AppViewModel();
ko.applyBindings(vm);
$('button').click(function(){
console.log(vm.selectedCountryId()); // plain
console.log(ko.toJSON(vm.selectedCountryId())); // json
});
});
​
http://jsfiddle.net/DiegoVieira/6kZMj/4/
Please take a look into this demo I've created for you Click here for the DEMO
Updated Demo Click here for the updated Demo
HTML Code
<select data-bind="options: countries, optionsText: 'name', optionsValue: 'id', value: selectedChoice, optionsCaption: 'Choose..'"></select>
<br/>
<label data-bind="text: selectedChoice"></label>
Javascript Code
var CountryModel = function(data){
var self = this;
self.id = ko.observable(data.id);
self.name = ko.observable(data.name);
};
var viewModel = function(data) {
var self = this;
self.selectedChoice = ko.observable();
self.countries = ko.observableArray([
new CountryModel({id: "1", name: "Russia"}),
new CountryModel({id: "2", name: "Qatar"})]);
};
ko.applyBindings(new viewModel());
START UPDATE
What is updated:
HTML Code:
Added button on event Click it calls sendMe function which returns json object of selectedCountryId
<input type="button" data-bind="click: sendMe, enable: selectedChoice" Value="Click Me"/>
Javascript Code
self.sendMe = function(){
alert(ko.toJSON({ selectedCountryId: this.selectedChoice()}));
};
END UPDATE
START UPDATE1
This is update for the last comment, regarding avoid addition model, in this case let's skip CountryModel
So, the Javascript Code will be the following:
var viewModel = function(data) {
var self = this;
self.selectedChoice = ko.observable();
self.countries = ko.observableArray([
{id: "1", name: "Russia"},
{id: "2", name: "Qatar"}]);
self.sendMe = function(){
alert(ko.toJSON({ selectedCountryId: this.selectedChoice()}));
};
};
ko.applyBindings(new viewModel());
END UPDATE1
Hope, it will help you.
Thanks.