Удовольствие сомнительное, но в моем случае использование Google Apps Script было необходимым условием задачи, а AngularJS в силу ряда причин, не имеющих прямого отношения к настоящему посту, пришелся очень даже кстати.
В общем если вы приняли решение встать на скользкий путь создания мэшапов на GAS и ангуляр, думаю освоение следующего материала может сократить количество неприятных ощущений, которые вы без сомнения испытаете в процессе применения озвученных выше инструментов.
На этом прелюдия завершена, переходим к содержательной части.
Тестовое приложение выглядит следующим образом:
... и состоит из:
- Код.js - серверный javascript-код
- index.html - html-код
- js.html - клиентский javascript-код
- css.html - css-код
Код.js - html-шаблон отдаем обязательно в "нативном" режиме "песочницы", для инжекта кода, в нашем случае из файлов js.html и css.html, используем функцию require (назовите ее на ваш вкус):
function doGet(e) {
var t = HtmlService.createTemplateFromFile('index');
return t.evaluate().setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
function require(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
index.html - в самом начале инжектим код клиентских js и css:<?!= require('css'); ?>
<?!= require('js'); ?>
<div class="container" ng-app="">
<h1>Hello <span ng-bind="name"></span></h1>
<input type="text" ng-model="name" placeholder="Enter your name">
</div>
js.html - здесь обязательно ссылка на полный, не минифицированный, код ангуляра:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
css.html - забутстрапим для красоты:
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
Разворачиваем веб-приложение, тестим:
Ура, мы все-таки скрестили ангуляр и GAS! Дальше расскажу как получить данные сервера на клиенте.
Добавим в файл Код.gs функцию по имени getData:
function doGet(e) {
var t = HtmlService.createTemplateFromFile('index');
return t.evaluate().setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
function require(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getData() {
return [['a','b','c'],[1,'qwe','rty'],[2,'asd','fgh'],[3,'zxc','vbn']];
}
В контексте этого поста неважно как мы получили эти данные, главное что они есть.
Пытаемся отобразить данные, полученные с сервера в таблице - редактируем файл index.html:
<?!= require('css'); ?>
<?!= require('js'); ?>
<div class="container" ng-app="app" ng-controller="MainCtrl">
<h1>Hello <span ng-bind="name"></span></h1>
<input type="text" ng-model="name" placeholder="Enter your name">
<table class="table table-hover">
<thead>
<tr>
<th ng-repeat="key in heading">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="arr in list">
<td ng-repeat="i in arr">{{arr[$index]}}</td>
</tr>
</tbody>
</table>
</div>
Теперь самое интересное - редактируем файл js.html - получаем данные с сервера и втыкаем их в $scope.list приложения (заголовок таблицы нас пока не интересует):
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script>
angular.module('app', []).controller('MainCtrl', function($scope) {
google.script.run.withSuccessHandler(gotData).withFailureHandler(gotError).getData();
$scope.heading = [];
$scope.list = [];
function gotData(data) {
console.log('data: ' + JSON.stringify(data));
$scope.list = data;
}
function gotError(e) {
console.log('error: ' + e.message);
}
});
</script>
И ничего не случилось, хотя данные с сервера прилетели:
Пытаемся обновить данные - редактируем файл js.html - $scope.apply() :
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script>
angular.module('app', []).controller('MainCtrl', function($scope) {
google.script.run.withSuccessHandler(gotData).withFailureHandler(gotError).getData();
$scope.heading = [];
$scope.list = [];
function gotData(data) {
console.log('data: ' + JSON.stringify(data));
$scope.list = data;
$scope.$apply();
}
function gotError(e) {
console.log('error: ' + e.message);
}
});
</script>
И получаем ошибку на клиенте:
Пчелы начали что-то подозревать :). Должен признать что следующая итерация заняла у меня не менее получаса, редактируем файл js.html еще раз:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script>
angular.module('app', []).controller('MainCtrl', function($scope) {
google.script.run.withSuccessHandler(gotData).withFailureHandler(gotError).getData();
$scope.heading = [];
$scope.list = [];
function gotData(data) {
console.log('data: ' + JSON.stringify(data));
console.log('data isExtensible: ' + Object.isExtensible(data));
console.log('data isSealed: ' + Object.isSealed(data));
console.log('data isFrozen: ' + Object.isFrozen(data));
$scope.list = data;
$scope.$apply();
}
function gotError(e) {
console.log('error: ' + e.message);
}
});
</script>
Обращаю внимание на скриншот - не знаю где и с какой целью происходит "заморозка" данных, короче ничего не остается кроме как растасовать данные, полученные с сервера в аргументе data функции gotData путем перебора свойств аргумента, как-то так:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script>
angular.module('app', []).controller('MainCtrl', function($scope) {
google.script.run.withSuccessHandler(gotData).withFailureHandler(gotError).getData();
$scope.heading = [];
$scope.list = [];
function gotData(data) {
console.log('data: ' + JSON.stringify(data));
var heading = data[0], i = 0, hLen = heading.length, j, dLen = data.length, arr;
for (; i < hLen; i += 1) {
$scope.heading.push(heading[i]);
}
for (i = 1; i < dLen; i += 1) {
arr = [];
for (j = 0; j < hLen; j += 1) {
arr.push(data[i][j]);
}
$scope.list.push(arr);
}
$scope.$apply();
}
function gotError(e) {
console.log('error: ' + e.message);
}
});
</script>
Еще пара вариантов "разморозки" попроще:
data = JSON.parse(JSON.stringify(data));
data = angular.copy(data);
Только после подобных манипуляций мы можем рассчитывать на результат:
На этом тему мэшапа Google Apps Script и AngularJS считаю раскрытой. Кого заинтересовали подробности этого извращения - пишите в комменты, по возможности постараюсь ответить.
p.s.: Если приложение по ссылке не отрабатывает как ожидается - попробуйте обновить страницу в браузере - это







Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации