Titanium Alloy Backbone and ACS - javascript

I'm trying to pass data from Appcelerator Cloud Services to Backbone models. I couldn't find documentation on how to do this...
Below is the config from my model file:
exports.definition = {
config: {
"columns": {
"id":"integer",
"address":"text",
"user_completed":"integer"
},
"adapter": {
"type": "", //what can I enter?
"collection_name": "places"
}
},
extendModel : function(Model) {
_.extend(Model.prototype, {
validate : function(attrs) {
for (var key in attrs) {
var value = attrs[key];
if (value) {
if (key === "item") {
if (value.length <= 0) {
return 'Error: No item!';
}
}
if (key === "done") {
if (value.length <= 0) {
return 'Error: No completed flag!';
}
}
}
}
}
});
return Model;
},
extendCollection : function(Collection) {
_.extend(Collection.prototype, {
comparator: function(places) {
return places.get('done');
}
});
return Collection;
}
};
How can I pass data from ACS?

You need to use "acs" in your config.
Check this :
exports.definition = {
config: {
"columns": {
"id":"integer",
"address":"text",
"user_completed":"integer"
},
"adapter": {
"type": "acs", // Use "acs"
"collection_name": "places"
}
},
extendModel : function(Model) {
_.extend(Model.prototype, {
validate : function(attrs) {
for (var key in attrs) {
var value = attrs[key];
if (value) {
if (key === "item") {
if (value.length <= 0) {
return 'Error: No item!';
}
}
if (key === "done") {
if (value.length <= 0) {
return 'Error: No completed flag!';
}
}
}
}
}
});
return Model;
},
extendCollection : function(Collection) {
_.extend(Collection.prototype, {
comparator: function(places) {
return places.get('done');
}
});
return Collection;
}
};
Check this presentation : Titanium presentation under ACS topic with "ACS in Alloy" header.
Also , here is sample example : Alloy backbone & ACS
Hope this helps.

Related

How to simplify JavaScript code modifying an JSON object

So the goal is to have included only those endpoints (and its methods e.g. get, post...) which are defined in the configuration file.
Example structure object that holds all the endpoints.
et swaggerApis = {
header: {
propertyHeader: "valueHeader"
},
blocks: [
{
tags: ["Tenant & User"],
paths: {
"/tenants": {
post: {
property: "value"
},
get: {
property: "value"
}
},
"/tenants/{id}": {
post: {
property: "value"
},
get: {
property: "value"
},
delete: {
property: "value"
}
}
}
}
]
};
Example of the configuration file that holds only those endpoints and its methods we want to have included in the final object.
const CONFIG = {
api: {
include: {
"/tenants/{id}": ["get"]
}
}
};
So far here is my second version of the JavaScript code that works but introduces a high cyclometric complexity and is hard to read. I'm pretty new to JavaScript and looking a way not just to improve this code.
function includeEnpointsByConfig(data) {
for (let blockItem of data.blocks) {
for (let path in blockItem.paths) { //console.log(blockItem.paths[path])
let result = setMethodsOfEndpoint(path, blockItem.paths[path]);
if (result === 'undefined') {
delete blockItem.paths[path] // if the config does not contain, remove
} else {
blockItem.paths[path] = result;
}
}
}
return data;
}
function setMethodsOfEndpoint(path, value) {
let newMethods = {};
for (let confPath in CONFIG.api.include) {
if (path === confPath) { // match endpoint in config and swaggerApis object
if (CONFIG.api.include[confPath].length > 0) { // if array in config is not empty , filter
for (let c of CONFIG.api.include[confPath]) { //console.log(c); // get
for (let v in value) {// properties of object tenants/{id} => {get{}, post{}}
if (v === c) {
newMethods = { ...newMethods, [v]: value[v] };
}
}
}
} else {// if array in config is empty , return param "value" from setMethodsOfEndpoint so we will include all methods of endpoint
return value;
}
} else {
return 'undefined'
}
}
if (Object.keys(newMethods).length !==0) { // if in the config is in the array (nothing that match with swaggerEndpoints e.g. typo get --> gte)
return newMethods
} else {
return value;
}
}
console.log(includeEnpointsByConfig(swaggerApis));
Code can be found also here
https://codesandbox.io/s/blazing-worker-1emzl?file=/src/index2.js
I believe there is a way to do it much easier, cleaner and more effective.
Thank you
With some creative usage of Array.prototype.forEach(), Object.keys() and Object.entries():
swaggerApis.blocks.forEach(block => {
Object.entries(block.paths).forEach(([path, methods]) => {
if (!CONFIG.api.include[path]) {
delete block.paths[path];
} else {
Object.keys(methods).forEach(method => {
if (!CONFIG.api.include[path].includes(method)) {
delete methods[method];
}
});
}
});
});
Complete snippet:
const swaggerApis = {
header: {
propertyHeader: "valueHeader"
},
blocks: [
{
tags: ["Tenant & User"],
paths: {
"/tenants": {
post: {
property: "value"
},
get: {
property: "value"
}
},
"/tenants/{id}": {
post: {
property: "value"
},
get: {
property: "value"
},
delete: {
property: "value"
}
}
}
}
]
};
const CONFIG = {
api: {
include: {
"/tenants/{id}": ["get"]
}
}
};
swaggerApis.blocks.forEach(block => {
Object.entries(block.paths).forEach(([path, methods]) => {
if (!CONFIG.api.include[path]) {
delete block.paths[path];
} else {
Object.keys(methods).forEach(method => {
if (!CONFIG.api.include[path].includes(method)) {
delete methods[method];
}
});
}
});
});
console.log(swaggerApis);

3angular.js:13920 TypeError: Cannot set property 'contract' of undefined

function loadAll() {
Organization.query({`enter code here`
page: pagingParams.page - 1,
size: vm.itemsPerPage,
sort: sort(),
mapperType: 'NORMAL',
status: 'DISABLED',
search: vm.search
}, onSuccess, onError);
function sort() {
var result = [vm.predicate + ',' + (vm.reverse ? 'asc' : 'desc')];
if (vm.predicate !== 'id') {
result.push('id');
}
return result;
}
function onSuccess(data, headers) {
vm.links = ParseLinks.parse(headers('link'));
vm.totalItems = headers('X-Total-Count');
vm.queryCount = vm.totalItems;
vm.page = pagingParams.page;
vm.searchParams = PrmJson.fromJson(pagingParams.search);
// vm.organizations = data;
vm.organizations = getContractStatus(data);
}
function onError(error) {
AlertService.error(error.data.message);
}
}
function getContractStatus(organizations) {
for (var i = 0; i < organizations.length; i++) {
Contract.getByOrganizationId({
organizationId: organizations[i].id
}, function (data) {
if (data.length == 0) {
organizations[i]["contract"] = {id: 0};
} else {
organizations[i]["contract"] = {id: data.id};
}
}
);
}
return organizations;
}
When I run the code above I get the following error message:
angular.js:13920 TypeError: Cannot set property 'contract' of undefined
You are passing anonymous function, so there data and i value both are undefined .
function(data,i) {
if (data.length == 0) {
organizations[i]["contract"] = {
id: 0
};
} else {
organizations[i]["contract"] = {
id: data.id
};
}
}(data,i);
Demo
for (var i = 0; i <= 5; i++) {
demo1(i, function(k,l) {
console.log('annonymous',l)
}(i,i));
}
function demo1(val) {
console.log('demo1',val)
}

Transfer data from factory to controller

Somehow I am not able to get my data from the factory method to the controller. I am using javascript remoting and factory is given below
function userRecordFetchFactory($rootScope) {
var custRec = {};
return {
checkRecordType : function(urlObject) {
function loadRecordType(err, records, event) {
if (err) {
displayReadingInformationErrorView();
} else if (records != null && records.length == 0) {
displayReadingInformationErrorView();
} else {
custRec = {
Name : records[0].get('Name'),
lat : records[0].get('Latitude__c'),
lon : records[0].get('Longitude__c'),
SiteStreet : records[0]
.get('SiteStreet__c'),
SiteCity : records[0].get('SiteCity__c'),
SiteCountryCode : records[0]
.get('SiteCountryCode__c'),
SitePostalCode : records[0]
.get('SitePostalCode__c'),
AddressID : records[0].get('AddressID__c'),
loaded : true
};
}
}
if (urlObject && urlObject.aid
&& urlObject.aid.startsWith(accPrefix)) {
objModel = new RemoteObjectModel.Account();
}
if (urlObject && urlObject.aid
&& urlObject.aid.startsWith(leadPrefix)) {
objModel = new RemoteObjectModel.Lead();
}
if (objModel) {
objModel.retrieve({
where : {
Id : {
eq : urlObject.aid
}
}
}, loadRecordType);
}
return custRec;
}
};
}
and my controller is given below to access the data
function LocatorInitController($document, $scope,
userRecordFetchFactory) {
console.log("inside the controller"+urlParams);
$scope.CustomerSite = {};
userRecordFetchFactory.checkRecordType(urlParams)
.then(function successData(data){
$scope.CustomerSite = data.data;
execGeoCoding();
});
I get an error cannot read property success of undefined. In the factory the method checkRecordType has a retrieve function which is a javascript remoting call and that finction has a callback to loadrecordtype.
Suggest you write your factory in a simpler way to read it. All your nesting is causing you not to see the whole thing easily
Put all the accessible members up top
// pass functions as references to object properties
// can easily see the whole factory object at top of the file
var custRec = {
checkRecordType : checkRecordType,
subscribe : subscribe
};
return custRec;
// move function declarations to the bottom and out of the way
function checkRecordType(){
/// do stuff
return stuff;
}
function loadRecordType(err, records, event) {
/// do stuff
return stuff;
}
function subscribe(scope, callback){
/// do stuff
return stuff;
}
See John Papa Angular STyle Guide
Why don't you try rewriting your factory like so:
function Factory() {
var custRec = {
subscribe: function(scope, callback) {
var handler = $rootScope.$on(
'fire-event-accountservice-retrieve',
function(
event, data) {
callback(data);
scope.$apply();
});
scope.$on('$destroy', handler);
},
checkRecordType: function(urlObject) {
var custRec;
if (urlObject.aid == null && urlObject.addr == null) {
displayCurrentLocation();
}
if (urlObject && urlObject.aid &&
urlObject.aid.startsWith(accPrefix)) {
objModel = new RemoteObjectModel.Account();
}
if (urlObject && urlObject.aid &&
urlObject.aid.startsWith(leadPrefix)) {
objModel = new RemoteObjectModel.Lead();
}
if (objModel == null && urlObject.aid != null && urlObject.addr == null) {
displayReadingInformationErrorView();
}
if (objModel) {
objModel.retrieve({
where: {
Id: {
eq: urlObject.aid
}
}
}, loadRecordType);
} else if ((urlObject.addr != null || urlObject.addr != '') && (typeof urlObject.addr != "undefined")) {
displayLocationBasedOnAddress(urlObject.addr);
}
function loadRecordType(err, records, event) {
if (err) {
displayReadingInformationErrorView();
} else if (records != null && records.length == 0) {
displayReadingInformationErrorView();
} else {
custRec = {
Name: records[0].get('Name'),
lat: records[0].get('Latitude__c'),
lon: records[0].get('Longitude__c'),
SiteStreet: records[0]
.get('SiteStreet__c'),
SiteCity: records[0].get('SiteCity__c'),
SiteCountryCode: records[0]
.get('SiteCountryCode__c'),
SitePostalCode: records[0]
.get('SitePostalCode__c'),
AddressID: records[0].get('AddressID__c'),
loaded: true
};
/* $rootScope.$emit(
'fire-event-accountservice-retrieve',
custRec); */
}
}
}
}
return custRec;
}
Looks like you're returning your factory object the wrong way.
function userRecordFetchFactory($rootScope) {
var custRec = {};
custRec.checkRecordType = function (urlObject) {
function loadRecordType(err, records, event) {
if (err) {
displayReadingInformationErrorView();
} else if (records != null && records.length == 0) {
displayReadingInformationErrorView();
} else {
custRec = {
Name: records[0].get('Name'),
lat: records[0].get('Latitude__c'),
lon: records[0].get('Longitude__c'),
SiteStreet: records[0]
.get('SiteStreet__c'),
SiteCity: records[0].get('SiteCity__c'),
SiteCountryCode: records[0]
.get('SiteCountryCode__c'),
SitePostalCode: records[0]
.get('SitePostalCode__c'),
AddressID: records[0].get('AddressID__c'),
loaded: true
};
}
}
if (urlObject && urlObject.aid
&& urlObject.aid.startsWith(accPrefix)) {
objModel = new RemoteObjectModel.Account();
}
if (urlObject && urlObject.aid
&& urlObject.aid.startsWith(leadPrefix)) {
objModel = new RemoteObjectModel.Lead();
}
if (objModel) {
objModel.retrieve({
where: {
Id: {
eq: urlObject.aid
}
}
},
return custRec;
}

SAPUI5 only update specific binding

In SAPUI5 I have a Model ("sModel") filled with metadata.
In this model I have a property "/aSelectedNumbers".
I also have a panel, of which I want to change the visibility depending on the content of the "/aSelectedNumbers" property.
update
first controller:
var oModelMeta = cv.model.recycleModel("oModelZAPRegistratieMeta", that);
//the cv.model.recycleModel function sets the model to the component
//if that hasn't been done so already, and returns that model.
//All of my views are added to a sap.m.App, which is returned in the
//first view of this component.
var aSelectedRegistratieType = [];
var aSelectedDagdelen = ["O", "M"];
oModelMeta.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
oModelMeta.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
First Panel (Which has checkboxes controlling the array in question):
sap.ui.jsfragment("fragments.data.ZAPRegistratie.Filters.RegistratieTypeFilter", {
createContent: function(oInitData) {
var oController = oInitData.oController;
var fnCallback = oInitData.fnCallback;
var oModel = cv.model.recycleModel("oModelZAPRegistratieMeta", oController);
var oPanel = new sap.m.Panel( {
content: new sap.m.Label( {
text: "Registratietype",
width: "120px"
})
});
function addCheckBox(sName, sId) {
var oCheckBox = new sap.m.CheckBox( {
text: sName,
selected: {
path: "oModelZAPRegistratieMeta>/aSelectedRegistratieType",
formatter: function(oFC) {
if (!oFC) { return false; }
console.log(oFC);
return oFC.indexOf(sId) !== -1;
}
},
select: function(oEvent) {
var aSelectedRegistratieType = oModel.getProperty("/aSelectedRegistratieType");
var iIndex = aSelectedRegistratieType.indexOf(sId);
if (oEvent.getParameters().selected) {
if (iIndex === -1) {
aSelectedRegistratieType.push(sId);
oModel.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
}
} else {
if (iIndex !== -1) {
aSelectedRegistratieType.splice(iIndex, 1);
oModel.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
}
}
// arrays update niet live aan properties
oModel.updateBindings(true); //******** <<===== SEE HERE
if (fnCallback) {
fnCallback(oController);
}
},
width: "120px",
enabled: {
path: "oModelZAPRegistratieMeta>/bChanged",
formatter: function(oFC) {
return oFC !== true;
}
}
});
oPanel.addContent(oCheckBox);
}
addCheckBox("Presentielijst (dag)", "1");
addCheckBox("Presentielijst (dagdelen)", "2");
addCheckBox("Uren (dagdelen)", "3");
addCheckBox("Tijd (dagdelen)", "4");
return oPanel;
}
});
Here is the panel of which the visibility is referred to in the question. Note that it DOES work after oModel.updateBindings(true) (see comment in code above), but otherwise it does not update accordingly.
sap.ui.jsfragment("fragments.data.ZAPRegistratie.Filters.DagdeelFilter", {
createContent: function(oInitData) {
var oController = oInitData.oController;
var fnCallback = oInitData.fnCallback;
var oModel = cv.model.recycleModel("oModelZAPRegistratieMeta", oController);
var oPanel = new sap.m.Panel( {
content: new sap.m.Label( {
text: "Dagdeel",
width: "120px"
}),
visible: {
path: "oModelZAPRegistratieMeta>/aSelectedRegistratieType",
formatter: function(oFC) {
console.log("visibility");
console.log(oFC);
if (!oFC) { return true; }
if (oFC.length === 0) { return true; }
return oFC.indexOf("2") !== -1;
}
}
});
console.log(oPanel);
function addCheckBox(sName, sId) {
var oCheckBox = new sap.m.CheckBox( {
text: sName,
selected: {
path: "oModelZAPRegistratieMeta>/aSelectedDagdelen",
formatter: function(oFC) {
if (!oFC) { return false; }
console.log(oFC);
return oFC.indexOf(sId) !== -1;
}
},
select: function(oEvent) {
var aSelectedDagdelen = oModel.getProperty("/aSelectedDagdelen");
var iIndex = aSelectedDagdelen.indexOf(sId);
if (oEvent.getParameters().selected) {
if (iIndex === -1) {
aSelectedDagdelen.push(sId);
oModel.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
}
} else {
if (iIndex !== -1) {
aSelectedDagdelen.splice(iIndex, 1);
oModel.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
}
}
if (fnCallback) {
fnCallback(oController);
}
},
enabled: {
path: "oModelZAPRegistratieMeta>/bChanged",
formatter: function(oFC) {
return oFC !== true;
}
},
width: "120px"
});
oPanel.addContent(oCheckBox);
}
addCheckBox("Ochtend", "O", true);
addCheckBox("Middag", "M", true);
addCheckBox("Avond", "A");
addCheckBox("Nacht", "N");
return oPanel;
}
});
The reason that the model doesn´t trigger a change event is that the reference to the Array does not change.
A possible way to change the value is to create a new Array everytime you read it from the model:
var newArray = oModel.getProperty("/aSelectedNumbers").slice();
// do your changes to the array
// ...
oModel.setProperty("/aSelectedNumbers", newArray);
This JSBin illustrates the issue.

How to do a synchronous call with jaydata

I'm a bit confused about the asynchous call to the DataBase.
I just want to have a javasctipt adapter class for the calls to the web sql. But I'm not quite sure how to do this. Propably somebody have a good hint for me.
The function OfflneAppDBAdapter.prototype.IsDeviceConfigured() should return true or false depending if there are any items in the Table DeviceConfig.
function OfflneAppDBAdapter() {
self = this;
this.deviceIsConfigured = false;
this.Init = function () {
$data.Entity.extend("$de.offlineapp.DeviceConfig", {
Id: { type: "int", key: true, computed: true },
Name: { type: "string", required: true },
Token: { type: "string" },
Type: { type: "string" }
});
$data.EntityContext.extend("$de.offlineapp.DataContext", {
DeviceConfig: { type: $data.EntitySet, elementType: $de.offlineapp.DeviceConfig }
});
}
self.Init();
$de.offlineapp.context = new $de.offlineapp.DataContext({
name: "webSql", databaseName: "OfflineApp"
});
$de.offlineapp.context.onReady(function () {
});
}
// ************************************************************************
// PUBLIC METHODS -- ANYONE MAY READ/WRITE
// ************************************************************************
OfflneAppDBAdapter.prototype.AddDeviceConfig = function (deviceName, deviceToken, deviceTyp) {
$de.offlineapp.context.onReady(function () {
var promise = $de.offlineapp.context.DeviceConfig.toArray(function (x) {
if (x.length == 0) {
var emp = new $de.offlineapp.DeviceConfig({ Name: deviceName, Token: deviceToken, Type: deviceTyp });
$de.offlineapp.context.DeviceConfig.add(emp);
$de.offlineapp.context.saveChanges();
}
}
)
});
}
OfflneAppDBAdapter.prototype.IsDeviceConfigured = function () {
$de.offlineapp.context.onReady(function () {
var promise = $de.offlineapp.context.DeviceConfig.toArray(function (x) {
if (x.length == 0) {
this.deviceIsConfigured = true;
}
}
)
});
return this.deviceIsConfigured;
}
var myOfflineAppDBAdapter = new OfflneAppDBAdapter();
myOfflineAppDBAdapter.AddDeviceConfig("DeviceName", "Token", "iPad");
console.log(myOfflineAppDBAdapter.IsDeviceConfigured());
As expected the console prints "false". I' aware that the jaydata call works with callbacks and the callbacks are not part of the main class. But there must be a possibility to do so?
I would really apprechiate any help.
Thank you in advance....
Chris
UPDATE:
As you requested the startup code:
function OfflineApplication()
{
self = this;
}
OfflineApplication.prototype.StartApplication = function () {
//Check if online, then sync and
if (navigator && navigator.onLine === true) {
this.IsDeviceConfigured();
}
else {
}
}
///check if the device has a base configuration
OfflineApplication.prototype.IsDeviceConfigured = function () {
myOfflineAppDBAdapter.GetDeviceConfiguration(function (result) {
if (result.length > 0) {
myOfflineAppDBAdapter.deviceIsConfigured = true;
myOfflineApplication.HasDeviceAnApplication();
}
else {
///Get the device base conf from the server.
myOfflineAppSynchronisationAdapter.getDeviceConfigurationByToken(token, myOfflineApplication.HasDeviceAnApplication);
myOfflineAppDBAdapter.deviceIsConfigured = true;
}
});
}
///check if the device has an "application config" in general
OfflineApplication.prototype.HasDeviceAnApplication = function () {
myOfflineAppDBAdapter.GetDeviceAnApplication(function (result) {
if (result.length > 0) {
myOfflineApplication.IsDeviceApplicationVersionLatest(result);
}
else {
myOfflineApplication.GetApplication(false);
}
});
}
///the application config could differ from time to time, so we have to check if a different application should be synct with the device
OfflineApplication.prototype.IsDeviceApplicationVersionLatest = function (result) {
myOfflineAppDBAdapter.DeleteDeviceAnApplication(function () { });
console.log(result);
}
///get the application from the server
OfflineApplication.prototype.GetApplication = function (clearConfig) {
if (clearConfig === true)
{
}
myOfflineAppSynchronisationAdapter.getDeviceApplicationByToken(token, myOfflineApplication.LoadApplication);
}
OfflineApplication.prototype.LoadApplication = function () {
console.log('Now everything is finde and the application gets loaded..');
}
var myOfflineAppDBAdapter = new OfflneAppDBAdapter();
var myOfflineAppSynchronisationAdapter = new OfflineAppSynchronisationAdapter();
var myOfflineApplication = new OfflineApplication();
myOfflineApplication.StartApplication();
There is no sync way. You handling promises wrong. Make your code simple :) You'll need something like this:
$data.Entity.extend("$de.offlineapp.DeviceConfig", {
Id: { type: "int", key: true, computed: true },
Name: { type: "string", required: true },
Token: { type: "string" },
Type: { type: "string" }
});
$data.EntityContext.extend("$de.offlineapp.DataContext", {
DeviceConfig: { type: $data.EntitySet, elementType: $de.offlineapp.DeviceConfig }
});
var context = new $de.offlineapp.DataContext({
name: "webSql", databaseName: "OfflineApp"
});
function AddDeviceConfig(deviceName, deviceToken, deviceTyp) {
return context.DeviceConfig.toArray()
.then(function (x) {
if (x.length == 0) {
var emp = new $de.offlineapp.DeviceConfig({ Name: deviceName, Token: deviceToken, Type: deviceTyp });
context.DeviceConfig.add(emp);
return context.saveChanges();
}
})
}
function IsDeviceConfigured() {
return context.DeviceConfig.toArray()
.then(function (x) {
return x.length > 0;
})
}
context.onReady()
.then(IsDeviceConfigured)
.then(console.log)
.then(function() { return AddDeviceConfig("DeviceName", "Token", "iPad"); })
.then(IsDeviceConfigured)
.then(console.log);
here's a fiddle which does this: http://jsfiddle.net/JayData/cpT5q/1/

Categories