Boolean search using Google AppMaker - google-app-maker

I am creating an app using Google AppMaker and wish to create a boolean search option (text box where I can use AND/OR options to search multiple combinations of strings). This is similar to how I can search currently on Gmail or LinkedIn etc. How can I create it?

Here is one way to accomplish this:
Make a new datasource for the model you want to search in.
Select Query Script as the query type.
Add a string parameter called searchCriteria
Add a bunch of parameters called parameter0, parameter1, parameter2, etc.
Enter this code as the Server Script (assuming the field you want to search in is called Name):
var searchCriteria = query.parameters.searchCriteria;
if(searchCriteria === null) return query.run();
var searchArray = searchCriteria.split(/( and | or )/i);
var searchString = '';
for(var i = 0; i < searchArray.length; i++){
if(i % 2 === 0 ){
searchString += 'Name contains :parameter' + i.toString() + ' ';
query.parameters['parameter' + i.toString()] = searchArray[i];
}else{
searchString += searchArray[i];
}
}
query.where = searchString;
return query.run();
Then on your page bind the text box you want to search with to #datasource.query.parameters.searchCriteria
Finally modify the onValueEdit of the search box to Reload Datasource
This technique is limited by how many numbered parameters you create and doesn't allow using parenthesis.

Related

nextPage() method - not functioning

I have a datasource that contains > 1000 records. The current Query page size is at 100.
I have a need to loop through each item, and try to find a record that matches input given by the user. Fairly simple use-case, however, I can't seem to get the script to loop through the pages so it just finishes its loop at the query page size of 100 and therefore only searching the first 100 records.
I've tried putting in
app.datasources.Vehicles.nextPage();
at the end of the for loop and then call regoExists again with the new page but it doesn't work. How is nextPage() meant to be used in client scripts?
function regoExists(rego){
var regoUp = rego.toUpperCase();
regoUp = regoUp.trim();
ds = app.datasources.Vehicles.items;
for (var i in ds){
if (ds[i].registration === regoUp){
console.log(ds[i].registration + " equals " + regoUp);
app.datasources.Vehicles.query.filters.registration._equals = regoUp;
return true;
} else {
console.log(ds[i].registration + " does not equals " + regoUp);
continue;
}
}
}
Rather than looping through each record and performing the query on each individual record I would suggest introducing a textbox widget in the same datasource and setting the binding to:
#datasource.query.filters.registration._equals
Then load the datasource via a button click or via the onValueEdit event of the textbox widget. If the registration value exists, it will be returned in a table presumably, and if it doesn't exist no records would be returned.

How to get the Guids and mobilephone from a Party List?

I'm making a windows service that triggers on the create message of a custom activity SMS. These program will send the actual sms using a third party sms service provider.
Therefore I need to get the mobilephone numbers for every contact/lead/user/account in the "To" field of the SMS activity. This is a field of type: Party List.
In addition I have another field ("new_msisdn") which I use it if "to" field be empty.(In this field user will type phone numbers directly)
I'm currently using the following code:
EntityCollection results = CrmService.RetrieveMultiple(query);
string msisdn;
string newmessage;
Entity entity;
int encode;
bool flash;
res = new Message[results.Entities.Count];
if (results != null && results.Entities.Count > 0)
{
try
{
for (int i = 0; i < results.Entities.Count; i++)
{
entity = results.Entities[i];
msisdn = (string)entity["new_msisdn"];
// I have to add an condition here to check if "to" is not empty , then get mobilephones.
newmessage = (string)entity["new_message"];
encode = ((OptionSetValue)entity["new_messagetype"]).Value;
flash = (bool)entity["new_flashsms"];
res[i] = new Message();
res[i].crmId = entity.Id;
res[i].senderNumber = msisdn;
res[i].sendDate = DateTime.Now;
res[i].message = newmessage;
if (encode == 1)
res[i].encoding = 1;
else
res[i].encoding = 2;
if (flash)
res[i].flash = 2;
else res[i].flash = 1;
}
}
I have no ideas to do this. By the way, I use CRM 2015.
Try to use something like below.
if(entity.Attributes.Contains("to"))
{
EntityCollection to=(EntityCollection)entitiy["to"];
foreach(Entity toEntity in to.Entities)
{
//You will get each to field record here.
//Use that information to get the mobile numbers of respective users.
Guid Id=toEntity.Id;
//Below code mostly will return string.empty.
//You may have to query CRM to get mobile number for respective contacts.
string mobileNumber=toEntity.Attributes.Contains("mobilenumber")?toEntity["mobilenumber"].ToString():string.Empty;
}
}
Hope I have addressed your query. Please let us know if you have any further questions on the same.
Also its a best practice to check whether attribute is already available in the entity object or not before using a particular attribute.

Change a space to a + in order to complete an api in flex

I'm trying to make a search form to use on an api. However when the user types in the search field more then one name I want it to break the string into pieces and make a new string with a + between every keyword. I have no idea how to do this however.
Try this
var searchString:String = "nameOne nameTwo nameThree";
var whiteSpacePattern:RegExp = /\s+/g;
var replacedString:String = searchString.replace(whiteSpacePattern, "+");
trace(replacedString); // nameOne+nameTwo+nameThree
More information about String.replace : http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f00.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7ef1

How to revert the changes in text file, if "Save & Close" on a page is not clicked?

I am passing the page id component id and template id to a aspx page as querystring with this java script:
var masterTabControl = $controls.getControl($("#MasterTabControl"),
"Tridion.Controls.TabControl");
p.compPresTab = masterTabControl.getPage("ComponentPresentationsTab");
p.selectedComponentPresentation = p.compPresTab.getSelectedComponentPresentation();
p.selectedComp = p.selectedComponentPresentation.getComponentId();
window.open("http://" + location.hostname + ":path/test.aspx?pgId=" + pageId +
"&comId=" + p.selectedComponentPresentation.getComponentId() +
"&comTmpId=" +
p.selectedComponentPresentation.getComponentTemplateId(),
"myWindow", "status = 1,
toolbar=no,width=300,height=200,resizable=no,scrollbars=yes");
Now on the test.aspx page i am reading the id and with some additional information from the user i am saving it into a text file.
On a button click on popup test.aspx page i am saving it in text file:
sLogDetails = PageId + "| " + ComponentId + "|" + ComponentTemplateId +
"|" + text ;
//Move the contents to the temp file other than the existing one.
using (var sr = new StreamReader(permanentFile))
{
using (var sw = new StreamWriter(#"" + tempFile , true))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] parts = line.Split('|');
PageId = parts[0].Trim();
ComponentId = parts[1].Trim();
ComponentTemplateId = parts[2].Trim();
//Check there exist same record already
if (SPageId != PageId.Trim() || SComponentId != ComponentId.Trim()
|| SComponentTemplateId != ComponentTemplateId.Trim())
sw.WriteLine(line);
}
//Delete the Permanent file & create permanent file from temporary file
File.Delete(permanentFile);
File.Move(tempFile, permanentFile);
// Insert changes to the Permanent file
using (StreamWriter w = File.AppendText(permanentFile))
{
// Close the writer and underlying file.
w.WriteLine(sLogDetails);
w.Flush();
w.Close();
}
If the id is already present in the text file then i am populating it in the text field on popup test.aspx page like :
using (StreamReader r = File.OpenText(strPath + "Log.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
// Console.WriteLine(line);
string[] parts = line.Split('|');
PageId=parts[0].Trim();
ComponentId = parts[1].Trim();
ComponentTemplateId = parts[2].Trim();
//If there exist a record populate the data fields
if (SPageId == PageId.Trim() && SComponentId == ComponentId.Trim()
&& SComponentTemplateId == ComponentTemplateId.Trim())
{
txtRuleName.Text = (string)parts[3];
}
}
r.Close();
}
Now I am getting stuck here. When it's populating in the text field, user can edit the text area in popup test.aspx page and on click of ok it will get saved in text file. And if user is closing the page window without "save & Close", then the changes made by him in text field should not get saved in text file. It should revert back to old one.
Any idea how can i make it?
It is fairly difficult to respond to "something that didn't happen".
So is there any way you can create a list of other ways that the user can exit that Window? With that list you can register the relevant event handlers (or override the relevant commands) and implement your roll back there.
Alternatively you can consider making the change to the file in a temporary location from your popup. And then only commit it to your text file when the user clicks Save and Close.
Note that his file-based approach will start failing when you scale out your Tridion GUI and Content Manager to run on multiple machines. In general you should be wary of storing things in files on a server, when you are working on enterprise level software. What is a single server now (and will always be a single server in your development environment) will turn into multiple servers at some point in the future at which time your solution will cause problems.

Adobe Flex Salesforce problem converting account ids to account name

I am using Adobe Air to get data from SalesForce, and present it in a datagrid.
I am using a query to get the data, and then put it into an arraycollection that is bound to the datagrid, this works correctly and the data is displayed.
The problem is that I want to convert the Account Id in the Event to show the account Name. To do this I am using the following code:-
_serviceWrapper.query( "Select * From Event order by StartDateTime asc", new mx.rpc.Responder( eventQueryHandler, faultHandler ))}
protected function eventQueryHandler(qr:ArrayCollection):void {
var acctIdss:String = "";
for each(var contact:DynamicEntity in qr) {
if (contact.AccountId != null && acctIdss.indexOf(contact.AccountId) == -1) {
acctIdss += "'" + contact.AccountId + "',";
}
//contact.AccountName = ""; // Add field to contact for account name
TempGridProvider.addItem(contact); // Add contact to temp grid data data provider
//TempGridProvider.contact.AccountName = "";
}
acctIdss = acctIdss.substr(0, acctIdss.length - 1);
// Query for the accounts based on the account ids found in the contact list
_serviceWrapper.query("Select Id, Name, BillingCity From Account Where Id in (" + acctIdss + ")",
new SfdcAsyncResponder(Event2QueryHandler, faultHandler));
}
protected function Event2QueryHandler(accounts:ArrayCollection):void {
for each (var account:DynamicEntity in accounts) {
for each(var contact:DynamicEntity in TempGridProvider) {
if (contact.AccountId == account.Id) {
contact.AccountName = account.Name + " - " + account.BillingCity;
}
}
}
onQueryResult(TempGridProvider);
private function onQueryResult( rows : ArrayCollection ) : void {
// release previous query results
_serviceWrapper.releaseQueryResults( _gridDataProvider );
// populate datagrid
_gridDataProvider = rows;
// show message in status bar
var status : F3Message = new F3Message( F3Message.STATUS_INFO, "Query came back with " + ( _gridDataProvider == null ? 0 : _gridDataProvider.length ) + " " + _selectedEntity + "s" );
showStatus( status );
TempGridProvider = new ArrayCollection();;
}
This works and displays the Account Name, the problem is that when I use this script and then Sync Changes to SalesForce all the records that have been displayed are identified as needing to be syncronised even if they have only been displayed.
If I skip the function eventQueryHandler, and link my query to the OnQueryResult function then there is no problem, but only the Account Id can be displayed.
How can I stop Air marking these records as having changed, or is there a better way to achieve this??
Thanks in advance, any help is greatly appreciated.
Roy
I think you need to not manipulate the underlying object. There are two options for getting the data to render in a DataGrid.
Option 1 - Create another non-managed ValueObject that holds the values you need to display in the DataGrid. Copy the values when you receive them into the new ValueObject.
Option 2 - Use a labelFunction on the DataGridColumn to fetch the data externally when each cell in a given column is rendered.

Resources