I use 2 XML fragment, one for display data, the other for edit.
I switch the fragment using this method:
onAfterRendering : function () {
this._toggleForm("Display");
},
_toggleForm : function(sFragmentName) {
var oPage = this._detailPage;
//my detail page has an object header, a fragment form and a form in detail view.
if(oPage.getContent().length > 2) {
oPage.removeContent(1);
}
oPage.insertContent(this._getFormFragment(sFragmentName), 1);
},
_formFragments: {},
_getFormFragment: function (sFragmentName) {
var oFormFragment = this._formFragments[sFragmentName],
oView = this.getView();
if (oFormFragment) {
return oFormFragment;
}
oFormFragment = sap.ui.xmlfragment(oView.getId(), "namespace.fragment." + sFragmentName, this);
oView.addDependent(oFormFragment);
return this._formFragments[sFragmentName] = oFormFragment;
}
Everything works fine... BUT, if I call the app from the Fiori launchpad, the first call is ok, but the second time give me this error in insertContent :
The object with ID XXX-detail--general was destroyed and cannot be used anymore.
Display/Change fragment is destroyed after exit, but this._fromFragment still stored a reference, and returned this reference oFormFragment when _getFormFragment is called when I entered the second time, which caused this error.
Fixed by add:
onExit : function () {
for(var sPropertyName in this._formFragments) {
if(!this._formFragments.hasOwnProperty(sPropertyName)) {
return;
}
this._formFragments[sPropertyName].destroy();
this._formFragments[sPropertyName] = null;
}
}
Answer #AndriiNaumovych 's question:
It seems that only sap.ui.comp.smartform.SmartForm has a EditTogglable property, and it need a sap:updatable="true" in metadata.xml (I saw that in Explore, not specified in doc.)
I use sap.ui.layout.form.SimpleForm, editable seems not working in JSON model without metadata. So I use this example with fragment.
Related
Actaully i am using "before submit" listener to do some validation for my selection box
I have reffered the following link:
https://helpx.adobe.com/experience-manager/using/classic_dialog_validation.html.
But "before submit" method calling only when i place ,
dialog listener in the dialog root level only.
how to place dialog listener in dialog root level(I checked in my project there is no dialog.xml file ,they using only java code to construct component dialog).
Can anyone please help me in this ?enter image description here
Dialog property construction code :
#DialogField(name ="./validateProgram",
fieldLabel = "Validate Program",
fieldDescription = "(synchronized)",
additionalProperties = {
#Property(renderIn = Property.RenderValue.TOUCH,
name = "validation",
value = "validation-program")
},
listeners = {
#Listener(name ="beforesubmit",
value = "function(dialog){" +
"return programValidation.beforeSubmit(dialog);"+
"}")
})
#Selection(
type ="select",
optionsProvider = " ",
dataSource = "/resourcetype/data")
public final String validateProgram;
Java Script code:
window.onload = function() {
programValidation.init();
};
var programValidation= programValidation|| (function($) {
function initialize() {
};
function validate() {
alert("inside validate method");
var res = true;
return res;
};
return {
beforeSubmit: validate,
init: initialize
}
})(jQuery);
You are using the cq component maven plugin this a very vital piece of information to get your question answered.
I have not used this plugin before, but in your case, I assume you are looking for the Listener annotation where you can set the name as beforesubmit and the value as function(){alert(1)}
you'll probably have to set the annotation on a local variable similar to how you would annotate a dialog field '#DialogField', find more docs in the plugin's usage page here: http://code.digitalatolson.com/cq-component-maven-plugin/usage.html
Hope this helps.
Thanks for your support. Found the following way to solve the issue .
I added ValidateFields method from within the 2 listeners (FIELD_LISTENER_LOAD_CONTENT and FIELD_LISTENER_SELECTION_CHANGED)
function ValidateFields(dialog) {
dialog.on("beforesubmit", function(e) {
if(<condtion failed>)
CQ.Ext.Msg.alert(CQ.I18n.getMessage("Error"), CQ.I18n.getMessage("<error message>"));
return false;
} else {
return true;
}
}, this);
}
i need to build the page by binding aggregation as below
view
<NavContainer
id="navCon"
class="navContainerControl sapUiSmallMarginBottom" height="50%">
</NavContainer>
controller
onInit : function()
{
var navCon = this.getView().byId("navCon");
navCon.bindAggregation('pages',{
path:'/pages',
factory : jQuery.proxy(this.createPages,this)
});
}
createPages : function(sid,context)
{
var eachpageData = context.getObject();
var grid = new sap.ui.layout.Grid({
defaultSpan:"L4 M6 S6"
});
var page = new sap.m.Page({
id : eachpageData.name,
title : eachpageData.name,
content : grid
});
grid.bindAggregation('content',{path:'data',factory :this.createPageContent});
return page;
},
But when i see from the debugger it has only one page
But when i call navto
handleNav : function(evt)
{
var navCon = this.getView().byId("navCon");
var target = evt.getSource().getText();
if (target) {
//var animation = this.getView().byId("animationSelect").getSelectedKey();
navCon.to(this.getView().byId(target));
} else {
navCon.back();
}
}
and if i see the navCon.getPages() will give 2 pages.
What mistake i have done here?
You are trying to pass the DOM element to the NavContainers.to(DOM) method. This is where its gone wrong.
But NavContainers.to() method can accept id(String) as parameter.
Change your handleNav method as follows it will work.
handleNav : function(evt)
{
var navCon = this.getView().byId("navCon");
var target = evt.getSource().getText();
if (target) {
navCon.to(target);
} else {
navCon.back();
}
}
NavContainers can display only one page. You can add more pages to the pages aggregation, but they will be visible only if a navigation event is fired with the proper parameters. After that, the layout of the new page is loaded and added to the DOM.
In case of SplitApp, application can display two pages (master and detail) if you see it on tablet or desktop; however it's implemented by the use of two NavContainers.
That's why the control inspector returns with one page before the navigation, second page is not part of the DOM until you navigates to it.
If you place a breakpoint into your code instead of using the control inspector, you can call the navCon.getPages() which should return with the number of pages in the aggregation.
We want to update / edit the Data of a Customer. So we've tried out the original Code from the examples. The example works fine, but we usually have to check the Userinputs before we write that to the Database. Here's my Code:
/**
* Event handler (attached declaratively) for the view save button. Saves the changes added by the user.
* #function
* #public
*/
onSave: function() {
var that = this,
oModel = this.getModel();
// abort if the model has not been changed
if (!oModel.hasPendingChanges()) {
MessageBox.information(
this._oResourceBundle.getText("keine Änderungen"), {
id: "noChangesInfoMessageBox",
styleClass: that.getOwnerComponent().getContentDensityClass()
}
);
return;
}
this.getModel("appView").setProperty("/busy", true);
if (this._oViewModel.getProperty("/mode") === "edit") {
// attach to the request completed event of the batch
oModel.attachEventOnce("batchRequestCompleted", function(oEvent) {
var oParams = oEvent.getParameters();
if (oParams.success) {
that._fnUpdateSuccess();
} else {
that._fnEntityCreationFailed();
}
});
}
oModel.submitChanges();
},
How may I access to the REQUEST Data ? I've tried to look at the oModel DOM, but only found aBindings where a lot of unuseful Stuff is there. Even window.location.search wasn't the solution.
We've fixed it.
Just use this._getFormFields(this.byId("newEntitySimpleForm"));
I'm new to SAPUI5
I'm trying to show the master page when a Tile is clicked in a home page. Below is the code that I have used with in event handler.
var context = evt.getSource().getBindingContext();
this.nav.to("Master", context);
The problem here is I am getting following error TypeError: this.nav.to is not a function
Please assist
What is this in your context? That depends on where your tilePressed method is defined. If it's defined in a controller, this will refer to the controller.
If it is defined statically - you often find this for formatter functions - this will refer to the control that triggered the event.
Is the variable this.nav defined and appropriatly initialized? It needs to contain some kind of NavContainer e.g. the outermost sap.m.App resp. sap.m.SplitApp.
Also check out this article on the usage of this in JavaScript and this very handy jQuery function jQuery.proxy
The this.nav.to() and this.nav.back() functions are not
defined in the App.controller.js. You need to write the following code
in App.controller.js so that the compiler identifies the functions
being called.
to : function (pageId, context) {
var app = this.getView().app;
// load page on demand
var master = ("Master" === pageId);
if (app.getPage(pageId, master) === null) {
var page = sap.ui.view({
id : pageId,
viewName : "ProjectPath.view." + pageId,
type : "XML"
});
page.getController().nav = this;
app.addPage(page, master);
jQuery.sap.log.info("app controller > loaded page: " + pageId);
}
// show the page
app.to(pageId);
// set data context on the page
if (context) {
var page = app.getPage(pageId);
page.setBindingContext(context);
}
},
back : function (pageId) {
this.getView().app.backToPage(pageId);
}
I'm building a Metro app using the single-page navigation model. On one of my pages I start an async ajax request that fetches some information. When the request returns I want to insert the received information into the displayed page.
For example:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
WinJS.xhr(...).done(function (result) {
element.querySelector('#target').innerText = result.responseText;
});
}
};
But how do I know that the user hasn't navigated away from the page in the meantime? It doesn't make sense to try to insert the text on a different page, so how can I make sure that the page that was loading when the request started is still active?
You can compare the pages URI with the current WinJS.Navigation.location to check if you are still on the page. You can use Windows.Foundation.Uri to pull the path from the pages URI to do this.
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var page = this;
WinJS.xhr(...).done(function (result) {
if (new Windows.Foundation.Uri(page.uri).path !== WinJS.Navigation.location)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};
I couldn't find an official way to do this, so I implemented a workaround.
WinJS.Navigation provides events that are fired on navigation. I used the navigating event to build a simple class that keeps track of page views:
var PageViewManager = WinJS.Class.define(
function () {
this.current = 0;
WinJS.Navigation.addEventListener('navigating',
this._handleNavigating.bind(this));
}, {
_handleNavigating: function (eventInfo) {
this.current++;
}
});
Application.pageViews = new PageViewManager();
The class increments a counter each time the user starts a new navigation.
With that counter, the Ajax request can check if any navigation occurred and react accordingly:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var pageview = Application.pageViews.current;
WinJS.xhr(...).done(function (result) {
if (Application.pageViews.current != pageview)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};