Selecting Item in Array - google-app-maker

I'm trying to run a query by using a user input. The query is run in a database which has multiple columns (practically a vlookup). The query is run and the output is an array of values.
How do I get the value of only one value (scalar output to put in alert)?
Thanks
I've tried to use methods familiar to java in order to call one field in an array without any success.
i.e. output_array[0]
// define input
// var custno = app.pageFragments.Add_SalesOrder.children.Form1.children.Form1Body.children.CustomerNo_Input;
var custno = 'ENC';
// define location of output
var outputWidget = app.pageFragments.Add_SalesOrder.children.Form1.children.Form1Body.children.CustomerName_Input;
// define datasource
var datasource = app.datasources.SalesOrder;
// query
datasource.query.filters.CustomerNo._startsWith = custno.value;
// load query
datasource.load();
alert(datasource[0]);
I expect to get the first entry in the array but instead I get 'Undefined'.

If you look at the datasource documentation, you'll find out that the datasource is NOT an array, but instead an object. Since you are looking for the first result of the query, then you should access the items property of the datasource. That is an array and you can then just access the zero index of the array to get what you need.
alert(datasource.items[0]);

Related

Firestore rule to only add/remove one item of array

To optimize usage, I have a Firestore collection with only one document, consisting in a single field, which is an array of strings.
This is what the data looks like in the collection. Just one document with one field, which is an array:
On the client side, the app is simply retrieving the entire status document, picking one at random, and then sending the entire array back minus the one it picked
var all = await metaRef.doc("status").get();
List tokens=all['all'];
var r=new Random();
int numar=r.nextInt(tokens.length);
var ales=tokens[numar];
tokens.removeAt(numar);
metaRef.doc("status").set({"all":tokens});
Then it tries to do some stuff with the string, which may fail or succeed. If it succeeds, then no more writing to the database, but if it fails it fetches that array again, adds the string back and pushes it:
var all = await metaRef.doc("status").get();
List tokens=all['all'];
List<String> toate=(tokens.map((element) => element as String).toList());
toate.add(ales.toString());
metaRef.doc("status").set({"all":toate});
You can use the methods associated with the Set object.
Here is an example to check that only 1 item was removed:
allow update: if checkremoveonlyoneitem()
function checkremoveonlyoneitem() {
let set = resource.data.array.toSet();
let setafter = request.resource.data.array.toSet();
return set.size() == setafter.size() + 1
&& set.intersection(setafter).size() == 1;
}
Then you can check that only one item was added. And you should also add additional checks in case the array does not exist on your doc.
If you are not sure about how the app performs the task i.e., successfully or not, then I guess it is nice idea to implement this logic in the client code. You can just make a simple conditional block which deletes the field from the document if the operation succeeds, either due to offline condition or any other issue. You can find the following sample from the following document regarding how to do it. Like this, with just one write you can delete the field which the user picks without updating the whole document.
city_ref = db.collection(u'cities').document(u'BJ')
city_ref.update({
u'capital': firestore.DELETE_FIELD
})snippets.py

How to get the number of elements using Optional

Get the number of elements in List using size() method but how to get number of elements using Optional<entityname>.
In List:
List<User> data = this.Service.getUserById(id);
System.out.print(data.size());
In Optional:
Optional<User> data = this.Service.getUserById(id);
System.out.print(); // how to get in Optional
You need to think that your list (data) is inside Optional. So you need to convert (map) this list to size of this list, and return value (using e.g orElseGet) or return 0 is list is null.
You could try something like this:
Optional<User> data = this.Service.getUserById(id);
int size = data .map(List::size).orElseGet(() -> Integer.valueOf(0)).intValue();
// or int size = data .map(List::size).orElse(0);
An Optional<User> is not a list, what you are getting back is MAYBE a single user, or not, and it is your job to check if it returned a SINGLE user or not. The optional contains a User not a List<User>
If you want to get the user if it was returned, there are several ways.
This is one way, to get the user but is just an example code and should not be used in any production scenario as it is more verbose than it needs to be and is here to explain the general idea. but as mentioned there are several other ways in the link in the end of the post.
// This line returns maybe a single user, not a list of users.
Optional<User> data = this.Service.getUserById(id);
if(data.isPresent()) {
final User user = data.get();
}
You can read more about using optionals here:
Java Optionals

Best way for displaying total Pages for a datasource in Appmaker

I have a Google drive table data source which stores list of open positions. Now in the data source I've set "Query per size" field to 10 so that I can get 10 records per page. I've added a Pager as well to show pagination.
My query is I want to display like "Page 1 of X" to my end users and this X will vary based on certain search filters. What will the best way to achieve this in Appmaker?
I've tried counting total records in a data source as per below code but every time updating that with the search criteria and recounting it is not a proper solution.
//Server side
var newQuery = app.models.Company.newQuery();
var records = newQuery.run();
var totalCount =0;
for(var i=0;i<records.length;i++)
{
totalCount=totalCount+1;
}
return totalCount;
In case you don't have any filters in your table your server code can be as simple as
// Server script
function getPagesCount(pageSize) {
var recordsCount = app.models.MyModel.newQuery().run().length;
var pagesCount = Math.ceil(recordsCount / pageSize);
return pagesCount;
}
As an alternative you can consider creating Calculated Model with a single field PagesCount.
In case you have some filters associated with the table then you'll need to run the query for the pages number with exact same filters.
Most likely the entire setup will not work effectively with Drive Tables since there is no way to query records number without querying records themselves. With Cloud SQL data backend one can create Calculated SQL Model with lightweight native SQL query (here :PageSize is query parameter which should be equal to the query.limit of the actual datasource):
SELECT
Ceil(COUNT(1) / :PageSize) AS RecordsNumber
FROM
TableName
WHERE
...
I've achieved this using Calculated Model as suggested by Pavel.
Steps :
Create a calculated data source with one field count.
In that data source add one parameter searchQuery. This will contain users filter going forward. Currently I have only one search query in which user can search many things. So I've added one parameter only.
In this data source add following server script.
Code:
// Server script
function getTotalRecords(query) {
var receivedQuery = query.parameters.searchQuery;
// console.log('Received query:' + query.parameters.searchQuery);
var records = app.models.Company.newQuery();
records.parameters.SearchText = query.parameters.searchQuery;
if(receivedQuery !== null) {
records.where = '(Name contains? :SearchText or InternalId contains? ' +
':SearchText or LocationList contains? :SearchText )';
}
var recordsCount = records.run().length;
var calculatedModelRecords = [];
var draftRecord = app.models.RecordCount.newRecord();
draftRecord.count = ''+recordsCount;
calculatedModelRecords.push(draftRecord);
return calculatedModelRecords;
}
.
On the Appmaker page bind a label with this data source.
On search query/your filter applied event add following code which Reload this data source and assign value to Parameter.
// Client script
function updateRecordCount(newValue) {
var ds = app.datasources.RecordCount;
ds.query.parameters.searchQuery = newValue;
ds.unload();
ds.load();
}

How to bind Dropdown widget to query filter?

I have a Calculated Model, MonthlyTotalsByResource, displayed in a table that I am trying to query with a filter. First, I am retrieving the initial data from a regular Data Model called Allocations. I only wish to retrieve records from Allocations where the "Approved" field =true.
I also want to allow the user to filter MonthlyTotalsByResource by the "ManagerName" field. I have created a Dropdown widget with the Options as the full list of managers, and the Value is a query on the Calculated Model datasource:
#datasource.query.filters.ManagerName._equals
Here is the beginning of my code for getting the data for the Calculated Model MonthlyTotalsByResource from the regular data model Allocations, and where I filter for only "true" values in the Approved field. I am unclear what I should make the ManagerName filter set to in order for it to be binded to my Dropdown widget, or if I should add another query on the Calculated Model itself, instead of here on the regular Data Model.
function getMonthlyTotalsByResource_() {
var allRecordsQuery = app.models.Allocations.newQuery();
allRecordsQuery.filters.Approved._equals = true;
allRecordsQuery.filters.Resource.Manager.ManagerName._equals = ;
First things first, you need to introduce ManagerName parameter in your calculated datasource:
Once you add the parameter, you'll be able to set its value on client and read on server.
// dropdown widget's 'value' property binding
#datasources.MonthlyTotalsByResource.query.parameters.ManagerName
// server side code to get parameter value
var query = app.models.Allocations.newQuery();
...
query.filters.Resource.Manager.ManagerName._equals = query.parameters.ManagerName;
...

How to pass results from raw SQL query to view in Symfony2

I have this code that uses a raw SQL query inside my controller:
$sql1 = "SELECT completion_date FROM enviro_figures_upload GROUP BY YEAR(completion_date), MONTH(completion_date) DESC;";
$activeDate = $this->getDoctrine()->getManager()->getConnection()->prepare($sql1);
$activeDate->execute();
$activeDate->fetchAll();
This code then passes the data to the view which is then used in a drop down date picker. However, no results are passed to the view even though running that SQL query on the database returns the results I need. What am I missing in order to pass this data to the view?
$activeDate->execute();
$activeDate->fetchAll();
This code then passes the data to the view ...
this code doesn't pass the data to view, you have to pass the data to view by array option in render method..
something like this:
$sql1 = "SELECT completion_date FROM enviro_figures_upload GROUP BY YEAR(completion_date), MONTH(completion_date) DESC;";
$activeDate = $this->getDoctrine()->getManager()->getConnection()->prepare($sql1);
$activeDate->execute();
$result = $activeDate->fetchAll();
return $this->render('TEMPLATE_PATH', [
'result' => $result
]);

Resources