How to log all properties from an object in google script - arrays

I am trying to get all the properties of array object routes to be logged 1 by 1, however, it's giving undefined error.
function testRoutes () { //Calling the maps API and new direction finder.
var directions = Maps.newDirectionFinder()
.setOrigin('Kharadar, Karachi')
.setDestination('Guru Mandir, Karachi')
.setMode(Maps.DirectionFinder.Mode.DRIVING) //By default driving.
.getDirections();
//We have got all the directions now from origin to destination in test variable.
// var route = directions.routes[0].legs[0].steps[1];
// var route2 = directions.routes[0];
var route = directions.routes;
for (var propt in route) {
Logger.log(route[0].propt);
}
//Logger.log(route[0].summary);
}

If you loop through properties of variable route it should be
for (var propt in route) {
Logger.log(route[propt]);
}

Related

How to loop through an object and push into an array

What I'm working with
angular2
firebase
What I have
A returned object
Each item in the object has a URL property
What I would like to do
Loop through each of the items in the object and get the URL property
Pass that into a firebase storage variable
Push the URL property into an array to make available for my HTML
note: I have this working by hard coding a url, I just need some assistance looping through the object to get the other urls in the object.
Component.ts
'this.imagesToDisplay' will return an object of object (image below)
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
this.testing(this.imageToDisplayArray);
});
Comnponent TS - Testing method
So this is hardcoded and pushes the hardcoded url into the array and displays correctly through databinding with the HTML. Cool. However, I would like to loop through the 'imagesToDisplay' object and get both returned urls.
testing(imageToDisplayArray) {
// this works with one url
var storage = firebase.storage().ref().child("image/-Kosd82P-bmh4SFetuf3/-Kosd8HhGmFiUhYMrlvw/30DD9F39-4684-4AA0-9DBF-3B0F0C3450A4.jpg");
storage.getDownloadURL().then(function(url) {
imageToDisplayArray.push(url);
console.log(imageToDisplayArray);
});
}
Any help here would be massively appreciated.
Note: I think this question here is what I'm trying to do, I'm just not sure how to integrate that into my current code. Any help would be awesome.
Stack Overflow question on firebase storage looping
UPDATE
So, I'm incredibly close now. I just have one issue. The code below loops through the returned data and extract the URL properties. I use the url properties to connect to the firebase storage and return the download URLs. Both of these are logged to the console! Awesome. I now have the URLs i needed! The issue I'm having is, it will only let me push these values to a local array. In this instance 'var array'. I need to push to an array that's outside of the 'activatedRoute' 'method'. Anytime I do, it returns as undefined.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var array = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
console.log(url);
array.push(url);
})
});
});
I would recommend you to use the features rxjs provides you:
this.activatedRoute.data.switchMap(data => {
let parsedData = {
issueToDisplay: data.issueData,
imagesToDisplay: data.issueImageData
}
let imageUrls$ = data.issueImageData.map(image => {
var imagePathReference = storage.ref().child(image);
return Observable.fromPromise(imagePathReference.getDownloadURL())
});
return Observable.forkJoin(imageUrls$).map((...urls) => {
return Object.assign(parsedData, { urls });
})
}).subscribe(data => {
/*
data looks like this:
{
issueToDisplay: any,
imagesToDisplay: any,
urls: string[]
}
*/
});
If I'm correct, you're looking for a solution to map an array-like object of objects to an actual array of objects.
Here is a way to do just that:
var object = {
'0': {
"url": "url1",
"name": "obj1",
"data": 1234
},
'1': {
"url": "url2",
"name": "obj2",
"data": 5678
},
'length': 2
}
var sliced = Array.prototype.slice.call( object, 0 );
console.log(sliced)
Couple remarks:
If you wonder how this works, check this post.
Alternative syntax that you could encounter looks like [].slice.call()
If you want to perform array-like operations, you can probably do that right away with Array.prototype.<METHOD>.call(object, <CALLBACK>
For example:
Array.prototype.map.call(object, function(el) { // return your enhanced element })
So, this works. Not entirely sure how clean it is. But it works.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var localImageArray = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
localImageArray.push(url);
})
this.getIssueImageArray(localImageArray);
});
});
}
// Get Image Array
getIssueImageArray(array) {
this.imageToDisplayArray = array;
}

Protractor : Error: Error while waiting for Protractor to sync with the page: "window.angular is undefined. If i create new object of PageObject

I am trying to create a object of page object into spec and i am getting the error.
dashboard.pageObject.js
/*global exports,console*/
module.exports = function(){
this.dashboarurl = 'http://localhost:2525/ars-webapp/';
this.createNewReport_Clickhear = element(By.xpath("//a[contains(.,'Click Here')]"));
this.reportInputModel = element(by.model('reportDefCntrl.reportDef.reportname'));
this.reportDescriptionModel = element(by.model('reportDefCntrl.reportDef.reportdesc'));
this.templateListSelect = element(By.xpath("//select[#id='template-list-select']")).click();
this.selectAlarmDashboarTemplate= element(By.xpath("//option[contains(#value,'number:2')]"));
this.durationOfAlarmTemplate = element(By.xpath("//span[#class='ui-select-placeholder text-muted ng-binding']"));
this.duration_Daily = element(By.xpath("//span[contains(.,'Daily')]"));
this.addObject = element(By.xpath("//button[#data-ng-click='reportDefCntrl.addLogObjects()']"));
this.searchInput = element(By.xpath("//input[#type='search']"));
this.searchButton = element(By.xpath("//button[contains(.,'Search')]"));
this.selectAllButton = element(By.xpath("//button[contains(.,'SelectAll')]"));
this.addObjectButton = element(By.xpath("//button[#data-ng-click='addLogObjectsCntrl.submitObjects()']"));
this.saveButton = element(By.xpath("//button[contains(.,'Save')]"));
}
Specfile is
/global require,console/
var Dashboard = require('../pageObjects/dashboard.pageObject.js');
var dashboard = new Dashboard();
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get(dashboard.dashboarurl);
}
if i skip the line
var dashboard = new Dashboard();
and provide
browser.get('http://localhost:2525/ars-webapp/');
instead of
browser.get(dashboard.dashboarurl);
it's working .
but i can't use feature of page object.
if i use
var dashboard = new Dashboard();
so i am getting error
E/launcher - Error while waiting for Protractor to sync with the page:
"window.angular is undefined. This could be either because this is a
non-angular page or because your test involves client-side navigation,
which can interfere with Protractor's bootstrapping. See
http://git.io/v4gXM for details"
Oh Man .. found it !!.. Everything was fine in your code. You know what .. The problem was .. you had a click() in this line this.templateListSelect = element(By.xpath("")).click() in your file - dashboard.pageObject.js
Since you have a require() first .. The dashboard file is executed first and click() is trigerred even before browser.get() and thats the reason you were seeing that error

getting location and running a function on a new window (following window.open) and not the old

I'm a junior dev' and trying to open a new window following ng-click on a button, then run a function with setTimeout on the new window in order to parse a parameter from the new window url. This is my code, but it doesn't really work on the new window (nor console.log or alert):
window.open("https://runkeeper.com/apps/authorize?client_id=499eec7e74084561ac8cd8018fd090f2&redirect_uri=http://localhost:3000/&response_type=code")
setTimeout(function(){
var wl = window.location
alert(wl);
wl = wl.href.split("/code")
console.log("this is wl", wl);
wl = wl[1]
carrotService.connectRunkeeper(wl)
}, 5000)
Appreciate your time and help,
Ark
Since you can easily call functions on a popup window's opener why not have your new window call a function on the opener once it resolves to your redirect URI
On the page it redirects to (defined as redirect_uri in your location string), you could have some on-load JS code that gets the parameter you need and sends it to the window.opener
ie:
window.onload = function() {
var val=getQueryVariable(PARAM_YOU_NEED)
window.opener.myFunctionOnWindowLoad(val)
}
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
(Borrowed that non-jQuery param code from https://css-tricks.com/snippets/javascript/get-url-variables/)
Would that fix your wagon or did I misunderstand what you're trying to do?

URL from $routeChangeStart route params in angularjs routes

How would it be possible to get the URL hash fragment from route params in $routeChangeStart.
$scope.$on('$routeChangeStart', function (event, next, current) {
// trying to get the url hash fragment from <next> param here
// e.g. to_url_function(next) -> '/my_path/1'
});
Receiving the URL hash fragment would be easy using $locationChangeStart but this is not an option for me.
dasboe: I think I'm answering your question.
I have a app with an authentication/authorization check in the $routeChangeStart event handler. If not authenticated, I present user with modal login page. I want a successful login to send them to their original destination (Beauty of $routeChangeStart is that it will run again and check authorization after the successful login). I save the path built from the next in a user session service that is injected into the modal login controller.
here is the event handler
//before each route change, check if the user is logged in
//and authorized to move onto the next route
$rootScope.$on('$routeChangeStart', function (event, next, prev) {
if (next !== undefined) {
if ('data' in next) {
if ('authorizedRoles' in next.data) {
var authorizedRoles = next.data.authorizedRoles;
if (!SessionService.isAuthorized(authorizedRoles)) {
event.preventDefault();
SessionService.setRedirectOnLogin(BuildPathFromRoute(next));
if (SessionService.isLoggedIn()) {
// user is not allowed
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
} else {
// user is not logged in
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
}
}
}
}
}
});
Here is the function that builds the path from the next object
function BuildPathFromRoute(routeObj)
{
var path = routeObj.$$route.originalPath;
for (var property in routeObj.pathParams)
{
if (routeObj.pathParams.hasOwnProperty(property))
{
var regEx = new RegExp(":" + property, "gi");
path = path.replace(regEx, routeObj.pathParams[property].toString());
}
}
return path;
}
Notes:
I'm not keen on my $$route reliance, but I couldn't find any other way to do it. Maybe I missed something easier. I may be inviting trouble in the long term.
The preventDefault() will not work on AngularJS versions before 1.3.7 (see event.preventDefault() not working for routeChangeStart in angularjs app).
Standard caveat: This is all client side and subject to abuse. Make sure authentication/authorization happens server side.
The next Route object (from the event handler) also has a params property. I'm not sure if I should spin through its properties like I do with pathParams.
If you don't want to use hasOwnProperty, you could take advantage of the $$route.keys to get the names of the pathParams fields names:
function getPathFromRoute(routeObj)
{
var path = routeObj.$$route.originalPath;
var keys = routeObj.$$route.keys;
var value;
for (var i = 0; i < keys.length; i++) {
if(angular.isDefined(keys[i]) && angular.isDefined(keys[i].name)){
value = routeObj.pathParams[keys[i].name];
var regEx = new RegExp(":" + keys[i].name, "gi");
path = path.replace(regEx, value.toString());
}
}
return path;
};
Don't use object fields with $$ prefix like in previously given answers, because it's a prefix used by AngularJS for private properties. Use this method for get url from route (not tested):
var buildPathFromRoute = function (route) {
// get original route path
var path = route.originalPath;
// get params keys
var keysLength = route.keys.length;
for (var i=0; i<keysLength; i+=1) {
var param = route.keys[i];
// optional params postfix is '?'
var postfix = param.optional ? '\\?' : '';
var replaceString = ':' + param.name + postfix;
var regex = new RegExp(replaceString, 'g');
var paramValue = route.params[param.name].toString();
// replace param with value
path = path.replace(regex, paramValue);
}
path = path.replace(/\:\S+?\??/g, '');
return path;
};

Angular - update services object during asynchronous function

Folks: Creating an app in angular and node webkit - where users queue up files for downloading, navigate to their dashboard view and this initiates the downloads.
I've created a service which holds an object of the files data:
..
var downloadObj = {};
// fileObj = {'name':'The file name'; 'download_progress' : dlProgress}
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
}
console.log(downloadObj);
};
showcaseFactory.getDownloads = function() {
return downloadObj;
};
..
When the dashboard view loads - ng-repeat loops over $scope.downloadFiles which references this object returning the data.
<div ng-repeat="file in downloadFiles">
<div><span>{{file.name}}</span> [{{file.download_progress}}%]</div>
</div>
I've created a custom module which utilises node_modules to perform the download of the files:
nwjsDownloadFactory.commenceDownload = function(event_id, url, dest, cb) {
var http = require('http');
var fs = require('fs');
var statusBar = require('status-bar');
var path = require('path');
// THIS UPDATES THE OBJECT AND DISPLAYS FINE --------- >>
var id = 7;
var testFileObj = {
'name' : 'This is the file name prior to the download...',
'download_progress' : 10
};
ShowCase.myDownloads(id, testFileObj);
// <<< THIS UPDATES THE OBJECT AND DISPLAYS FINE ---------
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
bar = statusBar.create({ total: response.headers['content-length'] })
.on('render', function (stats) {
// var percentage = this.format.percentage(stats.percentage);
// console.log(event_id + '....' + percentage);
var id = 7;
var testFileObj = {
'name' : 'This is the new file name during the download...',
'download_progress' : 35 // this will be replaced with percentage
};
ShowCase.myDownloads(id, testFileObj);
});
response.pipe(bar);
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
}
QUESTION: Prior to the line var request = http.get(url, function(response) the object gets updated, and the changes are reflected in the UI. However, I need to constantly update the object with download complete % so I can create a progress bar.. However, as this asynchronous function executes, the object
appears to be updating - see the attached screen shot - but the UI is not reflecting this.
Can somebody please steer me in the right direction - I need the object to update during the function bar = statusBar.create({ and for the changes to reflect in the UI..
Call $scope.$apply() after making changes to your model to notify Angular that it has to update the UI.
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
$scope.$apply();
}
console.log(downloadObj);
};
If you use Angular's $http object, this is handled automatically for you, but if you update your model from other asynchronous callbacks, you have to take care of it yourself.
See this blog post and this documentation page for more in-depth explanations about what's going on.

Resources