Probably I'm missing something basic here. Scenario goes like this:
Within the root view controller of my application (App.controller.js, onInit function) I'm performing a series of read operations on a named model in order to have additional data ready mainly for use by formatters in subsequent views. What I have done is using promises to make sure that data will be ready.
Problem is that application occasionally crashes when the initial view with pattern "" (Worklist.view.xml in my case) is loaded after the root view (App.view.xml) because the formatter function can't find the data expected. Added a few break-points and observed the debugger:
stopping at the first read function
stopping at the promises condition at the end
stopping (and throwing error) at the formatter function at the subsequent view
stopping in the success function of oData read (resolve)
page freezes afterwards as result of the exception thrown above
"Normal" flow, when application doesn't crash goes like this:
stopping at the first read function
stopping at the promises condition at the end
stopping in the success function of oData read (resolve)
stopping at the readyToGo function (it's there just for temporary debugging)
stopping at the formatter function at the subsequent view
page display, everything in order
Judging by the above, I have reached the conclusion that my promises do not work. Any ideas?
sap.ui.define([
"kristal/apps/agreements/controller/BaseController",
"sap/ui/model/json/JSONModel"
], function (BaseController, JSONModel) {
"use strict";
/* PROMISE VARIABLES */
var oModelTypeDataDeferred = jQuery.Deferred();
var oModelStatusDataDeferred = jQuery.Deferred();
var oModelRoleDataDeferred = jQuery.Deferred();
var oModelRefDataDeferred = jQuery.Deferred();
var oModelExtOrgDataDeferred = jQuery.Deferred();
var oModelInvolvementDataDeferred = jQuery.Deferred();
return BaseController.extend("kristal.apps.agreements.controller.App", {
onInit: function () {
/* CALLED AFTER PROMISES HAVE BEEN FULFILLED */
var readyToGo = function() {
jQuery.sap.log.error("Ready!");
};
var oViewModel;
var fnSetAppNotBusy;
var iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
var oViewModel = new JSONModel({
busy: true,
delay: 0
});
this.setModel(oViewModel, "appView");
fnSetAppNotBusy = function() {
oViewModel.setProperty("/busy", false);
oViewModel.setProperty("/delay", iOriginalBusyDelay);
};
this.getOwnerComponent().getModel().metadataLoaded().then(fnSetAppNotBusy);
var oModel = this.getOwnerComponent().getModel("f4");
/* oData READ OPS */
oModel.metadataLoaded().then(function(){
// Initialize additional data
var sPath = "/Agreement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelTypeDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Agreement_StatusesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelStatusDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Role_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRoleDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Reference_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/External_OrganizationsSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Involvement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelInvolvementDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
/* IF ALL PROMISES FULFILLED, PROCEED */
jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelRoleDataDeferred, oModelRefDataDeferred, oModelExtOrgDataDeferred, oModelInvolvementDataDeferred)
.done().then(jQuery.proxy(readyToGo, this));
},
// ...
});
});
manifest.json:
{
"_version": "1.4.0",
"sap.app": {
"id": "kristal.apps.agreements",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "/DEV/sap/opu/odata/SAP/ZCONTRACTS_SRV/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
},
"sourceTemplate": {
"id": "sap.ui.ui5-template-plugin.1worklist",
"version": "1.38.3"
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "sap-icon://task",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"rootView": {
"viewName": "kristal.apps.agreements.view.App",
"type": "XML",
"id": "app",
"async": true
},
"dependencies": {
"minUI5Version": "1.38.0",
"libs": {
"sap.ui.core": {
"minVersion": "1.38.0"
},
"sap.m": {
"minVersion": "1.38.0"
},
"sap.ushell": {
"minVersion": "1.38.0"
},
"sap.collaboration": {
"minVersion": "1.38",
"lazy": true
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "kristal.apps.agreements.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"defaultBindingMode": "TwoWay"
}
},
"f4": {
"dataSource": "mainService",
"preload": true,
"settings": {
"metadataUrlParams": {
"sap-documentation": "heading"
},
"defaultBindingMode": "TwoWay"
}
}
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "kristal.apps.agreements.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": [
"notFound"
]
},
"async": true
},
"routes": [{
"pattern": "",
"name": "worklist",
"target": [
"worklist"
]
}, {
"pattern": "AgreementsSet/{objectId}",
"name": "object",
"target": [
"object"
]
}],
"targets": {
"worklist": {
"viewName": "Worklist",
"viewId": "worklist",
"viewLevel": 1
},
"object": {
"viewName": "Object",
"viewId": "object",
"viewLevel": 2
},
"objectNotFound": {
"viewName": "ObjectNotFound",
"viewId": "objectNotFound"
},
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
}
}
}
},
"sap.platform.abap": {
"uri": "/sap/bc/ui5_ui5/sap/zctr_contr_mnt/webapp",
"_version": "1.1.0"
}
}
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"kristal/apps/agreements/model/models",
"kristal/apps/agreements/controller/ErrorHandler"
], function(UIComponent, Device, models, ErrorHandler) {
"use strict";
return UIComponent.extend("kristal.apps.agreements.Component", {
metadata: {
manifest: "json"
},
init: function() {
UIComponent.prototype.init.apply(this, arguments);
this._oErrorHandler = new ErrorHandler(this);
this.setModel(models.createDeviceModel(), "device");
this.setModel(models.createFLPModel(), "FLP");
this.getRouter().initialize();
},
destroy: function() {
this._oErrorHandler.destroy();
// call the base component's destroy function
UIComponent.prototype.destroy.apply(this, arguments);
},
getContentDensityClass: function() {
if (this._sContentDensityClass === undefined) {
// check whether FLP has already set the content density class; do nothing in this case
if (jQuery(document.body).hasClass("sapUiSizeCozy") || jQuery(document.body).hasClass("sapUiSizeCompact")) {
this._sContentDensityClass = "";
} else if (!Device.support.touch) { // apply "compact" mode if touch is not supported
this._sContentDensityClass = "sapUiSizeCompact";
} else {
// "cozy" in case of touch support; default for most sap.m controls, but needed for desktop-first controls like sap.ui.table.Table
this._sContentDensityClass = "sapUiSizeCozy";
}
}
return this._sContentDensityClass;
}
});
});
It was all about moving functionality from the root view to component.js and putting the router initialization into the promise conditions, thank you experts
Related
I have a problem, that sometimes the controller does not get loaded:
and you can see the error message. It should load the following controller(marked with red border):
Why it is not getting loaded sometimes?
When the controller gets loaded, it looks like:
UPDATE:
I am using flexible column layout.
The App.view.xml looks like:
<mvc:View controllerName="ch.mindustrie.ZMM_CLASSIFICATION.controller.App" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:f="sap.f">
<App id="root">
<f:FlexibleColumnLayout id="idClassLayout"/>
</App>
</mvc:View>
the manifest.json file:
{
"_version": "1.9.0",
"sap.app": {
"id": "ch.mindustrie.ZMM_CLASSIFICATION",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "0.1.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "servicecatalog.connectivityComponentForManifest",
"version": "0.0.0"
},
"dataSources": {
"ZMM_CLASSIFICATION_SRV": {
"uri": "/sap/opu/odata/sap/ZMM_CLASSIFICATION_SRV/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/ZMM_CLASSIFICATION_SRV/metadata.xml"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_belize"
]
},
"sap.ui5": {
"handleValidation": true,
"rootView": {
"viewName": "ch.mindustrie.ZMM_CLASSIFICATION.view.App",
"type": "XML",
"async": true,
"id": "app"
},
"dependencies": {
"minUI5Version": "1.50.0",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {},
"sap.f": {},
"sap.collaboration": {
"lazy": true
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "ch.mindustrie.ZMM_CLASSIFICATION.i18n.i18n"
}
},
"Classification": {
"uri": "/sap/opu/odata/sap/ZMM_CLASSIFICATION_SRV/",
"type": "sap.ui.model.odata.v2.ODataModel",
"settings": {
"defaultOperationMode": "Server",
"defaultBindingMode": "OneWay",
"defaultCountMode": "Request"
},
"dataSource": "ZMM_CLASSIFICATION_SRV",
"preload": true
}
},
"resources": {
"css": [
{
"uri": "css/style.css"
}
]
},
"routing": {
"config": {
"routerClass": "sap.f.routing.Router",
"viewType": "XML",
"viewPath": "ch.mindustrie.ZMM_CLASSIFICATION.view",
"controlId": "idClassLayout",
"bypassed": {
"target": [
"search",
"characteristic"
]
},
"async": true
},
"routes": [
{
"pattern": "",
"name": "search",
"target": [
"characteristic",
"search"
],
"layout": "TwoColumnsBeginExpanded"
},
{
"pattern": "search/{internalclassnum}",
"name": "characteristic",
"target": [
"search",
"characteristic"
],
"layout": "TwoColumnsMidExpanded"
}
],
"targets": {
"search": {
"viewName": "Search",
"viewLevel": 1,
"viewId": "search",
"controlAggregation": "beginColumnPages"
},
"characteristic": {
"viewName": "Characteristic",
"viewLevel": 2,
"viewId": "characteristic",
"controlAggregation": "endColumnPages"
}
}
}
},
"sap.platform.abap": {
"uri": "/sap/bc/ui5_ui5/sap/zmm_classifi/webapp",
"_version": "1.1.0"
}
}
the Search.view.xml:
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:l="sap.ui.layout" xmlns:uxap="sap.uxap"
xmlns:f="sap.ui.layout.form" xmlns:smartFilterBar="sap.ui.comp.smartfilterbar"
controllerName="ch.mindustrie.ZMM_CLASSIFICATION.controller.Search" xmlns:html="http://www.w3.org/1999/xhtml">
<smartFilterBar:SmartFilterBar id="SelectionFilterBar" entitySet="ZMM_C_CLASSIFICATION" search="onSearchClass">
<smartFilterBar:controlConfiguration>
<smartFilterBar:ControlConfiguration key="ClassType" visibleInAdvancedArea="true" preventInitialDataFetchInValueHelpDialog="false"></smartFilterBar:ControlConfiguration>
<smartFilterBar:ControlConfiguration key="ClassNum" visibleInAdvancedArea="true" preventInitialDataFetchInValueHelpDialog="false"></smartFilterBar:ControlConfiguration>
</smartFilterBar:controlConfiguration>
</smartFilterBar:SmartFilterBar>
<Tree id="ClassTree" items="{path: 'Tree>/'}" toggleOpenState="onOpenAnItemOnTree">
<CustomTreeItem>
<FlexBox width="100%" alignItems="Center" justifyContent="SpaceBetween">
<items>
<Label text="{Tree>text}" wrapping="true"/>
<Button icon="sap-icon://display" type="Transparent" press="onClassPressed"/>
</items>
</FlexBox>
</CustomTreeItem>
</Tree>
</mvc:View>
And the Search.Controller
sap.ui.define([
"ch/mindustrie/ZMM_CLASSIFICATION/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("ch.mindustrie.ZMM_CLASSIFICATION.controller.Search", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* #memberOf ch.mindustrie.ZMM_CLASSIFICATION.view.Search
*/
onInit: function () {
//Set model for smart filter bar
const oModel = this.getModel("Classification");
this.setModel(oModel);
//Model for classification tree
this.setModel(new sap.ui.model.json.JSONModel(), "Tree");
},
onSearchClass: function () {
const aFilter = this.byId("SelectionFilterBar").getFilters();
const self = this;
//Build the first node
this._readClassification(aFilter)
.then(aData => self.getModel("Tree").setProperty("/", aData));
},
/*
* Read classification from server.
*/
_readClassification: function (aFilter) {
const self = this;
//Build entry node
const oModel = this.getModel("Classification");
const oDateFrom = new sap.ui.model.Filter({
path: "ValidFrom",
operator: sap.ui.model.FilterOperator.LE,
value1: new Date()
});
const oDateUntil = new sap.ui.model.Filter({
path: "ValidFrom",
operator: sap.ui.model.FilterOperator.GE,
value1: new Date()
});
return new Promise((resolve, reject) => {
oModel
.read("/ZMM_C_CLASSIFICATION", {
filters: aFilter.concat([oDateFrom, oDateUntil]),
success: function (oData) {
let aTreeWithNodes = [];
const aTree = oData.results.map(self._buildEntryTree);
aTree.forEach((oNode, index) => {
self._readSubClasses(oNode.internalClass)
.then(aData => {
const oWithNodes = aTree[index];
if (aData.length > 0) {
oWithNodes.nodes = aData;
}
aTreeWithNodes.push(oWithNodes);
if (aTreeWithNodes.length === aTree.length) {
resolve(aTreeWithNodes);
}
});
});
},
error: function (oError) {
reject(oError);
}
});
});
},
_readSubClasses: function (sSubInternalClass) {
const oModel = this.getModel("Classification");
const self = this;
const oUpInteralClass = new sap.ui.model.Filter({
path: "UpInternalClass",
operator: sap.ui.model.FilterOperator.EQ,
value1: sSubInternalClass
});
return new Promise((resolve) => {
oModel
.read("/ZMM_C_CLASSSUB_REL", {
filters: [oUpInteralClass],
success: function (oData) {
const aNewNodes = (oData.results.length > 0 ? oData.results.map(self._prepareDescEntryNodes) : []);
resolve(aNewNodes);
},
error: function () {
resolve([]);
}
});
});
},
/*
* Build the entry node.
*/
_buildEntryTree: function (oData) {
return {
text: oData.ClassType + " " + oData.ClassNum + " " + oData.ClassNumDescr,
classType: oData.ClassType,
classNum: oData.ClassNum,
internalClass: oData.InternalClass,
nodes: []
};
},
onOpenAnItemOnTree: function (oEvent) {
const bExpanded = oEvent.getParameter("expanded");
if (!bExpanded) {
return;
}
const iItemIndex = oEvent.getParameter("itemIndex");
const oItemContext = oEvent.getParameter("itemContext");
const oTree = this.byId("ClassTree");
const oModel = this.getView().getModel("Tree");
const sPath = oItemContext.getPath();
const oCurrentNode = oModel.getProperty(sPath);
this._loadOnDemand(oModel, oCurrentNode, sPath, oTree.getItems()[iItemIndex].getLevel());
},
/*
* Load descendants asynchronously.
*/
_loadOnDemand: function (oModel, oCurrentNode, sPath) {
const aChildNodes = oCurrentNode.nodes.map(oClass => {
return new sap.ui.model.Filter({
path: "InternalClass",
operator: sap.ui.model.FilterOperator.EQ,
value1: oClass.internalClass
});
});
this._readClassification(aChildNodes)
.then(aNewNodes => oModel.setProperty(sPath + "/nodes", aNewNodes));
},
/*
* When the item in the tree is getting pressed.
*/
onClassPressed: function (oEvent) {
const oRow = oEvent.getSource().getBindingContext("Tree").getObject();
this.getRouter().navTo("characteristic", {
internalclassnum: oRow.internalClass
});
}
});
});
I believe the flexibility services only work in the Fiori launchpad, not in the webide sandbox launchpad. Do you get the same issue if you deploy?
I am working on UI5 application using Web IDE and I have created a view where I need to bind the data based on parameter received from last view. But the patternMatched event is not firing.
manifest.json
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "oomsdisplay.pso.com.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": ["notFound"]
},
"async": true
},
"routes": [{
"pattern": "",
"name": "worklist",
"target": ["worklist"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "object",
"target": ["object"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "payobject",
"target": ["payobject"]
}],
"targets": {
"worklist": {
"viewName": "Worklist",
"viewId": "worklist",
"viewLevel": 1
},
"object": {
"viewName": "Object",
"viewId": "object",
"viewLevel": 2
},
"objectNotFound": {
"viewName": "ObjectNotFound",
"viewId": "objectNotFound"
},
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
},
"payobject": {
"viewName": "PayObject",
"viewId": "payobject",
"viewLevel": 2
}
}
}
Component.js
init: function() {
UIComponent.prototype.init.apply(this, arguments);
// ...
this.getRouter().initialize(); // create the views based on the url/hash
},
Now, I have created a view. When I press the button on view, my second view i.e. PayObject will be called. Here is my code on button press of view one:
fViewPayment: function(oEvent) {
this.getRouter().getTargets().display("payobject", {
objectId: "MyParameterhere"
});
},
Now, here is my PayObejct view's init handler with object matched handler. But it is not working.
onInit: function() {
// ...
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("payobject").attachPatternMatched(this._onObjectMatched, this);
},
_onObjectMatched: function(oEvent) { // this event handler is not firing
var sObjectId = oEvent.getParameter("arguments").objectId;
sap.m.MessageBox.show(sObjectId);
// ...
},
If you have two routes with the same pattern, only the first one will be matched in the Router.
{
"pattern": "ZISOHSet/{objectId}",
"name": "object",
"target": ["object"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "payobject",
"target": ["payobject"]
}
So in this case "object" will me matched. Change the patter of one of your routes and try again.
Furthermore, use navTo() when navigating:
this.getRouter().navTo("payobject", {
objectId: "MyParameterhere"
});
Instead of using
getTargets().display
Use method navTo from your Router object
https://sapui5.hana.ondemand.com/#/api/sap.ui.core.routing.Router/overview
You have to routes with identical patterns: "object" and "payobject", I would try to remove one and check again.
Tring to add an object route to the main route(table page), but return this.getRouter is not a function error.
In main Controller:
onPress : function(oEvent) {
this._showObject(oEvent.getSource());
},
_showObject : function (oItem) {
this.getRouter().navTo("object", {
objectId: oItem.getBindingContext().getProperty("task_id")
});
},
In Component.js(I've checked , it's already loaded, no error produced)
sap.ui.define(["sap/ui/core/UIComponent"],
function (UIComponent) {
"use strict";
return UIComponent.extend("cts.mobile.Component", {
metadata : {
rootView : "cts.mobile.view.TaskTest",
routing : {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "cts.mobile.view",
"controlId": "taskapp", //in task.view.xml
"controlAggregation": "pages",
"async": true
},
"routes": [
{
"pattern": "",
"name": "task",
"target": "task"
},
{
"pattern": "ProductCollection/{objectId}",
"name": "object",
"target": "object"
}
],
"targets": {
"worklist": {
"viewName": "TaskTest",
"viewId": "TaskTest",
"viewLevel": 1
},
"object": {
"viewName": "Object",
"viewId": "object",
"viewLevel": 2
}
}
}
},
init : function () {
UIComponent.prototype.init.apply(this, arguments);
// Parse the current url and display the targets of the route that matches the hash
this.getRouter().initialize();
}
});
}
);
this value in _showObject:
f {mEventRegistry: Object, oView: f}
How to fix this error?
Try
return this.getOwnerComponent().getRouter();
Instead of what you now have in the getRouter function.
Tried
onPress : function(oEvent) {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("object", {
objectId:
oEvent.getSource().getBindingContext().getProperty("task_id")
});
And it's working.
ref: https://openui5.hana.ondemand.com/#docs/guide/e5200ee755f344c8aef8efcbab3308fb.html
Thanks to #hdereli
I forgot to include the helper : BaseController.js
getRouter : function () {
return sap.ui.core.UIComponent.getRouterFor(this)
},
Please help in accessing postgresql database view using strongloop.
im able to access table
{"name": "test",
"options": {
"idInjection": false,
"postgresql": {
"schema": "public",
"table": "test_data_v"
}
},
"properties": {
"assetid": {
"type": "String",
"required": false,
"length": 40,
"precision": null,
"scale": null,
"id": 1,
"postgresql": {
"columnName": "asset_id",
"dataType": "character varying",
"dataLength": 40,
"dataPrecision": null,
"dataScale": null,
"nullable": "YES"
}
}
}}
in same way please suggest me how to access view
Thanks
Divya
I am not installed postgresql but I tried in mysql, Its working fine.
IN your model you can do directly see this Example
In database I have created view that is
CREATE VIEW shareviews AS
SELECT id,name
FROM share where id = 1;
In model you can call viewname directly like this example
module.exports = function(Share) {
var server = require('../../server/server');
var ds = server.dataSources.MySQL; // use server.dataSources.postgres;
Share.list = function(optionalparam, cb) {
var sql = 'select * from shareviews';
ds.connector.execute(sql, function(err, data)
{
if(err) return err;
console.log(err);
console.log("data",data);
cb(null, data);
});
}
Share.remoteMethod(
'list',
{
accepts: {arg: 'param', type: 'string'},
returns: {arg: 'result', type: 'object'},
http: {path: '/list', verb: 'get'}
}
);
};
You need to set data source in datasource.json
{
"db": {
"name": "db",
"connector": "memory"
},
"postgres": {
"host": "localhost",
"port": 5432,
"database": "postgres",
"username": "postgres",
"password": "*******",
"name": "postgres",
"connector": "postgresql"
}
}
Then in model-config.json you need to assign data source name to each
model.
That is
{
"_meta": {
"sources": [
"loopback/common/models",
"loopback/server/models",
"../common/models",
"./models"
],
"mixins": [
"loopback/common/mixins",
"loopback/server/mixins",
"../common/mixins",
"./mixins"
]
},
"User": {
"dataSource": "db"
},
"AccessToken": {
"dataSource": "db",
"public": false
},
"ACL": {
"dataSource": "db",
"public": false
},
"RoleMapping": {
"dataSource": "db",
"public": false
},
"Role": {
"dataSource": "db",
"public": false
},
"yourmodelname": {
"dataSource": "postgres",
"public": true
},
"yourmodelname": {
"dataSource": "postgres",
"public": true
}
}
then you can access database in you model.js or Rest call(example localhost:3000/explorer) For Example my
model name Grocerylist
module.exports = function(Grocerylist) {
Grocerylist.beforeRemote('create', function(context, user, next) {
var req = context.req;
req.body.date = Date.now();
req.body.shopperId = req.accessToken.userId;
next();
});
Grocerylist.complete = function(shopperId, cb) {
Grocerylist.find({
where: {
purchased:false,
shopperId: shopperId,
}
}, function(err, list) {
var response;
if (typeof list === 'undefined' || list.length === 0) {
response = "All done shopping!"
}
else {
response = "Shopping is not done.";
}
cb(null, response);
});
};
Grocerylist.remoteMethod(
'complete',
{
accepts: {
arg: 'shopperId', type: 'string'
},
http: {
path: '/complete',
verb: 'get'
},
returns: {
arg: 'complete',
type: 'string'
}
}
);
};
How can I disable the "Copy" (but not cut / paste) functionality of the jsTree right click context menu?
This pretty much did the trick.
$("#housingTree").jstree({
"plugins": ["themes", "html_data", "ui", "crrm", "hotkeys", "contextmenu"],
"core": { "initially_open": ["phtml_1"] },
"contextmenu": {
"items": function ($node) {
return {
"Rename": {
"label": "Rename",
"action": function (obj) { this.rename(obj); }
},
"Create": {
"label": "Create",
"action": function (obj) { this.create(obj); }
},
"Delete": {
"label": "Delete",
"action": function (obj) { this.remove(obj); }
},
"Cut": {
"label": "Cut",
"action": function (obj) { this.cut(obj); }
},
"Paste": {
"label": "Paste",
"action": function (obj) { this.paste(obj); }
}
};
}
}
})
i dont know if the action functions are the default functions or custom functions, but that didnt work for me... anyway your post did set me in the right path! thanks!
this is how i did it, after finding another post:
"contextmenu": {
"items": function ($node) {
var tree = $("#html1Tree").jstree(true);
return {
"Rename": {
"label": "Rename",
"action": function (obj) {
tree.edit($node);
}
},
"Create": {
"label": "Create",
"action": function (obj) {
$node = tree.create_node($node);
tree.edit($node);
}
}
};
}
}
jsTree and Context Menu: modify items
The shorter approach could be
"contextmenu": {
"items": function(node) {
var defaultItems = $.jstree.defaults.contextmenu.items();
console.log("default items : "+JSON.stringify(defaultItems));
delete defaultItems.ccp.submenu.copy;
return defaultItems;
}
},
You can console.log(defaultItems). It wil print json representation of object. You can modify other properties also.
this is my easiest option.
All main code placed in "contextmenu.items" block.
$('#c-list').jstree({
"core": {
"themes": {"responsive": false},
"check_callback": true,
},
"types": {
"default": {
"icon": "fa fa-folder text-warning fa-lg"
},
"file": {
"icon": "fa fa-file text-warning fa-lg"
}
},
"contextmenu":{
'items' : function(node) {
var items = $.jstree.defaults.contextmenu.items();
items.ccp = false;
return items;
}
},
"plugins": ["contextmenu", "dnd", "types", "search", "wholerow","checkbox"]
});