Get data from code.hs with calling function(argument) - google-apps-script

I have index.html given below
<select id="id">
<option>1</option>
<option>2</option>
</select>
document.getElementById("id").onchange = function(){
let id = this.value
google.script.run.withSuccessHandler(setData).getData(id)
}
function setData(data) {
console.log(data)
}
And code.gs given below
function getData() {
var data = cleanRange(SpreadsheetApp.getActive().getSheetByName("Продажи").getRange("A2:K2").getValues(), id)
return data
}
function cleanRange(range, id){
var filtered = range.filter(function (el) {
return el[5] === id;
});
return filtered;
}
How can i call function getData from index.html with an argument.

I did it with the following code, because I realized that the above option would not work.
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select id="id>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
<script>
document.getElementById("id").onchange = function(){
let id = this.value;
google.script.run.withSuccessHandler(getData).setId(id)
}
function getData(){
google.script.run.withSuccessHandler(setData).getData()
}
function setData(data){
console.log(data);
}
</script>
</body>
</html>
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getData(){
var data = SpreadsheetApp.getActive().getSheetByName("Продажи").getRange("D2:K").getValues();
var id = PropertiesService.getScriptProperties().getProperty("orderNumber");
var result = cleanRange(data, id)
console.log(result)
return result;
}
function setId(id){
PropertiesService.getScriptProperties().setProperty("orderNumber", id);
}
function cleanRange(range, id){
var filtered = range.filter(function (el) {
return el[2] == id;
});
return filtered;
}

Related

send data in object from html by fetch to spreadsheet

I try to send data from html inputs to spreasheet like author in video
https://www.youtube.com/watch?v=yiPnkBEHqf0&list=PLRmEk9smitaVGAAhgU0Pdc2sEs7yxDrEk
In JS and HTML I wrote this:
const url = "https://script.google.com/macros/s/AKfycbzZe824lIxa-hNsO71xoFfq5qXbFaDKhHZeACrQgLMCjU_EjvY/exec";
var loginText = document.getElementById("tLogin");
var tableText = document.getElementById("tTable");
var orderText = document.getElementById("tOrder");
function testGS(){
var userInfo = {
login: loginText.value,
table: tableText.value,
order: orderText.value,
sdate: new Date().toLocaleDateString(),
};
fetch(url, {
method: 'POST',
headers: {"Content-Type": 'application/json'},
body: JSON.stringify(userInfo)
})
.then((res) => res.text())
.then((text) => console.log(text));
}
document.getElementById("del").addEventListener("click", testGS);
<!doctype html>
<html lang="en">
<head>
<title>CLR: PACKING</title>
<meta charset = "UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="CSS/main_page_style.css">
<link rel="icon" href="Image/favicon.png" type="png">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
</head>
<body>
<div class="conteiner">
<form novalidate>
<h6 class="title">PACKING</h6>
<img src="Image/mainImg.jpg" class="img-fluid" alt="...">
<div class="dws-input">
<div class="col-md-3"></div>
<div>
<div>
<button id="del" type="button"><======СБРОС</button>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tLogin" name= "username" placeholder= "Login:" autofocus >
<label for="tLogin">Логин:</label>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tTable" name= "text" placeholder= "Table:" >
<label for="tTable">Номер стола:</label>
</div>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" novalidate class="form-control" id="tOrder" name= "text" placeholder= "Order:" >
<label for="type3">Заказ:</label>
</div>
</div>
</form>
</div>
<script src="JS/fetchNew.js"></script>
</body>
</html>
In GAS I wrote this:
function doGet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("LOG_history");
const data = ws.getRange("A1").getDataRegion().getValues();
const headers = data.shift();
const jsonArray = data.map(r => {
let obj = {};
headers.forEach((h , i) => {
obj[h] = r[i];
});
return obj;
})
const response = [{status: 200, data: jsonArray}];
return sendJSON_(response);
}
function doPost(e){
let jsonResponse;
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("LOG_history");
const headers = ws.getRange(1,1,1,ws.getLastColumn()).getValues()[0];
const headersOriginalOrder = headers.slice();
headersOriginalOrder.shift();
//remove id columns header
headers.shift();
headers.sort();
const body = e.postData.contents;
const bodyJSON = JSON.parse(body);
const headersPassed = Object.keys(bodyJSON).sort();
if(!compareTwoArray_(headers, headersPassed)){
jsonResponse = [{status:500, message:"Invalid Arguments Passed"}];
return sendJSON_(jsonResponse);
}
const arrayOfData = headersOriginalOrder.map(h => bodyJSON[h]);
const aoaIds = ws.getRange(2,1,ws.getLastRow()-1,1).getValues();
const newIDNumber = getMaxFromArrayOfArray_(aoaIds) + 1;
arrayOfData.unshift(newIDNumber);
ws.appendRow(arrayOfData);
return ContentService.createTextOutput("ok");
}
//return true if all ites are the same
function compareTwoArray_(arr1, arr2){
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i ++){
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
function sendJSON_(jsonResponse){
return ContentService
.createTextOutput(JSON.stringify(jsonResponse))
.setMimeType(ContentService.MimeType.JSON);
}
//return the highest number / id
function getMaxFromArrayOfArray_(aoa){
let maxID = 0;
aoa.forEach(r => {
if (r[0] > maxID) maxID = r[0];
});
return maxID;
}
I need to send the data from inputs html page into object UserInfo in js-function and appendthem to spreadsheet but nothing happens.
If I put userInfo object in fetch like this "body: JSON.stringify(userInfo)" I get cor-mistake.
How can I organize that? thank you!
I have one notice: if I write in fetch "mode: 'no-cors'," then the data appends to spreadsheet, but return-info from doPost doesn't show. I need return info....((
Do you have to stringify your object to pass between server and client? I have this code in my html for getting data back from the server.
function succeed (res) {
alert('Begin succeed' );
console.log('Begin succeed' );
if (res == null) {
alert('Error: response was null!' );
console.log('Error: response was null!' );
return;
}
try {
alert(JSON.stringify(res) );
console.log(JSON.stringify(res) );
alert(res);
console.log(res);
} catch (err) {
alert('catch error trying to display res' );
console.log('catch error trying to display res' );
}
try {
document.getElementById('listDisplay').innerHTML = JSON.stringify(res);
} catch (err) {
alert('catch error trying to put res into textarea' );
console.log('catch error trying to put res into textarea' );
}
}
function fail (err) {
alert('Begin fail' );
console.log('Begin fail' );
alert('Error occurred', err);
console.log('Error occurred', err);
document.getElementById('listDisplay').innerHTML = 'ERROR: ' + err;
}

How can get value of an item based on ID in cshtml?

Let says I have a select tag with a specific id and multiples option. Then below, I want to display partial view base on the selected . I think of using something as if else statement but I don't know how to gain the value of that select with c#.
My thought about this is like this
<select id="selectItem">
<option value="A">A</option>
<option value="B">A</option>
<option value="C">A</option>
</select>
#if ('selectItem' == "A"){
<partial name="..."/>
}
you can do it with js,here is a demo:
Controller(Test):
public IActionResult Index()
{
return View();
}
public IActionResult Partial()
{
return PartialView("Partial1");
}
Partial1:
<h1>Partial1</h1>
Index.cshtml:
<select id="selectItem">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
<div id="PartialContent"></div>
js:
<script>
$(function () {
getPartial();
});
$("#selectItem").change(function () {
getPartial();
});
function getPartial() {
if ($("#selectItem").val() == "C") {
$.ajax({
type: 'GET',
url: "/Test/Partial",
dataType: 'html', //dataType - html
success: function (result) {
//Create a Div around the Partial View and fill the result
$('#PartialContent').html(result);
}
});
}else {
$('#PartialContent').html("");
}
}
</script>
result:

AngularJS function doesn't run

I have the following angular factory and controller.
var app = angular.module("carForm", []);
app.factory("dataService", ['$http', function getData($http) {
function getCars(){
return $http({
method: 'GET',
url: '/data.json'
}).then(function (response){
console.log(response.data);
return response.data
},function (error){
console.log("product error");
})
};
return { getCars : getCars }
}]);
app.controller("dataSort", ['dataService', '$scope', function(dataService, $scope) {
dataService.getCars().then(function(response){
cars = response;
$scope.make = [];
for (key in cars){
item = cars[key];
console.log(item);
$scope.make.push(item);
}
$scope.model = [];
for (key in cars[$scope.selectMake]){
item = cars[item][key_2]
$scope.model.push(item)
}
})
search = function(cars){
cars[$scope.selectMake][$scope.selectModel][$scope.selectType]
}
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div class="col-12" ng-contoller="dataSort">
<div class="row" style="text-align: center;">
<div class="form-group col-6">
<label for="inputState">Make</label>
<select id="inputState" class="form-control">
<option ng-model="selectMake" selected>Select make</option>
<option ng-repeat="item in make">{{ item }}</option>
</select>
</div>
<div class="form-group col-6">
<label for="inputState">Model</label>
<select id="inputState" class="form-control">
<option ng-model="selectModel" selected>Select model</option>
<option ng-repeat="item in model">{{ model }}</option>
</select>
</div>
<div class="form-group col-3">
<label for="inputState">Type</label>
<select id="inputState" class="form-control">
<option ng-model="selectType"selected>Select make type</option>
<option ng-repeat="item in type">{{ model }}</option>
</select>
</div>
</div>
</div>
I don't believe either factory or controller are running. Nothing is logged in console, neither the data or the error message. Angular is properly linked to my form as there is no {{ }} also the ng app is declared at the top of the html in the body tag using ng-app="carForm". The JS page is correctly linked to the html as when I console.log outside the angular function it prints. Angular is loaded before my JS script in the head tag, I cant figure out what I'm doing wrong.
Your factory is uncorrected, because you didn't pass your function in return
Right way to make a factory
app.factory("dataService", ['$http', function($http) {
var x = {};
return x;
}]);
But even you change the code it's not work on your controller because
you want to return response.data in $http as promise and this not happens, in
the case you need $q as injection in your service.
var app = angular.module("carForm", []);
app.factory("dataService", ['$http', '$q', function ($http, $q) {
var factory = {}
factory.sample = function() {
console.log("in factory!");
return [1,2,3]
}
factory.getCars = function() {
var deferred = $q.defer();
$http.get("api").then(function(response){
deferred.resolve(response.data);
})
return deferred.promise;
}
return factory;
}]);
app.controller("dataSort", ['dataService', '$scope', function(dataService, $scope) {
$scope.items = dataService.sample();
//uncomment when your api was ready
//dataService.getCars().then(function(response){
// console.log(response);
//})
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="carForm" ng-controller="dataSort">
<ul>
<li ng-repeat="item in items">{{item}}</li>
<ul>
</div>
Your factory is not correctly implemented Please change it like this.
app.factory("dataService", ['$http', function($http) {
function getCars(){
return $http({
method: 'GET',
url: '/data.json'
}).then(function (response){
console.log(response.data);
return response.data
},function (error){
console.log("product error");
})
};
return { getCars : getCars }
}]);

How do I communicate between sibling controllers?

Here's my code:
<div ng-controller="mainCtrl">
<button ng-click="onclick()"></button>
<button ng-click="onclick()"></button>
<button ng-click="onclick()"></button>
{{display}}
</div>
<div ng-controller="SecondController">{{display}}</div>
<div ng-controller="lastController">{{display}}</div>
I have to get some message in each div when the user clicks on the button.
I've tried the below code:
app.controller('mainCtrl',function($scope,$rootScope){
$scope.OnClick = function (msg) {
$rootScope.$broadcast("firstEvent",{});
}
$scope.$on("firstEvent", function (msg ) {
$scope.display = "hello world";
});
});
app.controller('SecondController',function( $scope){
$scope.$on("firstEvent", function (msg) {
$scope.display = "hello how Are you";
});
});
app.controller('lastController',function($scope) {
$scope.$on("firstEvent", function (msg) {
$scope.display = "this is my Query";
});
});
When the user clicks on each button, it should get data in each div.
How come its only possible with $on, $event and $broadcast?
$broadcast() sends an even downwards from parent to child controllers. The $emit() method, on the other hand, does exactly opposite. It sends an event upwards from the current controller to all of its parent controllers.
This is a simple example of communicating between controllers
angular.module("app", [])
.controller("mainCtrl", [
"$scope", "$rootScope",
function($scope, $rootScope) {
$scope.go = function(msg) {
if (msg == 1) {
$scope.display = "hello firstEvent";
} else if (msg == 2) {
$rootScope.$broadcast("showSomething", {});
} else {
$rootScope.$broadcast("showGoodBye", {});
}
};
}
]).controller("SecondController", [
"$scope", "$rootScope",
function($scope, $rootScope) {
$scope.$on("showSomething", function(msg) {
$scope.display = "hello Something";
});
}
]).controller("ThirdController", [
"$scope", "$rootScope",
function($scope, $rootScope) {
$scope.$on("showGoodBye", function(msg) {
$scope.display = "hello GoodBye";
});
}
]);
<div ng-app="app">
<div ng-controller="mainCtrl">
mainCtrl : {{display}}
<br>
<button ng-click="go(1)"> Show Hello </button>
<button ng-click="go(2)"> Show Something </button>
<button ng-click="go(3)"> Show GoodBye </button>
</div>
<hr>
<div ng-controller="SecondController">
SecondController : {{display}}
<hr>
</div>
<div ng-controller="ThirdController">
SecondController : {{display}}
<hr>
</div>
</div>
A complete Tour
Here is the solution:
I prefer not to use rootScope, you can use intermaeidate service to share data between two controllers
Solution with services:
Here is how service looks:
app.service('StoreService',function(){
var data;
this.save=function(data){
this.data=data;
};
this.getData=function(){
return this.data;
};
});
Using a service without rootScope
Demo without rootScope
Solution with rootScope
var app = angular.module('myApp', []);
app.controller('mainCtrl',function($scope,$rootScope){
$scope.buttonclick = function (msg) {
var object = {
data: msg
}
$rootScope.$broadcast("firstEvent",object);
}
$rootScope.$on("firstEvent", function (event, msg) {
$scope.display = msg.data;
});
})
app.controller('SecondController',function( $scope, $rootScope){
$rootScope.$on("firstEvent", function (event, msg) {
$scope.display = msg.data;
});
})
app.controller('lastController',function( $scope, $rootScope){
$rootScope.$on("firstEvent", function (event, msg) {
$scope.display = msg.data;
});
})
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp">
<div ng-controller="mainCtrl">
<button ng-click="buttonclick('button1')">button1</button>
<button ng-click="buttonclick('button2')">button2</button>
<button ng-click="buttonclick('button3')">button3</button>
<br>
{{display}}
</div>
<div ng-controller="SecondController">{{display}}</div>
<div ng-controller="lastController">{{display}}</div>
</div>
</body>
</html>
Please run the above snippet
Here is a Working DEMO

AngularJS $resource JSON field name conversion

I'm working on an AngularJS project that uses an API to deal with data. Now I'm implementing the 'create' functionality using $resource. Everything was going well except the naming conversion: I use camelCase but the API accepts snake_case only.
Is there a way to automatically convert these keys to snake_case?
Service:
services.factory('Salons', ['$resource',
function ($resource) {
return $resource('/salons/:slug', {
slug: "#slug"
});
}
]);
Controller:
controllers.controller('CreateSalonController', ['$scope', 'Salons',
function ($scope, Salons) {
$scope.submit = function() {
Salons.save(this.salon);
};
}
]);
View:
<form name="salonForm" role="form" ng-submit="submit()">
<div class="form-group">
<label for="salonContactFirstName">First name</label>
<input name="contactFirstName" type="text" class="form-control" id="salonContactFirstName" data-ng-model="salon.contactFirstName" />
</div>
...
I have not found any built-in solution so I implemented one:
A new service:
services.factory('Util', function () {
var Util = {
stringToSnakeCase: function (input) {
return input.replace(/([0-9A-Z])/g, function ($1) {
return "_" + $1.toLowerCase();
});
},
objectKeysToSnakeCase: function (input) {
var output = {};
_.each(input, function (val, key) {
output[Util.stringToSnakeCase(key)]
= _.isObject(val) ? Util.objectToSnakeCase(val) : val;
});
return output;
}
};
return Util;
}
);
And the updated controller:
controllers.controller('CreateSalonController', ['$scope', 'Salons', 'Util',
function ($scope, Salons, Util) {
$scope.submit = function() {
Salons.save(Util.objectKeysToSnakeCase(this.salon));
};
}
]);